Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
koh110 opened this issue Jul 18, 2023 · 27 comments · Fixed by #51047
Closed

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

koh110 opened this issue Jul 18, 2023 · 27 comments · Fixed by #51047
Labels
test_runner Issues and PRs related to the test runner subsystem.

Comments

@koh110
Copy link
Contributor

koh110 commented Jul 18, 2023

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
@MoLow MoLow added the test_runner Issues and PRs related to the test runner subsystem. label Jul 18, 2023
@MoLow
Copy link
Member

MoLow commented Jul 18, 2023

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

@koh110
Copy link
Contributor Author

koh110 commented Jul 18, 2023

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

@MoLow
Copy link
Member

MoLow commented Jul 18, 2023

the file calling run should not be excluded

@koh110
Copy link
Contributor Author

koh110 commented Jul 18, 2023

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

@MoLow
Copy link
Member

MoLow commented Jul 18, 2023

why? it is still correct

@koh110
Copy link
Contributor Author

koh110 commented Jul 18, 2023

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.

@koh110
Copy link
Contributor Author

koh110 commented Jul 22, 2023

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

@MoLow
Copy link
Member

MoLow commented Jul 22, 2023

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

@koh110
Copy link
Contributor Author

koh110 commented Jul 23, 2023

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.

@koshic
Copy link

koshic commented Jul 23, 2023

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.

@koh110
Copy link
Contributor Author

koh110 commented Jul 28, 2023

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

@koshic Thanks for the supplement!

@MoLow
Copy link
Member

MoLow commented Jul 28, 2023

@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

@koh110
Copy link
Contributor Author

koh110 commented Jul 28, 2023

@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.

@koh110
Copy link
Contributor Author

koh110 commented Jul 28, 2023

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...

@MoLow
Copy link
Member

MoLow commented Jul 28, 2023

you should not be running run.js with --test

@koh110
Copy link
Contributor Author

koh110 commented Jul 29, 2023

@MoLow It gives the same result without --test. node run.js occurs Infinite loop.
It seems difficult to tell. Can you give me a sample that can be run or Should I write a test and submit a PR for this pattern?

@cjihrig
Copy link
Contributor

cjihrig commented Jul 29, 2023

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.

@koh110
Copy link
Contributor Author

koh110 commented Jul 29, 2023

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

@cjihrig
Copy link
Contributor

cjihrig commented Jul 29, 2023

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

@koh110
Copy link
Contributor Author

koh110 commented Jul 29, 2023

@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?

@cjihrig
Copy link
Contributor

cjihrig commented Jul 29, 2023

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.

@koh110
Copy link
Contributor Author

koh110 commented Jul 31, 2023

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

@MoLow
Copy link
Member

MoLow commented Aug 2, 2023

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

@MoLow
Copy link
Member

MoLow commented Aug 2, 2023

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

@koh110
Copy link
Contributor Author

koh110 commented Aug 6, 2023

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

@pulkit-30
Copy link
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.

@MoLow
Copy link
Member

MoLow commented Nov 29, 2023

It should not be required - it has a default value

nodejs-github-bot pushed a commit that referenced this issue Dec 10, 2023
PR-URL: #51047
Fixes: #48823
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
Reviewed-By: James M Snell <jasnell@gmail.com>
RafaelGSS pushed a commit that referenced this issue Dec 15, 2023
PR-URL: #51047
Fixes: #48823
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
Reviewed-By: James M Snell <jasnell@gmail.com>
richardlau pushed a commit that referenced this issue Mar 25, 2024
PR-URL: #51047
Fixes: #48823
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
Reviewed-By: James M Snell <jasnell@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
test_runner Issues and PRs related to the test runner subsystem.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants