Skip to content
Merged
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
4 changes: 0 additions & 4 deletions src/node_options.cc
Original file line number Diff line number Diff line change
Expand Up @@ -422,10 +422,6 @@ void Parse(
// TODO(addaleax): Make that unnecessary.

DebugOptionsParser::DebugOptionsParser() {
#ifndef DISABLE_SINGLE_EXECUTABLE_APPLICATION
if (sea::IsSingleExecutable()) return;
#endif

AddOption("--inspect-port",
"set host:port for inspector",
&DebugOptions::host_port,
Expand Down
2 changes: 2 additions & 0 deletions test/sequential/sequential.status
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ test-single-executable-application-disable-experimental-sea-warning: SKIP
test-single-executable-application-empty: SKIP
test-single-executable-application-exec-argv: SKIP
test-single-executable-application-exec-argv-empty: SKIP
test-single-executable-application-inspect-in-sea-flags: SKIP
test-single-executable-application-inspect: SKIP
test-single-executable-application-snapshot: SKIP
test-single-executable-application-snapshot-and-code-cache: SKIP
test-single-executable-application-snapshot-worker: SKIP
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
'use strict';

// This tests that the debugger flag --inspect passed directly to a single executable
// application would not be consumed by Node.js but passed to the application
// instead.

require('../common');
const assert = require('assert');
const { writeFileSync, existsSync } = require('fs');
const { spawnSyncAndAssert } = require('../common/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();

writeFileSync(tmpdir.resolve('sea.js'), `console.log(process.argv);`, 'utf-8');

// Create SEA configuration
writeFileSync(configFile, `
{
"main": "sea.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
spawnSyncAndAssert(
outputFile,
['--inspect=0'],
{
env: {
...process.env,
},
},
{
stdout(data) {
assert.match(data, /--inspect=0/);
return true;
},
stderr(data) {
assert.doesNotMatch(data, /Debugger listening/);
return true;
},
trim: true,
}
);
122 changes: 122 additions & 0 deletions test/sequential/test-single-executable-application-inspect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
'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

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', (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', (code) => {
assert.strictEqual(code, 0, `Inspector process exited with code ${code}.`);
});

inspectorProcess.on('error', (err) => {
throw err;
});
}
});

seaProcess.on('close', (code) => {
assert.strictEqual(code, 0, `SEA process exited with code ${code}.`);
});

seaProcess.on('error', (err) => {
throw err;
});
Loading