node/test/sea/test-single-executable-application-inspect.js
Antoine du Hamel 53e325ffd0
test: ensure assertions are reachable in more folders
PR-URL: https://github.com/nodejs/node/pull/60411
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
2025-10-29 15:16:59 +00:00

123 lines
3.5 KiB
JavaScript

'use strict';
// This tests the creation of a single executable application that can be
// debugged using the inspector protocol with NODE_OPTIONS=--inspect-brk=0
const common = require('../common');
const assert = require('assert');
const { writeFileSync, existsSync } = require('fs');
const { spawn } = require('child_process');
const tmpdir = require('../common/tmpdir');
const { spawnSyncAndExitWithoutError } = require('../common/child_process');
const {
generateSEA,
skipIfSingleExecutableIsNotSupported,
} = require('../common/sea');
skipIfSingleExecutableIsNotSupported();
const configFile = tmpdir.resolve('sea-config.json');
const seaPrepBlob = tmpdir.resolve('sea-prep.blob');
const outputFile = tmpdir.resolve(process.platform === 'win32' ? 'sea.exe' : 'sea');
tmpdir.refresh();
// Create a simple hello world script
writeFileSync(tmpdir.resolve('hello.js'), `console.log('Hello, world!');`, 'utf-8');
// Create SEA configuration
writeFileSync(configFile, `
{
"main": "hello.js",
"output": "sea-prep.blob"
}
`);
// Generate the SEA prep blob
spawnSyncAndExitWithoutError(
process.execPath,
['--experimental-sea-config', 'sea-config.json'],
{ cwd: tmpdir.path },
);
assert(existsSync(seaPrepBlob));
// Generate the SEA executable
generateSEA(outputFile, process.execPath, seaPrepBlob);
// Spawn the SEA with inspect option
const seaProcess = spawn(outputFile, [], {
env: {
...process.env,
NODE_OPTIONS: '--inspect-brk=0',
},
});
let debuggerUrl = null;
let seaStderr = '';
seaProcess.stderr.setEncoding('utf8');
seaProcess.stdout.setEncoding('utf8');
seaProcess.stdout.on('data', (data) => {
console.log(`[SEA][STDOUT] ${data}`);
});
seaProcess.stderr.on('data', common.mustCallAtLeast((data) => {
console.log(`[SEA][STDERR] ${data}`);
seaStderr += data;
// Parse the debugger listening message
const match = seaStderr.match(/Debugger listening on ws:\/\/([\d.]+):(\d+)\//);
if (match && !debuggerUrl) {
const host = match[1];
const port = match[2];
debuggerUrl = `${host}:${port}`;
console.log(`Running ${process.execPath} inspect ${debuggerUrl}`);
// Once we have the debugger URL, spawn the inspector CLI
const inspectorProcess = spawn(process.execPath, ['inspect', debuggerUrl], {
stdio: ['pipe', 'pipe', 'pipe'],
});
let inspectorStdout = '';
inspectorProcess.stdout.setEncoding('utf8');
inspectorProcess.stderr.setEncoding('utf8');
inspectorProcess.stdout.on('data', (data) => {
console.log(`[INSPECT][STDOUT] ${data}`);
inspectorStdout += data;
// Check if we successfully connected
const matches = [...inspectorStdout.matchAll(/debug> /g)];
if (inspectorStdout.includes(`connecting to ${host}:${port} ... ok`) &&
matches.length >= 2) {
// We are at the second prompt, which means we can send commands to terminate both now.
console.log('Sending .exit command to inspector...');
inspectorProcess.stdin.write('.exit\n');
}
});
inspectorProcess.stderr.on('data', (data) => {
console.log(`[INSPECT][STDERR] ${data}`);
});
inspectorProcess.on('close', common.mustCall((code) => {
assert.strictEqual(code, 0, `Inspector process exited with code ${code}.`);
}));
inspectorProcess.on('error', (err) => {
throw err;
});
}
}));
seaProcess.on('close', common.mustCall((code) => {
assert.strictEqual(code, 0, `SEA process exited with code ${code}.`);
}));
seaProcess.on('error', (err) => {
throw err;
});