Sitelet https://github.com/nodejs/node/issues/48823
Skip to content

[node:test] Infinite loop occurs when files is empty #48823

Description

@koh110

Version

v20.4.0

Platform

Darwin MacBook-Pro.local 22.5.0 Darwin Kernel Version 22.5.0: Thu Jun 8 22:22:20 PDT 2023; root:xnu-8796.121.3~7/RELEASE_ARM64_T6000 arm64

Subsystem

No response

What steps will reproduce the bug?

This code occurs infinite loop.

import { run } from 'node:test' 
import { tap } from 'node:test/reporters';

const stream = run({
  // files: undefined
}).compose(tap);

stream.pipe(process.stdout);

How often does it reproduce? Is there a required condition?

everytime

What is the expected behavior? Why is that the expected behavior?

Default is written astest runner execution model. But it does not work.
https://nodejs.org/api/test.html#runoptions

files: An array containing the list of files to run. Default matching files from test runner execution model

It seems that tests that are run during node --test should be run when files is empty.

What do you see instead?

https://github.com/koh110/minimum-nodejs-test

$ node test-run-null-files.mjs
TAP version 13
# TAP version 13
# \# TAP version 13
# \# \\\# TAP version 13
# \# \\\# \\\\\\\# TAP version 13
# \# \\\# \\\\\\\# \\\\\\\\\\\\\\\# TAP version 13
# \# \\\# \\\\\\\# \\\\\\\\\\\\\\\# \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\# TAP version 13

Additional information

createTestFileList gets its own file path.
It seems that it have to exclude own file path when executing in run.

const hasUserSuppliedPattern = process.argv.length > 1;
const patterns = hasUserSuppliedPattern ? ArrayPrototypeSlice(process.argv, 1) : [kDefaultPattern];
console.log('createTestFileList:', hasUserSuppliedPattern, patterns);

const cwd = process.cwd();
const hasUserSuppliedPattern = process.argv.length > 1;
const patterns = hasUserSuppliedPattern ? ArrayPrototypeSlice(process.argv, 1) : [kDefaultPattern];

let testFiles = files ?? createTestFileList();

if (shard) {
  testFiles = ArrayPrototypeFilter(testFiles, (_, index) => index % shard.total === shard.index - 1);
}
console.log('testFiles: ', testFiles);

let testFiles = files ?? createTestFileList();
if (shard) {
testFiles = ArrayPrototypeFilter(testFiles, (_, index) => index % shard.total === shard.index - 1);
}

$ ~/dev/node/out/Release/node ./test-run-null-files.mjs
createTestFileList: true [ '/xxx/minimum-nodejs-test/test-run-null-files.mjs' ]
testFiles:  [ '/xxx/minimum-nodejs-test/test-run-null-files.mjs' ]
TAP version 13
# createTestFileList: true [ '/xxx/minimum-nodejs-test/test-run-null-files.mjs' ]
# testFiles:  [ '/xxx/minimum-nodejs-test/test-run-null-files.mjs' ]
# TAP version 13

Activity

  1. added
    test_runnerIssues and PRs related to the test runner subsystem.
    on Jul 18, 2023
  2. MoLow commented on Jul 18, 2023

    @MoLow
    Member

    I am not sure I would consider this a bug, you should either specify files or name the root file in some way that the default execution model won't detect it as a test file.
    and, due to the fact the the default will change to be a glob pattern starting node 21 - I don't think it should be excluded in any way

  3. koh110 commented on Jul 18, 2023

    @koh110
    ContributorAuthor

    Does it mean that the files should be specified? Or does it mean that it should not be excluded own file path?

    I don't think it should be excluded in any way

    Would you prefer to modify the document in that case?

    Default is written astest runner execution model

  4. MoLow commented on Jul 18, 2023

    @MoLow
    Member

    the file calling run should not be excluded

  5. koh110 commented on Jul 18, 2023

    @koh110
    ContributorAuthor

    So, I think Default matching in the document should be removed. What do you think about it?

  6. MoLow commented on Jul 18, 2023

    @MoLow
    Member

    why? it is still correct

  7. koh110 commented on Jul 18, 2023

    @koh110
    ContributorAuthor

    I think Default is the initial value that works that way if not specified.
    For example, the initial values for concurrency and inspectPort, timeout are described in the document.
    However, files will not work if it is excluded.
    I think this is different compared to other Default.

    So I think it should state that it cannot be omitted instead of Default.

  8. koh110 commented on Jul 22, 2023

    @koh110
    ContributorAuthor

    How do I call the default file pattern like node --test for run?

  9. MoLow commented on Jul 22, 2023

    @MoLow
    Member

    run({file: undefined}) or just run({}) will use the default behavior

  10. koh110 commented on Jul 23, 2023

    @koh110
    ContributorAuthor

    When I run run({file: undefined}) or run({}), it's occurs Infinite loop. I want to solve it.

    So, I think options.files has bug or Default in doc is not correct, when i create this issue.

    Could you please exec this code?

    $ node -v
    v20.4.0
    
    $ tree
    .
    └── run.js
    
    $ cat run.js
    require('node:test').run({ files: undefined }).compose(require('node:test/reporters').tap).pipe(process.stdout)
    
    # this code occurs infinite loop
    $ node run.js

    run.js is included in process.argv in createFiles if i set files: undefined. It seems to refer to itself.
    https://github.com/nodejs/node/blob/99881304c47138e09a06e6b2bd876cfdf840047e/lib/internal/test_runner/runner.js#L89C1-L93

    This happens with any file name.
    My first sample code with a file name starting with test- was bad. sorry.

  11. koshic commented on Jul 23, 2023

    @koshic

    run({file: undefined}) or just run({}) will use the default behavior

    Is that mean that 'node run.js' (which files: undefined) is equal to 'node --test run.js', as @koh110 explained? I don't think that such 'expected' behaviour is really expected. We should have note in docs, or some asserts in test-runner code to brake the loop.

  12. koh110 commented on Jul 28, 2023

    @koh110
    ContributorAuthor

    @MoLow Hi! Could you please help me with what is wrong with this sample code?

    @koshic Thanks for the supplement!

  13. MoLow commented on Jul 28, 2023

    @MoLow
    Member

    @koh110 if you experience an infinate loop - that means the file called by run has a name that is detected as a test file (as described here - https://nodejs.org/api/test.html#test-runner-execution-model it probably has the word test in its name.
    you can avoid that by changing the file name or not using the default files argument

  14. koh110 commented on Jul 28, 2023

    @koh110
    ContributorAuthor

    @MoLow It occurs with any file name. Could you please run this sample?
    #48823 (comment)
    This sample file is named run.js and it is located in the root directory.
    I think this is not part of the pattern.

  15. koh110 commented on Jul 28, 2023

    @koh110
    ContributorAuthor

    run call createTestFileList when options.files is empty.

    let testFiles = files ?? createTestFileList();

    But hasUserSuppliedPattern in createTestFileList is always true when node --test run.js.

    function createTestFileList() {
      const cwd = process.cwd();
      const hasUserSuppliedPattern = process.argv.length > 1;
      const patterns = hasUserSuppliedPattern ? ArrayPrototypeSlice(process.argv, 1) : [kDefaultPattern];

    process.argv cannot be empty when trying to call a file containing run.

    So, I think createTestFileList always returns path of run that named like root/a.js, root/b.js...

  16. 2 remaining items

  17. cjihrig commented on Jul 29, 2023

    @cjihrig
    Contributor

    One way we could address this with a semver major change is to make options.files a required option. That would eliminate any surprise behavior.

  18. koh110 commented on Jul 29, 2023

    @koh110
    ContributorAuthor

    @cjihrig Do you mean that the default file pattern like node --test cannot be called from run?
    #48823 (comment)

  19. cjihrig commented on Jul 29, 2023

    @cjihrig
    Contributor

    Correct. Although we could expose an API to get that list.

  20. koh110 commented on Jul 29, 2023

    @koh110
    ContributorAuthor

    @cjihrig Thanks. I understand thanks to your answer.
    I look forward to seeing this issue resolved.

    Should I send a PR to require options.files in the docs?

  21. cjihrig commented on Jul 29, 2023

    @cjihrig
    Contributor

    Should I send a PR to require options.files in the docs?

    Making it a required argument would also require a code change, but first let's see how other collaborators feel. There isn't really a rush because it's a breaking change so it wouldn't be released until October anyway.

  22. koh110 commented on Jul 31, 2023

    @koh110
    ContributorAuthor

    OK, thanks.
    I would like to create a draft PR how other collaborators feel. Is it more appropriate to create new issue?

  23. MoLow commented on Aug 2, 2023

    @MoLow
    Member

    Should I send a PR to require options.files in the docs?

    Making it a required argument would also require a code change, but first let's see how other collaborators feel. There isn't really a rush because it's a breaking change so it wouldn't be released until October anyway.

    the next semver release will include glob support, and until we expose fs.glob (wich I am working on doing) - I dont think we should make this required

  24. MoLow commented on Aug 2, 2023

    @MoLow
    Member

    hoever we can easily detect if run is being called when process.env.NODE_TEST_CONTEXT is set and warn/stop the execution

  25. koh110 commented on Aug 6, 2023

    @koh110
    ContributorAuthor

    It's sounds good for me. If you give me the sample, I will make a PR.

    hoever we can easily detect if run is being called when process.env.NODE_TEST_CONTEXT is set and warn/stop the execution

  26. pulkit-30 commented on Nov 28, 2023

    @pulkit-30
    Contributor

    I would like to work on this.
    making options.files a required option in run() seems a good solution for this (ref comment).
    WDYT @MoLow.

  27. MoLow commented on Nov 29, 2023

    @MoLow
    Member

    It should not be required - it has a default value

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    test_runnerIssues and PRs related to the test runner subsystem.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions