Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions test/fixtures/process-timeout/blocked-worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ const script = path.join(__dirname, 'wait-for-parent.js');
const args = [script, String(process.pid), process.argv[2]];
new Worker(`
require('child_process').execFileSync(process.execPath, ${JSON.stringify(args)}, {
// The child can briefly outlive the parent. Do not keep the test's
// temporary directory open, which prevents cleanup on Windows.
cwd: ${JSON.stringify(__dirname)},
stdio: 'ignore',
});
`, { eval: true, name: 'blocked' });
2 changes: 2 additions & 0 deletions test/parallel/parallel.status
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ test-crypto-keygen: SKIP
test-debugger-heap-profiler: PASS, FLAKY

[$system==solaris] # Also applies to SmartOS
# https://github.com/nodejs/node/pull/66282#issuecomment-5833089308
test-worker-init-failure: PASS, FLAKY
# https://github.com/nodejs/node/issues/43457
test-domain-no-error-handler-abort-on-uncaught-0: PASS, FLAKY
test-domain-no-error-handler-abort-on-uncaught-1: PASS,FLAKY
Expand Down
57 changes: 57 additions & 0 deletions test/report/test-report-process-timeout-worker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
'use strict';

// Tests --report-on-process-timeout with a blocked Worker.

const common = require('../common');
const assert = require('assert');
const fs = require('fs');
const { spawnSync } = require('child_process');
const fixtures = require('../common/fixtures');
const helper = require('../common/report');
const tmpdir = require('../common/tmpdir');

tmpdir.refresh();

// A Worker thread that is blocked in a synchronous native call cannot
// provide its part of the report. It is left out, so that the report is
// completed before the process is forced to exit.
// If the Worker thread was not blocked yet when the deadline expired, which
// the fixture signals by creating a file, it is included in the report. Run
// the fixture again with a longer timeout in that case.
let child;
let report;
for (let timeout = common.platformTimeout(1000); ; timeout *= 2) {
// Child processes of a previous attempt may still be running, so use a
// different file for each attempt.
const marker = tmpdir.resolve(`blocked-worker.${timeout}.ready`);
child = spawnSync(process.execPath, [
`--process-timeout=${timeout}ms`,
'--report-on-process-timeout',
fixtures.path('process-timeout', 'blocked-worker.js'),
marker,
], { cwd: tmpdir.path, encoding: 'utf8' });

const reports = helper.findReports(child.pid, tmpdir.path);
assert.strictEqual(reports.length, 1, child.stderr);
helper.validate(reports[0], [
['header.event', 'Process timed out (--process-timeout)'],
['header.trigger', 'ProcessTimeout'],
]);
report = JSON.parse(fs.readFileSync(reports[0], 'utf8'));
if ((fs.existsSync(marker) && report.workers.length === 0) ||
timeout >= common.platformTimeout(16000)) {
break;
}
}

assert.strictEqual(child.signal, null);
assert.strictEqual(child.status, 124, child.stderr);
assert.match(child.stderr, /^ {4}Worker \(thread 1, name 'blocked'\)$/m);
// The report is completed before the process is forced to exit, so the
// message about that is printed on its own line.
assert.match(child.stderr, new RegExp(
'^Writing Node\\.js report to file: report\\.\\S+\\.json\\r?\\n' +
'Node\\.js report completed\\r?\\n' +
'\\(node:\\d+\\) The process did not finish exiting within 5000ms after ' +
'--process-timeout expired\\. Forcing exit\\.$', 'm'));
assert.deepStrictEqual(report.workers, []);
47 changes: 0 additions & 47 deletions test/report/test-report-process-timeout.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ const common = require('../common');
const assert = require('assert');
const fs = require('fs');
const { spawnSync } = require('child_process');
const fixtures = require('../common/fixtures');
const helper = require('../common/report');
const tmpdir = require('../common/tmpdir');

Expand Down Expand Up @@ -46,49 +45,3 @@ helper.validate(reports[0], [

const report = JSON.parse(fs.readFileSync(reports[0], 'utf8'));
assert.match(report.javascriptStack.stack[0], /^at spin \(\[eval\]:1:\d+\)$/);

{
// A Worker thread that is blocked in a synchronous native call cannot
// provide its part of the report. It is left out, so that the report is
// completed before the process is forced to exit.
// If the Worker thread was not blocked yet when the deadline expired, which
// the fixture signals by creating a file, it is included in the report. Run
// the fixture again with a longer timeout in that case.
let child;
let report;
for (let timeout = common.platformTimeout(1000); ; timeout *= 2) {
// Child processes of a previous attempt may still be running, so use a
// different file for each attempt.
const marker = tmpdir.resolve(`blocked-worker.${timeout}.ready`);
child = spawnSync(process.execPath, [
`--process-timeout=${timeout}ms`,
'--report-on-process-timeout',
fixtures.path('process-timeout', 'blocked-worker.js'),
marker,
], { cwd: tmpdir.path, encoding: 'utf8' });

const reports = helper.findReports(child.pid, tmpdir.path);
assert.strictEqual(reports.length, 1, child.stderr);
helper.validate(reports[0], [
['header.event', 'Process timed out (--process-timeout)'],
['header.trigger', 'ProcessTimeout'],
]);
report = JSON.parse(fs.readFileSync(reports[0], 'utf8'));
if ((fs.existsSync(marker) && report.workers.length === 0) ||
timeout >= common.platformTimeout(16000)) {
break;
}
}

assert.strictEqual(child.signal, null);
assert.strictEqual(child.status, 124, child.stderr);
assert.match(child.stderr, /^ {4}Worker \(thread 1, name 'blocked'\)$/m);
// The report is completed before the process is forced to exit, so the
// message about that is printed on its own line.
assert.match(child.stderr, new RegExp(
'^Writing Node\\.js report to file: report\\.\\S+\\.json\\r?\\n' +
'Node\\.js report completed\\r?\\n' +
'\\(node:\\d+\\) The process did not finish exiting within 5000ms after ' +
'--process-timeout expired\\. Forcing exit\\.$', 'm'));
assert.deepStrictEqual(report.workers, []);
}
Loading