diff --git a/test/common/debugger.js b/test/common/debugger.js index dbaa62e71d3f..73a34a767763 100644 --- a/test/common/debugger.js +++ b/test/common/debugger.js @@ -27,6 +27,8 @@ function startCLI(args, flags = [], spawnOpts = {}, opts = { randomPort: true }) ...args, ], spawnOpts); + const closed = new Promise((resolve) => child.once('close', resolve)); + const outputBuffer = []; function bufferOutput(chunk) { if (this === child.stderr) { @@ -180,10 +182,8 @@ function startCLI(args, flags = [], spawnOpts = {}, opts = { randomPort: true }) }, quit() { - return new Promise((resolve) => { - child.stdin.end(); - child.on('close', resolve); - }); + child.stdin.end(); + return closed; }, }; } diff --git a/test/es-module/es-module.status b/test/es-module/es-module.status index 376b9cdeb07b..2e18fb7c96a1 100644 --- a/test/es-module/es-module.status +++ b/test/es-module/es-module.status @@ -6,10 +6,6 @@ prefix es-module [true] # This section applies to all platforms -[$system==linux || $system==freebsd] -# https://github.com/nodejs/node/issues/47836 -test-esm-loader-http-imports: PASS,FLAKY - [$arch==arm || $arch==arm64] # https://github.com/nodejs/node/issues/47297 test-wasm-web-api: SKIP diff --git a/test/es-module/test-esm-loader-http-imports.mjs b/test/es-module/test-esm-loader-http-imports.mjs index 07e84eddd861..96bfffe5b13f 100644 --- a/test/es-module/test-esm-loader-http-imports.mjs +++ b/test/es-module/test-esm-loader-http-imports.mjs @@ -34,7 +34,9 @@ const requestListener = ({ url }, rsp) => { .end(); }; -const server = http.createServer(requestListener); +// Leave closing idle connections to the client, so that the loader never +// reuses a keep-alive socket the server has just closed. +const server = http.createServer({ keepAliveTimeout: 0 }, requestListener); await promisify(server.listen.bind(server))({ host: '127.0.0.1', diff --git a/test/fixtures/debugger/alive.js b/test/fixtures/debugger/alive.js index c8ad157b452d..0b06798508a7 100644 --- a/test/fixtures/debugger/alive.js +++ b/test/fixtures/debugger/alive.js @@ -3,3 +3,5 @@ function heartbeat() { ++x; } setInterval(heartbeat, 50); + +if (process.send) process.send('ready'); diff --git a/test/parallel/parallel.status b/test/parallel/parallel.status index b260a86594c1..be53eda583b8 100644 --- a/test/parallel/parallel.status +++ b/test/parallel/parallel.status @@ -20,8 +20,6 @@ test-fs-read-stream-concurrent-reads: PASS, FLAKY test-snapshot-incompatible: SKIP [$system==win32] -# https://github.com/nodejs/node/issues/59090 -test-inspector-network-fetch: PASS, FLAKY # https://github.com/nodejs/node/issues/59636 test-fs-cp-sync-symlink-points-to-dest-error: SKIP test-fs-cp-async-symlink-points-to-dest: SKIP @@ -36,9 +34,6 @@ test-performance-function: PASS, FLAKY test-esm-loader-hooks-inspect-wait: PASS, FLAKY [$system==macos] -# https://github.com/nodejs/node/issues/42741 -test-http-server-headers-timeout-keepalive: PASS,FLAKY -test-http-server-request-timeout-keepalive: PASS,FLAKY # https://github.com/nodejs/node/issues/60050 test-cluster-dgram-1: SKIP @@ -141,10 +136,6 @@ test-tls-set-default-ca-certificates-append-fetch: SKIP test-tls-set-default-ca-certificates-reset-fetch: SKIP test-inspector-invalid-protocol: SKIP -[$asan==on] -# https://github.com/nodejs/node/issues/39655 -test-cluster-primary-error: PASS, FLAKY - [$arch==loong64] # https://github.com/nodejs/node/issues/51662 test-http-correct-hostname: SKIP @@ -152,8 +143,3 @@ test-http-correct-hostname: SKIP [$arch==riscv64] # Snapshot test works in some environments but not others for now on RISC-V test-snapshot-reproducible: PASS, FLAKY -# styletext ones are failing in jenkins but pass standalone so something -# odd is happening to the ttys when run via java. tty issue -# https://github.com/nodejs/build/issues/4099#issuecomment-5070947806 -test-util-styletext: PASS, FLAKY -test-util-styletext-hex: PASS, FLAKY diff --git a/test/parallel/test-cluster-primary-error.js b/test/parallel/test-cluster-primary-error.js index 232de51f29fb..f9ebdc4c85d1 100644 --- a/test/parallel/test-cluster-primary-error.js +++ b/test/parallel/test-cluster-primary-error.js @@ -88,12 +88,24 @@ if (cluster.isWorker) { // Check that the cluster died accidentally (non-zero exit code) assert.strictEqual(code, 1); + // Probe with signal 0. common.isAlive() sends SIGCONT, which discards the + // pending SIGSTOP that LeakSanitizer's exit-time stop-the-world waits for + // under ASan on Linux, leaving the exiting worker hung forever. + const isAlive = (pid) => { + try { + return process.kill(pid, 0); + } catch (err) { + if (err.code !== 'ESRCH') throw err; + return false; + } + }; + // XXX(addaleax): The fact that this uses raw PIDs makes the test inherently // flaky – another process might end up being started right after the // workers finished and receive the same PID. const pollWorkers = () => { // When primary is dead all workers should be dead too - if (workers.some((pid) => common.isAlive(pid))) { + if (workers.some(isAlive)) { setTimeout(pollWorkers, 50); } }; diff --git a/test/parallel/test-http-server-headers-timeout-keepalive.js b/test/parallel/test-http-server-headers-timeout-keepalive.js index 493c730cb7a9..1a9d060c9ff3 100644 --- a/test/parallel/test-http-server-headers-timeout-keepalive.js +++ b/test/parallel/test-http-server-headers-timeout-keepalive.js @@ -70,7 +70,7 @@ server.listen(0, common.mustCall(() => { performRequestWithDelay( client, headersTimeout / 5, - headersTimeout, + headersTimeout * 2, true ); }, defer).unref(); diff --git a/test/parallel/test-inspector-close-terminate-connections.js b/test/parallel/test-inspector-close-terminate-connections.js index ab18ad277dbb..e055044506b6 100644 --- a/test/parallel/test-inspector-close-terminate-connections.js +++ b/test/parallel/test-inspector-close-terminate-connections.js @@ -18,9 +18,9 @@ async function test() { const instance = new NodeInstance(['--inspect-brk=0'], script); const session = await instance.connectInspectorSession(); - // Enable Runtime domain and wait for an event to confirm the session is live. - await session.send({ method: 'Runtime.enable' }); - await session.waitForNotification('Runtime.executionContextCreated'); + // Wait until the child is ready to receive the resume command. + await session.send({ method: 'NodeRuntime.enable' }); + await session.waitForNotification('NodeRuntime.waitingForDebugger'); // Resume execution so the script calls inspector.close(). await session.send({ method: 'Runtime.runIfWaitingForDebugger' }); diff --git a/test/parallel/test-inspector-network-fetch.js b/test/parallel/test-inspector-network-fetch.js index 790446c84bfb..a637d3495466 100644 --- a/test/parallel/test-inspector-network-fetch.js +++ b/test/parallel/test-inspector-network-fetch.js @@ -12,9 +12,10 @@ const http = require('node:http'); const https = require('node:https'); const inspector = require('node:inspector/promises'); -// Disable certificate validation for the global fetch. +// Keep local requests independent of proxy settings and allow the test certificate. const undici = require('internal/deps/undici/undici'); undici.setGlobalDispatcher(new undici.EnvHttpProxyAgent({ + noProxy: '*', connect: { rejectUnauthorized: false, }, @@ -205,8 +206,10 @@ const testNetworkInspection = async () => { session.removeAllListeners(); }; -httpServer.listen(0, () => { - httpsServer.listen(0, async () => { +// Listen on the address the requests go to, so that a socket another process +// binds to 127.0.0.1 on the same port cannot take the connections over. +httpServer.listen(0, '127.0.0.1', () => { + httpsServer.listen(0, '127.0.0.1', async () => { try { await session.post('Network.enable'); await testNetworkInspection(); diff --git a/test/parallel/test-util-styletext-hex.js b/test/parallel/test-util-styletext-hex.js index f12c35a780d6..9677217bd331 100644 --- a/test/parallel/test-util-styletext-hex.js +++ b/test/parallel/test-util-styletext-hex.js @@ -213,8 +213,10 @@ describe('util.styleText hex color support', () => { for (const testCase of testCases) { it(`should respect ${testCase.description}`, () => { writeStream.isTTY = testCase.isTTY; + // Do not inherit color-related variables (TERM, CI, NO_COLOR, ...) + // from the environment the test happens to run in. process.env = { - ...originalEnv, + TERM: 'xterm-256color', ...testCase.env, }; const output = util.styleText('#ffcc00', 'test', { stream: writeStream }); diff --git a/test/parallel/test-util-styletext.js b/test/parallel/test-util-styletext.js index 3db01bec1c3a..ba81aae06d83 100644 --- a/test/parallel/test-util-styletext.js +++ b/test/parallel/test-util-styletext.js @@ -203,9 +203,11 @@ if (fd !== -1) { { isTTY: true, env: { FORCE_COLOR: '1', NO_COLOR: '1', NODE_DISABLE_COLORS: '1' }, expected: styled }, ].forEach((testCase) => { writeStream.isTTY = testCase.isTTY; + // Do not inherit color-related variables (TERM, CI, NO_COLOR, ...) from + // the environment the test happens to run in. process.env = { - ...process.env, - ...testCase.env + TERM: 'xterm-256color', + ...testCase.env, }; { const output = util.styleText('red', 'test', { stream: writeStream }); diff --git a/test/sequential/sequential.status b/test/sequential/sequential.status index 4111eb2b8ecf..f155b6747333 100644 --- a/test/sequential/sequential.status +++ b/test/sequential/sequential.status @@ -11,18 +11,11 @@ test-cpu-prof-dir-worker: PASS, FLAKY test-http2-large-file: PASS, FLAKY [$system==win32] -# https://github.com/nodejs/node/issues/63212#issuecomment-5423558796 -test-debugger-pid: PASS, FLAKY [$system==linux] -# https://github.com/nodejs/node/issues/54817 -test-http-server-request-timeouts-mixed: PASS, FLAKY [$system==macos] -# https://github.com/nodejs/node/issues/43465 -test-http-server-request-timeouts-mixed: PASS, FLAKY - [$system==solaris] # Also applies to SmartOS test-worker-prof: PASS, FLAKY diff --git a/test/sequential/test-debugger-pid.js b/test/sequential/test-debugger-pid.js index 97218b796cae..f05f968e4601 100644 --- a/test/sequential/test-debugger-pid.js +++ b/test/sequential/test-debugger-pid.js @@ -8,11 +8,15 @@ const startCLI = require('../common/debugger'); const assert = require('assert'); const { spawn } = require('child_process'); +const { once } = require('events'); const script = fixtures.path('debugger', 'alive.js'); (async () => { - const target = spawn(process.execPath, [script]); + const target = spawn(process.execPath, [script], { + stdio: ['ignore', 'pipe', 'pipe', 'ipc'], + }); + await once(target, 'message'); const cli = startCLI(['-p', `${target.pid}`], [], {}, { randomPort: false }); try { @@ -25,7 +29,8 @@ const script = fixtures.path('debugger', 'alive.js'); /> 3 {3}\+\+x;/, 'marks the 3rd line'); } finally { - await cli.quit(); + const targetClosed = once(target, 'close'); target.kill(); + await Promise.all([cli.quit(), targetClosed]); } })().then(common.mustCall()); diff --git a/test/sequential/test-debugger-quit-after-exit.js b/test/sequential/test-debugger-quit-after-exit.js new file mode 100644 index 000000000000..7e02175435bd --- /dev/null +++ b/test/sequential/test-debugger-quit-after-exit.js @@ -0,0 +1,12 @@ +'use strict'; +const common = require('../common'); +common.skipIfInspectorDisabled(); + +const assert = require('assert'); +const startCLI = require('../common/debugger'); + +(async () => { + const cli = startCLI(['--help'], [], {}, { randomPort: false }); + await assert.rejects(cli.waitForPrompt(), /Child exited while waiting/); + await cli.quit(); +})().then(common.mustCall()); diff --git a/test/sequential/test-http-server-request-timeouts-mixed.js b/test/sequential/test-http-server-request-timeouts-mixed.js index 034aa3630bbf..8e79cf6c9316 100644 --- a/test/sequential/test-http-server-request-timeouts-mixed.js +++ b/test/sequential/test-http-server-request-timeouts-mixed.js @@ -2,6 +2,7 @@ const common = require('../common'); const assert = require('assert'); +const { once } = require('events'); const { createServer } = require('http'); const { connect } = require('net'); @@ -70,7 +71,7 @@ server.listen(0, common.mustCall(() => { request1.client.write(requestBodyPart1); // After a little while send two new requests - setTimeout(() => { + setTimeout(common.mustCall(() => { request2 = createClient(server); request3 = createClient(server); @@ -79,7 +80,17 @@ server.listen(0, common.mustCall(() => { // Send the third request and stop in the middle of the headers request3.client.write(requestBodyPart1); - }, headersTimeout * 0.2); + + request2.client.on('end', common.mustCall(() => { + // The second request times out due to headersTimeout, so after the first + // request has been completed and before the fourth request's body is sent + assert(request1.completed); + assert(!request4.completed); + + assert(request1.response.startsWith(responseOk)); + assert(request2.response.startsWith(responseTimeout)); // It is expired due to headersTimeout + })); + }), headersTimeout * 0.2); // After another little while send the last two new requests setTimeout(() => { @@ -103,31 +114,23 @@ server.listen(0, common.mustCall(() => { }, headersTimeout * 0.8); setTimeout(common.mustCall(() => { - // After the first timeout, the first request should have been completed and second timedout - assert(request1.completed); - assert(request2.completed); + // After the first timeout, the requests with completed headers should still be pending assert(!request3.completed); assert(!request4.completed); assert(!request5.completed); - assert(request1.response.startsWith(responseOk)); - assert(request2.response.startsWith(responseTimeout)); // It is expired due to headersTimeout + const pending = [request3, request4, request5]; + Promise.all(pending.map(({ client }) => once(client, 'end'))).then(common.mustCall(() => { + // All request should be completed now, either with 200 or 408 + assert(request3.response.startsWith(responseTimeout)); // It is expired due to requestTimeout + assert(request4.response.startsWith(responseOk)); + assert(request5.response.startsWith(responseTimeout)); // It is expired due to requestTimeout + server.close(); + })); }), headersTimeout * 1.4); setTimeout(() => { // Complete the body for the fourth request request4.client.write(requestBodyPart3); }, headersTimeout * 1.5); - - setTimeout(common.mustCall(() => { - // All request should be completed now, either with 200 or 408 - assert(request3.completed); - assert(request4.completed); - assert(request5.completed); - - assert(request3.response.startsWith(responseTimeout)); // It is expired due to requestTimeout - assert(request4.response.startsWith(responseOk)); - assert(request5.response.startsWith(responseTimeout)); // It is expired due to requestTimeout - server.close(); - }), headersTimeout * 3 + connectionsCheckingInterval); })); diff --git a/test/test-runner/test-run-watch-cwd-isolation-none.mjs b/test/test-runner/test-run-watch-cwd-isolation-none.mjs index bbb1a141a4b4..c3d32883781a 100644 --- a/test/test-runner/test-run-watch-cwd-isolation-none.mjs +++ b/test/test-runner/test-run-watch-cwd-isolation-none.mjs @@ -1,14 +1,20 @@ // Test run({ watch: true, cwd, isolation: 'none' }) runs with different cwd while in watch mode and isolation none import * as common from '../common/index.mjs'; import * as fixtures from '../common/fixtures.mjs'; +import { readdir, readFile } from 'node:fs/promises'; import { run } from 'node:test'; import { skipIfNoWatch } from '../common/watch.js'; skipIfNoWatch(); +// Read the fixtures before watching them. On Windows, their first read can +// update access times and trigger a restart without changing their contents. +const cwd = fixtures.path('test-runner-watch'); +await Promise.all((await readdir(cwd)).map((file) => readFile(fixtures.path('test-runner-watch', file)))); + const controller = new AbortController(); const stream = run({ - cwd: fixtures.path('test-runner-watch'), + cwd, watch: true, signal: controller.signal, isolation: 'none', diff --git a/test/test-runner/test-runner.status b/test/test-runner/test-runner.status index 7ad99e20a87e..65ae96eb9e37 100644 --- a/test/test-runner/test-runner.status +++ b/test/test-runner/test-runner.status @@ -5,8 +5,3 @@ prefix test-runner # sample-test : PASS,FLAKY [true] # This section applies to all platforms - -[$system==win32] -# https://github.com/nodejs/node/issues/66056 -test-run-watch-cwd-isolation-none: PASS, FLAKY -test-run-watch-cwd-isolation-none-argv: PASS, FLAKY