From 678ee5b795c3ca7778790781aa710b4c079f51da Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Mon, 20 Apr 2026 12:26:08 +0200 Subject: [PATCH] test: normalize known inspector crash as completion This works around a pre-existing inspector issue: if the debuggee exits too quickly the inspector can segfault while tearing down. For now normalize the trailing segfault as completion to keep the CI green until the upstream bug is fixed, since it only reproduces on some slow CI machines and is not what the probe tests care about. --- test/common/debugger-probe.js | 42 +++++++++++++++++-- ...-debugger-probe-child-inspect-port-zero.js | 5 +-- ...test-debugger-probe-global-option-order.js | 5 +-- .../test-debugger-probe-json-preview.js | 8 ++-- ...test-debugger-probe-json-special-values.js | 8 ++-- test/parallel/test-debugger-probe-json.js | 5 +-- test/parallel/test-debugger-probe-miss.js | 5 +-- ...test-debugger-probe-text-special-values.js | 8 ++-- test/parallel/test-debugger-probe-text.js | 11 +++-- test/parallel/test-debugger-probe-timeout.js | 5 +-- 10 files changed, 69 insertions(+), 33 deletions(-) diff --git a/test/common/debugger-probe.js b/test/common/debugger-probe.js index 4ad693e0363c26..2e992b4bb47ad9 100644 --- a/test/common/debugger-probe.js +++ b/test/common/debugger-probe.js @@ -1,18 +1,54 @@ 'use strict'; +const assert = require('assert'); const fixtures = require('./fixtures'); const path = require('path'); +const probeTargetExitSignal = 'SIGSEGV'; +const probeTargetExitMessage = + `Target exited with signal ${probeTargetExitSignal} before target completion`; + function debuggerFixturePath(name) { return path.relative(process.cwd(), fixtures.path('debugger', name)); } -function escapeRegex(string) { - return string.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&'); +// Work around a pre-existing inspector issue: if the debuggee exits too quickly +// the inspector can segfault while tearing down. For now normalize the +// trailing segfault as completion until the upstream bug is fixed. +// See https://github.com/nodejs/node/issues/62765 +// https://github.com/nodejs/node/issues/58245 +function assertProbeJson(output, expected) { + const normalized = JSON.parse(output); + const lastResult = normalized.results?.[normalized.results.length - 1]; + + if (lastResult?.event === 'error' && + lastResult.error?.code === 'probe_target_exit' && + lastResult.error?.signal === probeTargetExitSignal && + lastResult.error?.message === probeTargetExitMessage) { + // Log to facilitate debugging if this normalization is occurring. + console.log('Normalizing trailing SIGSEGV in JSON probe output'); + normalized.results[normalized.results.length - 1] = { event: 'completed' }; + } + + assert.deepStrictEqual(normalized, expected); +} + +function assertProbeText(output, expected) { + const idx = output.indexOf(probeTargetExitMessage); + let normalized; + if (idx !== -1) { + // Log to facilitate debugging if this normalization is occurring. + console.log('Normalizing trailing SIGSEGV in text probe output'); + normalized = output.slice(0, output.lastIndexOf('\n', idx)) + '\nCompleted'; + } else { + normalized = output; + } + assert.strictEqual(normalized, expected); } module.exports = { - escapeRegex, + assertProbeJson, + assertProbeText, missScript: debuggerFixturePath('probe-miss.js'), probeScript: debuggerFixturePath('probe.js'), throwScript: debuggerFixturePath('probe-throw.js'), diff --git a/test/parallel/test-debugger-probe-child-inspect-port-zero.js b/test/parallel/test-debugger-probe-child-inspect-port-zero.js index a6f03ad9f41cbc..2abc81441edeb1 100644 --- a/test/parallel/test-debugger-probe-child-inspect-port-zero.js +++ b/test/parallel/test-debugger-probe-child-inspect-port-zero.js @@ -4,9 +4,8 @@ const common = require('../common'); common.skipIfInspectorDisabled(); -const assert = require('assert'); const { spawnSyncAndAssert } = require('../common/child_process'); -const { probeScript } = require('../common/debugger-probe'); +const { assertProbeJson, probeScript } = require('../common/debugger-probe'); spawnSyncAndAssert(process.execPath, [ 'inspect', @@ -18,7 +17,7 @@ spawnSyncAndAssert(process.execPath, [ probeScript, ], { stdout(output) { - assert.deepStrictEqual(JSON.parse(output), { + assertProbeJson(output, { v: 1, probes: [{ expr: 'finalValue', diff --git a/test/parallel/test-debugger-probe-global-option-order.js b/test/parallel/test-debugger-probe-global-option-order.js index 9e247c3213178a..19487c8f623795 100644 --- a/test/parallel/test-debugger-probe-global-option-order.js +++ b/test/parallel/test-debugger-probe-global-option-order.js @@ -4,9 +4,8 @@ const common = require('../common'); common.skipIfInspectorDisabled(); -const assert = require('assert'); const { spawnSyncAndAssert } = require('../common/child_process'); -const { probeScript } = require('../common/debugger-probe'); +const { assertProbeJson, probeScript } = require('../common/debugger-probe'); spawnSyncAndAssert(process.execPath, [ 'inspect', @@ -16,7 +15,7 @@ spawnSyncAndAssert(process.execPath, [ probeScript, ], { stdout(output) { - assert.deepStrictEqual(JSON.parse(output), { + assertProbeJson(output, { v: 1, probes: [{ expr: 'finalValue', diff --git a/test/parallel/test-debugger-probe-json-preview.js b/test/parallel/test-debugger-probe-json-preview.js index 62b9edfe489c4a..853939075aa326 100644 --- a/test/parallel/test-debugger-probe-json-preview.js +++ b/test/parallel/test-debugger-probe-json-preview.js @@ -4,9 +4,11 @@ const common = require('../common'); common.skipIfInspectorDisabled(); -const assert = require('assert'); const { spawnSyncAndAssert } = require('../common/child_process'); -const { probeTypesScript } = require('../common/debugger-probe'); +const { + assertProbeJson, + probeTypesScript, +} = require('../common/debugger-probe'); const location = `${probeTypesScript}:17`; @@ -23,7 +25,7 @@ spawnSyncAndAssert(process.execPath, [ probeTypesScript, ], { stdout(output) { - assert.deepStrictEqual(JSON.parse(output), { + assertProbeJson(output, { v: 1, probes: [ { expr: 'objectValue', target: [probeTypesScript, 17] }, diff --git a/test/parallel/test-debugger-probe-json-special-values.js b/test/parallel/test-debugger-probe-json-special-values.js index ea18a33f1e9ac7..97782c9e314e3d 100644 --- a/test/parallel/test-debugger-probe-json-special-values.js +++ b/test/parallel/test-debugger-probe-json-special-values.js @@ -4,9 +4,11 @@ const common = require('../common'); common.skipIfInspectorDisabled(); -const assert = require('assert'); const { spawnSyncAndAssert } = require('../common/child_process'); -const { probeTypesScript } = require('../common/debugger-probe'); +const { + assertProbeJson, + probeTypesScript, +} = require('../common/debugger-probe'); const location = `${probeTypesScript}:17`; @@ -38,7 +40,7 @@ spawnSyncAndAssert(process.execPath, [ probeTypesScript, ], { stdout(output) { - assert.deepStrictEqual(JSON.parse(output), { + assertProbeJson(output, { v: 1, probes: [ { expr: 'stringValue', target: [probeTypesScript, 17] }, diff --git a/test/parallel/test-debugger-probe-json.js b/test/parallel/test-debugger-probe-json.js index e95b7ffbd72587..be2288ee78ddac 100644 --- a/test/parallel/test-debugger-probe-json.js +++ b/test/parallel/test-debugger-probe-json.js @@ -4,9 +4,8 @@ const common = require('../common'); common.skipIfInspectorDisabled(); -const assert = require('assert'); const { spawnSyncAndAssert } = require('../common/child_process'); -const { probeScript } = require('../common/debugger-probe'); +const { assertProbeJson, probeScript } = require('../common/debugger-probe'); spawnSyncAndAssert(process.execPath, [ 'inspect', @@ -20,7 +19,7 @@ spawnSyncAndAssert(process.execPath, [ probeScript, ], { stdout(output) { - assert.deepStrictEqual(JSON.parse(output), { + assertProbeJson(output, { v: 1, probes: [ { expr: 'index', target: [probeScript, 8] }, diff --git a/test/parallel/test-debugger-probe-miss.js b/test/parallel/test-debugger-probe-miss.js index 7dc52e9a07b0c0..2908b8092aeb7d 100644 --- a/test/parallel/test-debugger-probe-miss.js +++ b/test/parallel/test-debugger-probe-miss.js @@ -4,9 +4,8 @@ const common = require('../common'); common.skipIfInspectorDisabled(); -const assert = require('assert'); const { spawnSyncAndAssert } = require('../common/child_process'); -const { missScript } = require('../common/debugger-probe'); +const { assertProbeJson, missScript } = require('../common/debugger-probe'); spawnSyncAndAssert(process.execPath, [ 'inspect', @@ -16,7 +15,7 @@ spawnSyncAndAssert(process.execPath, [ missScript, ], { stdout(output) { - assert.deepStrictEqual(JSON.parse(output), { + assertProbeJson(output, { v: 1, probes: [{ expr: '42', target: [missScript, 99] }], results: [{ diff --git a/test/parallel/test-debugger-probe-text-special-values.js b/test/parallel/test-debugger-probe-text-special-values.js index 17ff62ef4a086d..3886eb66daed8b 100644 --- a/test/parallel/test-debugger-probe-text-special-values.js +++ b/test/parallel/test-debugger-probe-text-special-values.js @@ -4,9 +4,11 @@ const common = require('../common'); common.skipIfInspectorDisabled(); -const assert = require('assert'); const { spawnSyncAndAssert } = require('../common/child_process'); -const { probeTypesScript } = require('../common/debugger-probe'); +const { + assertProbeText, + probeTypesScript, +} = require('../common/debugger-probe'); const location = `${probeTypesScript}:17`; @@ -37,7 +39,7 @@ spawnSyncAndAssert(process.execPath, [ probeTypesScript, ], { stdout(output) { - assert.strictEqual(output, [ + assertProbeText(output, [ `Hit 1 at ${location}`, ' stringValue = "hello"', `Hit 1 at ${location}`, diff --git a/test/parallel/test-debugger-probe-text.js b/test/parallel/test-debugger-probe-text.js index 75be98611d378b..30e77b25985d16 100644 --- a/test/parallel/test-debugger-probe-text.js +++ b/test/parallel/test-debugger-probe-text.js @@ -4,9 +4,8 @@ const common = require('../common'); common.skipIfInspectorDisabled(); -const assert = require('assert'); const { spawnSyncAndAssert } = require('../common/child_process'); -const { probeScript } = require('../common/debugger-probe'); +const { assertProbeText, probeScript } = require('../common/debugger-probe'); spawnSyncAndAssert(process.execPath, [ 'inspect', @@ -15,10 +14,10 @@ spawnSyncAndAssert(process.execPath, [ probeScript, ], { stdout(output) { - assert.strictEqual(output, - `Hit 1 at ${probeScript}:12\n` + - ' finalValue = 81\n' + - 'Completed'); + assertProbeText(output, + `Hit 1 at ${probeScript}:12\n` + + ' finalValue = 81\n' + + 'Completed'); }, trim: true, }); diff --git a/test/parallel/test-debugger-probe-timeout.js b/test/parallel/test-debugger-probe-timeout.js index d4728407bc5924..fe641f31943af0 100644 --- a/test/parallel/test-debugger-probe-timeout.js +++ b/test/parallel/test-debugger-probe-timeout.js @@ -4,9 +4,8 @@ const common = require('../common'); common.skipIfInspectorDisabled(); -const assert = require('assert'); const { spawnSyncAndExit } = require('../common/child_process'); -const { timeoutScript } = require('../common/debugger-probe'); +const { assertProbeJson, timeoutScript } = require('../common/debugger-probe'); spawnSyncAndExit(process.execPath, [ 'inspect', @@ -19,7 +18,7 @@ spawnSyncAndExit(process.execPath, [ signal: null, status: 1, stdout(output) { - assert.deepStrictEqual(JSON.parse(output), { + assertProbeJson(output, { v: 1, probes: [{ expr: '1', target: [timeoutScript, 99] }], results: [{