From 90730961b464d3970bc106a600712f8917bbb12a Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Tue, 27 Jan 2026 02:08:09 +0100 Subject: [PATCH] test: split test-embedding.js and run tests in parallel Split the tests so that it's easier to isolate and debug issues, and we can run the test cases in parallel to speed up. Also add more comments about what they are testing. --- .../test-embedding-create-require-fs.js | 17 ++ .../test-embedding-create-require-internal.js | 15 ++ .../test-embedding-disable-node-env-vars.js | 27 +++ test/embedding/test-embedding-exit-code.js | 14 ++ .../test-embedding-load-environment-basic.js | 16 ++ .../test-embedding-load-environment-utf8.js | 17 ++ .../test-embedding-snapshot-as-file.js | 50 ++++++ .../test-embedding-snapshot-basic.js | 50 ++++++ test/embedding/test-embedding-snapshot-vm.js | 43 +++++ ...t-embedding-snapshot-without-code-cache.js | 50 ++++++ .../test-embedding-snapshot-worker.js | 43 +++++ test/embedding/test-embedding-throw.js | 14 ++ test/embedding/test-embedding.js | 164 ------------------ test/embedding/testcfg.py | 2 +- test/fixtures/snapshot/create-vm.js | 11 ++ ...eate-worker-and-vm.js => create-worker.js} | 10 +- 16 files changed, 374 insertions(+), 169 deletions(-) create mode 100644 test/embedding/test-embedding-create-require-fs.js create mode 100644 test/embedding/test-embedding-create-require-internal.js create mode 100644 test/embedding/test-embedding-disable-node-env-vars.js create mode 100644 test/embedding/test-embedding-exit-code.js create mode 100644 test/embedding/test-embedding-load-environment-basic.js create mode 100644 test/embedding/test-embedding-load-environment-utf8.js create mode 100644 test/embedding/test-embedding-snapshot-as-file.js create mode 100644 test/embedding/test-embedding-snapshot-basic.js create mode 100644 test/embedding/test-embedding-snapshot-vm.js create mode 100644 test/embedding/test-embedding-snapshot-without-code-cache.js create mode 100644 test/embedding/test-embedding-snapshot-worker.js create mode 100644 test/embedding/test-embedding-throw.js delete mode 100644 test/embedding/test-embedding.js create mode 100644 test/fixtures/snapshot/create-vm.js rename test/fixtures/snapshot/{create-worker-and-vm.js => create-worker.js} (70%) diff --git a/test/embedding/test-embedding-create-require-fs.js b/test/embedding/test-embedding-create-require-fs.js new file mode 100644 index 00000000000000..28a09f60d99eb8 --- /dev/null +++ b/test/embedding/test-embedding-create-require-fs.js @@ -0,0 +1,17 @@ +'use strict'; + +// Tests that createRequire() works correctly with local fs in embedded environments. +// The createRequire() call is in embedtest.cc. + +const common = require('../common'); +const fixtures = require('../common/fixtures'); +const { spawnSyncAndExit } = require('../common/child_process'); + +const fixturePath = JSON.stringify(fixtures.path('exit.js')); +spawnSyncAndExit( + common.resolveBuiltBinary('embedtest'), + [`require(${fixturePath})`, 92], + { + status: 92, + signal: null, + }); diff --git a/test/embedding/test-embedding-create-require-internal.js b/test/embedding/test-embedding-create-require-internal.js new file mode 100644 index 00000000000000..d88ae4e39a178c --- /dev/null +++ b/test/embedding/test-embedding-create-require-internal.js @@ -0,0 +1,15 @@ +'use strict'; + +// Tests that createRequire() from embedded environments still cannot access internals. +// The createRequire() call is in embedtest.cc. + +const common = require('../common'); +const { spawnSyncAndExit } = require('../common/child_process'); + +spawnSyncAndExit( + common.resolveBuiltBinary('embedtest'), + ['require("lib/internal/test/binding")'], + { + status: 1, + signal: null, + }); diff --git a/test/embedding/test-embedding-disable-node-env-vars.js b/test/embedding/test-embedding-disable-node-env-vars.js new file mode 100644 index 00000000000000..13492e916947a2 --- /dev/null +++ b/test/embedding/test-embedding-disable-node-env-vars.js @@ -0,0 +1,27 @@ +'use strict'; + +// Tests node::ProcessInitializationFlags::kDisableNodeOptionsEnv works correctly. + +const common = require('../common'); +const { spawnSyncAndExit } = require('../common/child_process'); +const os = require('os'); + +if (process.config.variables.node_without_node_options) { + common.skip('NODE_REPL_EXTERNAL_MODULE cannot be tested with --without-node-options'); +} + +const embedtest = common.resolveBuiltBinary('embedtest'); +spawnSyncAndExit( + embedtest, + ['require("os")'], + { + env: { + ...process.env, + 'NODE_REPL_EXTERNAL_MODULE': 'fs', + }, + }, + { + status: 9, + signal: null, + stderr: `${embedtest}: NODE_REPL_EXTERNAL_MODULE can't be used with kDisableNodeOptionsEnv${os.EOL}`, + }); diff --git a/test/embedding/test-embedding-exit-code.js b/test/embedding/test-embedding-exit-code.js new file mode 100644 index 00000000000000..35cd7ffc125397 --- /dev/null +++ b/test/embedding/test-embedding-exit-code.js @@ -0,0 +1,14 @@ +'use strict'; + +// Tests that process.exitCode works correctly in embedded environments. + +const common = require('../common'); +const { spawnSyncAndExit } = require('../common/child_process'); + +spawnSyncAndExit( + common.resolveBuiltBinary('embedtest'), + ['process.exitCode = 8'], + { + status: 8, + signal: null, + }); diff --git a/test/embedding/test-embedding-load-environment-basic.js b/test/embedding/test-embedding-load-environment-basic.js new file mode 100644 index 00000000000000..2627dd34fc1f50 --- /dev/null +++ b/test/embedding/test-embedding-load-environment-basic.js @@ -0,0 +1,16 @@ +'use strict'; + +// Tests node::LoadEnvironment() with main_script_source_utf8 works. + +const common = require('../common'); +const { spawnSyncAndAssert } = require('../common/child_process'); + +const embedtest = common.resolveBuiltBinary('embedtest'); + +spawnSyncAndAssert( + embedtest, + ['console.log(42)'], + { + trim: true, + stdout: '42', + }); diff --git a/test/embedding/test-embedding-load-environment-utf8.js b/test/embedding/test-embedding-load-environment-utf8.js new file mode 100644 index 00000000000000..dfc5d52a86f65e --- /dev/null +++ b/test/embedding/test-embedding-load-environment-utf8.js @@ -0,0 +1,17 @@ +'use strict'; + +// Test node::LoadEnvironment() works with non-ASCII source code. The variable +// comes from embedtest.cc. + +const common = require('../common'); +const { spawnSyncAndAssert } = require('../common/child_process'); + +const embedtest = common.resolveBuiltBinary('embedtest'); + +spawnSyncAndAssert( + embedtest, + ['console.log(embedVars.nön_ascıı)'], + { + trim: true, + stdout: '🏳️‍🌈', + }); diff --git a/test/embedding/test-embedding-snapshot-as-file.js b/test/embedding/test-embedding-snapshot-as-file.js new file mode 100644 index 00000000000000..5a9b4b1d928350 --- /dev/null +++ b/test/embedding/test-embedding-snapshot-as-file.js @@ -0,0 +1,50 @@ +'use strict'; + +// Tests node::EmbedderSnapshotData::FromFile() works correctly. +// The snapshot is created in embedtest.cc. + +const common = require('../common'); +const tmpdir = require('../common/tmpdir'); +const assert = require('assert'); +const fixtures = require('../common/fixtures'); + +const { + spawnSyncAndAssert, + spawnSyncAndExitWithoutError, +} = require('../common/child_process'); + +const snapshotFixture = fixtures.path('snapshot', 'echo-args.js'); +const embedtest = common.resolveBuiltBinary('embedtest'); + +const buildSnapshotExecArgs = [ + `eval(require("fs").readFileSync(${JSON.stringify(snapshotFixture)}, "utf8"))`, + 'arg1', 'arg2', +]; +const snapshotBlobArgs = [ + '--embedder-snapshot-blob', tmpdir.resolve('embedder-snapshot.blob'), +]; + +const runSnapshotExecArgs = ['arg3', 'arg4']; + +tmpdir.refresh(); + +// Build the snapshot with the --embedder-snapshot-as-file flag. +spawnSyncAndExitWithoutError( + embedtest, + ['--', ...buildSnapshotExecArgs, ...snapshotBlobArgs, '--embedder-snapshot-as-file', '--embedder-snapshot-create'], + { cwd: tmpdir.path }); + +// Run the snapshot and check the serialized and refreshed argv values. +spawnSyncAndAssert( + embedtest, + ['--', ...runSnapshotExecArgs, ...snapshotBlobArgs ], + { cwd: tmpdir.path }, + { + stdout(output) { + assert.deepStrictEqual(JSON.parse(output), { + originalArgv: [embedtest, '__node_anonymous_main', ...buildSnapshotExecArgs], + currentArgv: [embedtest, ...runSnapshotExecArgs], + }); + return true; + }, + }); diff --git a/test/embedding/test-embedding-snapshot-basic.js b/test/embedding/test-embedding-snapshot-basic.js new file mode 100644 index 00000000000000..8ace784116df92 --- /dev/null +++ b/test/embedding/test-embedding-snapshot-basic.js @@ -0,0 +1,50 @@ +'use strict'; + +// Tests snapshot support in embedded environments. +// See embedtest.cc for the API usage. + +const common = require('../common'); +const tmpdir = require('../common/tmpdir'); +const assert = require('assert'); +const fixtures = require('../common/fixtures'); + +const { + spawnSyncAndAssert, + spawnSyncAndExitWithoutError, +} = require('../common/child_process'); + +const snapshotFixture = fixtures.path('snapshot', 'echo-args.js'); +const embedtest = common.resolveBuiltBinary('embedtest'); + +const buildSnapshotExecArgs = [ + `eval(require("fs").readFileSync(${JSON.stringify(snapshotFixture)}, "utf8"))`, + 'arg1', 'arg2', +]; +const snapshotBlobArgs = [ + '--embedder-snapshot-blob', tmpdir.resolve('embedder-snapshot.blob'), +]; + +const runSnapshotExecArgs = ['arg3', 'arg4']; + +tmpdir.refresh(); + +// Build the snapshot with the default flags. +spawnSyncAndExitWithoutError( + embedtest, + ['--', ...buildSnapshotExecArgs, ...snapshotBlobArgs, '--embedder-snapshot-create'], + { cwd: tmpdir.path }); + +// Run the snapshot and check the serialized and refreshed argv values. +spawnSyncAndAssert( + embedtest, + ['--', ...runSnapshotExecArgs, ...snapshotBlobArgs ], + { cwd: tmpdir.path }, + { + stdout(output) { + assert.deepStrictEqual(JSON.parse(output), { + originalArgv: [embedtest, '__node_anonymous_main', ...buildSnapshotExecArgs], + currentArgv: [embedtest, ...runSnapshotExecArgs], + }); + return true; + }, + }); diff --git a/test/embedding/test-embedding-snapshot-vm.js b/test/embedding/test-embedding-snapshot-vm.js new file mode 100644 index 00000000000000..0d60059056ad2f --- /dev/null +++ b/test/embedding/test-embedding-snapshot-vm.js @@ -0,0 +1,43 @@ +'use strict'; + +// Tests creating vm contexts after snapshot deserialization works +// in embedded environments. + +const common = require('../common'); +const tmpdir = require('../common/tmpdir'); +const fixtures = require('../common/fixtures'); + +const { + spawnSyncAndAssert, + spawnSyncAndExitWithoutError, +} = require('../common/child_process'); + +const snapshotFixture = fixtures.path('snapshot', 'create-vm.js'); +const embedtest = common.resolveBuiltBinary('embedtest'); + +const buildSnapshotExecArgs = [ + `eval(require("fs").readFileSync(${JSON.stringify(snapshotFixture)}, "utf8"))`, + 'arg1', 'arg2', +]; +const snapshotBlobArgs = [ + '--embedder-snapshot-blob', tmpdir.resolve('embedder-snapshot.blob'), +]; + +const runSnapshotExecArgs = ['arg3', 'arg4']; + +tmpdir.refresh(); + +// Build the snapshot with the vm-creating code in serialized main funciton. +spawnSyncAndExitWithoutError( + embedtest, + ['--', ...buildSnapshotExecArgs, ...snapshotBlobArgs, '--embedder-snapshot-create'], + { cwd: tmpdir.path }); + +// Run the snapshot that creates a vm context from the snapshot. +spawnSyncAndAssert( + embedtest, + ['--', ...runSnapshotExecArgs, ...snapshotBlobArgs ], + { cwd: tmpdir.path }, + { + stdout: /value: 42/, + }); diff --git a/test/embedding/test-embedding-snapshot-without-code-cache.js b/test/embedding/test-embedding-snapshot-without-code-cache.js new file mode 100644 index 00000000000000..577ace1188ff40 --- /dev/null +++ b/test/embedding/test-embedding-snapshot-without-code-cache.js @@ -0,0 +1,50 @@ +'use strict'; + +// Tests node::SnapshotFlags::kWithoutCodeCache. See +// embedtest.cc for more details. + +const common = require('../common'); +const tmpdir = require('../common/tmpdir'); +const assert = require('assert'); +const fixtures = require('../common/fixtures'); + +const { + spawnSyncAndAssert, + spawnSyncAndExitWithoutError, +} = require('../common/child_process'); + +const snapshotFixture = fixtures.path('snapshot', 'echo-args.js'); +const embedtest = common.resolveBuiltBinary('embedtest'); + +const buildSnapshotExecArgs = [ + `eval(require("fs").readFileSync(${JSON.stringify(snapshotFixture)}, "utf8"))`, + 'arg1', 'arg2', +]; +const snapshotBlobArgs = [ + '--embedder-snapshot-blob', tmpdir.resolve('embedder-snapshot.blob'), +]; + +const runSnapshotExecArgs = ['arg3', 'arg4']; + +tmpdir.refresh(); + +// Build the snapshot with the --without-code-cache flag. +spawnSyncAndExitWithoutError( + embedtest, + ['--', ...buildSnapshotExecArgs, ...snapshotBlobArgs, '--without-code-cache', '--embedder-snapshot-create'], + { cwd: tmpdir.path }); + +// Run the snapshot and check the serialized and refreshed argv values. +spawnSyncAndAssert( + embedtest, + ['--', ...runSnapshotExecArgs, ...snapshotBlobArgs ], + { cwd: tmpdir.path }, + { + stdout(output) { + assert.deepStrictEqual(JSON.parse(output), { + originalArgv: [embedtest, '__node_anonymous_main', ...buildSnapshotExecArgs], + currentArgv: [embedtest, ...runSnapshotExecArgs], + }); + return true; + }, + }); diff --git a/test/embedding/test-embedding-snapshot-worker.js b/test/embedding/test-embedding-snapshot-worker.js new file mode 100644 index 00000000000000..c6f665eed4d116 --- /dev/null +++ b/test/embedding/test-embedding-snapshot-worker.js @@ -0,0 +1,43 @@ +'use strict'; + +// Tests creating workers after snapshot deserialization works +// in embedded environments. + +const common = require('../common'); +const tmpdir = require('../common/tmpdir'); +const fixtures = require('../common/fixtures'); + +const { + spawnSyncAndAssert, + spawnSyncAndExitWithoutError, +} = require('../common/child_process'); + +const snapshotFixture = fixtures.path('snapshot', 'create-worker.js'); +const embedtest = common.resolveBuiltBinary('embedtest'); + +const buildSnapshotExecArgs = [ + `eval(require("fs").readFileSync(${JSON.stringify(snapshotFixture)}, "utf8"))`, + 'arg1', 'arg2', +]; +const snapshotBlobArgs = [ + '--embedder-snapshot-blob', tmpdir.resolve('embedder-snapshot.blob'), +]; + +const runSnapshotExecArgs = ['arg3', 'arg4']; + +tmpdir.refresh(); + +// Build the snapshot with the worker-creating code in serialized main funciton. +spawnSyncAndExitWithoutError( + embedtest, + ['--', ...buildSnapshotExecArgs, ...snapshotBlobArgs, '--embedder-snapshot-create'], + { cwd: tmpdir.path }); + +// Run the snapshot that creates a worker from the snapshot. +spawnSyncAndAssert( + embedtest, + ['--', ...runSnapshotExecArgs, ...snapshotBlobArgs ], + { cwd: tmpdir.path }, + { + stdout: /value: 42/, + }); diff --git a/test/embedding/test-embedding-throw.js b/test/embedding/test-embedding-throw.js new file mode 100644 index 00000000000000..8aacade67d40df --- /dev/null +++ b/test/embedding/test-embedding-throw.js @@ -0,0 +1,14 @@ +'use strict'; + +// Tests that uncaught exceptions are handled correctly in embedded environments. + +const common = require('../common'); +const { spawnSyncAndExit } = require('../common/child_process'); + +spawnSyncAndExit( + common.resolveBuiltBinary('embedtest'), + ['throw new Error()'], + { + status: 1, + signal: null, + }); diff --git a/test/embedding/test-embedding.js b/test/embedding/test-embedding.js deleted file mode 100644 index 79d79079b4b8c6..00000000000000 --- a/test/embedding/test-embedding.js +++ /dev/null @@ -1,164 +0,0 @@ -'use strict'; -const common = require('../common'); -const fixtures = require('../common/fixtures'); -const tmpdir = require('../common/tmpdir'); -const assert = require('assert'); -const { - spawnSyncAndAssert, - spawnSyncAndExit, - spawnSyncAndExitWithoutError, -} = require('../common/child_process'); -const fs = require('fs'); -const os = require('os'); - -tmpdir.refresh(); -common.allowGlobals(global.require); -common.allowGlobals(global.embedVars); - -const binary = common.resolveBuiltBinary('embedtest'); - -spawnSyncAndAssert( - binary, - ['console.log(42)'], - { - trim: true, - stdout: '42', - }); - -spawnSyncAndAssert( - binary, - ['console.log(embedVars.nön_ascıı)'], - { - trim: true, - stdout: '🏳️‍🌈', - }); - -spawnSyncAndExit( - binary, - ['throw new Error()'], - { - status: 1, - signal: null, - }); - -spawnSyncAndExit( - binary, - ['require("lib/internal/test/binding")'], - { - status: 1, - signal: null, - }); - -spawnSyncAndExit( - binary, - ['process.exitCode = 8'], - { - status: 8, - signal: null, - }); - -const fixturePath = JSON.stringify(fixtures.path('exit.js')); -spawnSyncAndExit( - binary, - [`require(${fixturePath})`, 92], - { - status: 92, - signal: null, - }); - -function getReadFileCodeForPath(path) { - return `(require("fs").readFileSync(${JSON.stringify(path)}, "utf8"))`; -} - -// Basic snapshot support -for (const extraSnapshotArgs of [ - [], ['--embedder-snapshot-as-file'], ['--without-code-cache'], -]) { - // readSync + eval since snapshots don't support userland require() (yet) - const snapshotFixture = fixtures.path('snapshot', 'echo-args.js'); - const blobPath = tmpdir.resolve('embedder-snapshot.blob'); - const buildSnapshotExecArgs = [ - `eval(${getReadFileCodeForPath(snapshotFixture)})`, 'arg1', 'arg2', - ]; - const embedTestBuildArgs = [ - '--embedder-snapshot-blob', blobPath, '--embedder-snapshot-create', - ...extraSnapshotArgs, - ]; - const buildSnapshotArgs = [ - ...buildSnapshotExecArgs, - ...embedTestBuildArgs, - ]; - - const runSnapshotExecArgs = [ - 'arg3', 'arg4', - ]; - const embedTestRunArgs = [ - '--embedder-snapshot-blob', blobPath, - ...extraSnapshotArgs, - ]; - const runSnapshotArgs = [ - ...runSnapshotExecArgs, - ...embedTestRunArgs, - ]; - - fs.rmSync(blobPath, { force: true }); - spawnSyncAndExitWithoutError( - binary, - [ '--', ...buildSnapshotArgs ], - { cwd: tmpdir.path }); - spawnSyncAndAssert( - binary, - [ '--', ...runSnapshotArgs ], - { cwd: tmpdir.path }, - { - stdout(output) { - assert.deepStrictEqual(JSON.parse(output), { - originalArgv: [binary, '__node_anonymous_main', ...buildSnapshotExecArgs], - currentArgv: [binary, ...runSnapshotExecArgs], - }); - return true; - }, - }); -} - -// Create workers and vm contexts after deserialization -{ - const snapshotFixture = fixtures.path('snapshot', 'create-worker-and-vm.js'); - const blobPath = tmpdir.resolve('embedder-snapshot.blob'); - const buildSnapshotArgs = [ - `eval(${getReadFileCodeForPath(snapshotFixture)})`, - '--embedder-snapshot-blob', blobPath, '--embedder-snapshot-create', - ]; - const runEmbeddedArgs = [ - '--embedder-snapshot-blob', blobPath, - ]; - - fs.rmSync(blobPath, { force: true }); - - spawnSyncAndExitWithoutError( - binary, - [ '--', ...buildSnapshotArgs ], - { cwd: tmpdir.path }); - spawnSyncAndExitWithoutError( - binary, - [ '--', ...runEmbeddedArgs ], - { cwd: tmpdir.path }); -} - -// Guarantee NODE_REPL_EXTERNAL_MODULE won't bypass kDisableNodeOptionsEnv -if (!process.config.variables.node_without_node_options) { - spawnSyncAndExit( - binary, - ['require("os")'], - { - env: { - ...process.env, - 'NODE_REPL_EXTERNAL_MODULE': 'fs', - }, - }, - { - status: 9, - signal: null, - stderr: `${binary}: NODE_REPL_EXTERNAL_MODULE can't be used with kDisableNodeOptionsEnv${os.EOL}`, - }); -} diff --git a/test/embedding/testcfg.py b/test/embedding/testcfg.py index a4b90f490c670f..f63bc393a6a878 100644 --- a/test/embedding/testcfg.py +++ b/test/embedding/testcfg.py @@ -3,4 +3,4 @@ import testpy def GetConfiguration(context, root): - return testpy.SimpleTestConfiguration(context, root, 'embedding') + return testpy.ParallelTestConfiguration(context, root, 'embedding') diff --git a/test/fixtures/snapshot/create-vm.js b/test/fixtures/snapshot/create-vm.js new file mode 100644 index 00000000000000..72f4eee45ef500 --- /dev/null +++ b/test/fixtures/snapshot/create-vm.js @@ -0,0 +1,11 @@ +const { + setDeserializeMainFunction, +} = require('v8').startupSnapshot; +const assert = require('assert'); + +setDeserializeMainFunction(() => { + const vm = require('vm'); + const result = vm.runInNewContext('21+21'); + console.log(`value: ${result}`); + assert.strictEqual(result, 42); +}); diff --git a/test/fixtures/snapshot/create-worker-and-vm.js b/test/fixtures/snapshot/create-worker.js similarity index 70% rename from test/fixtures/snapshot/create-worker-and-vm.js rename to test/fixtures/snapshot/create-worker.js index 4dd2aa940247af..d27c145dae30d5 100644 --- a/test/fixtures/snapshot/create-worker-and-vm.js +++ b/test/fixtures/snapshot/create-worker.js @@ -4,17 +4,19 @@ const { const assert = require('assert'); setDeserializeMainFunction(() => { - const vm = require('vm'); const { Worker } = require('worker_threads'); - assert.strictEqual(vm.runInNewContext('21+21'), 42); const worker = new Worker( 'require("worker_threads").parentPort.postMessage({value: 21 + 21})', { eval: true }); const messages = []; - worker.on('message', message => messages.push(message)); + worker.on('message', (message) => { + console.log('Worker message:', message); + messages.push(message); + }); process.on('beforeExit', () => { + console.log('Process beforeExit, messages:', messages); assert.deepStrictEqual(messages, [{value:42}]); - }) + }); });