From c091cdc74b6079198d9ea8104106c6e7bc23bad3 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Wed, 28 Jan 2026 16:02:55 +0100 Subject: [PATCH 1/2] build,test: add tests for binary linked with shared libnode This adds tests to ensure the V8 parts (v8, libplatform, cppgc) in shared libnode works correctly. PR-URL: https://github.com/nodejs/node/pull/61463 Refs: https://github.com/nodejs/node/pull/61144 Reviewed-By: Antoine du Hamel Reviewed-By: Richard Lau --- node.gyp | 55 ++++++++++++++++++++ test/common/index.js | 11 ++++ test/embedding/shared_embedtest.cc | 60 ++++++++++++++++++++++ test/embedding/test-embedding.js | 10 +--- test/embedding/test-shared-embedding-v8.js | 25 +++++++++ 5 files changed, 152 insertions(+), 9 deletions(-) create mode 100644 test/embedding/shared_embedtest.cc create mode 100644 test/embedding/test-shared-embedding-v8.js diff --git a/node.gyp b/node.gyp index 08f8059c0059..c58f4812e2e1 100644 --- a/node.gyp +++ b/node.gyp @@ -1511,6 +1511,61 @@ ], }, # embedtest + { + 'target_name': 'shared_embedtest', + 'type': 'executable', + + 'dependencies': [ + '<(node_lib_target_name)', + ], + + # Don't depend on node.gypi - it otherwise links to + # the static libraries and resolve symbols at build time. + 'include_dirs': [ + 'deps/v8/include', + ], + + 'sources': [ + 'test/embedding/shared_embedtest.cc', + ], + 'conditions': [ + [ 'node_shared=="true"', { + 'defines': [ + 'USING_V8_SHARED', + 'USING_V8_PLATFORM_SHARED', + ], + 'defines!': [ + 'BUILDING_V8_PLATFORM_SHARED=1', + 'BUILDING_V8_SHARED=1', + ], + }, { + # Only test shared embedding when Node is built as shared library. + 'type': 'none', + }], + # Only test platforms known to work. + ['OS not in "mac win linux"', { + 'type': 'none', + }], + ['OS=="win"', { + 'libraries': [ + 'Dbghelp.lib', + 'winmm.lib', + 'Ws2_32.lib', + ], + }], + ['OS=="mac"', { + 'xcode_settings': { + 'OTHER_LDFLAGS': [ '-Wl,-rpath,@loader_path', ], + } + }], + ['OS=="linux"', { + 'ldflags': [ + '-Wl,-rpath,\\$$ORIGIN' + ], + }], + ], + }, # shared_embedtest + { 'target_name': 'overlapped-checker', 'type': 'executable', diff --git a/test/common/index.js b/test/common/index.js index 6cfebae8f499..6b0dafffef13 100755 --- a/test/common/index.js +++ b/test/common/index.js @@ -51,6 +51,8 @@ if (isMainThread) const noop = () => {}; +// Whether the executable is linked against the shared library i.e. libnode. +const usesSharedLibrary = process.config.variables.node_shared; const hasCrypto = Boolean(process.versions.openssl) && !process.env.NODE_SKIP_CRYPTO; @@ -923,6 +925,13 @@ function sleepSync(ms) { Atomics.wait(i32, 0, 0, ms); } +function resolveBuiltBinary(binary) { + if (isWindows) { + binary += '.exe'; + } + return path.join(path.dirname(process.execPath), binary); +} + const common = { allowGlobals, buildType, @@ -967,6 +976,7 @@ const common = { printSkipMessage, pwdCommand, requireNoPackageJSONAbove, + resolveBuiltBinary, runWithInvalidFD, skip, skipIf32Bits, @@ -975,6 +985,7 @@ const common = { skipIfSQLiteMissing, spawnPromisified, sleepSync, + usesSharedLibrary, get enoughTestMem() { return require('os').totalmem() > 0x70000000; /* 1.75 Gb */ diff --git a/test/embedding/shared_embedtest.cc b/test/embedding/shared_embedtest.cc new file mode 100644 index 000000000000..f071f43c5b76 --- /dev/null +++ b/test/embedding/shared_embedtest.cc @@ -0,0 +1,60 @@ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +class Wrappable : public v8::Object::Wrappable { + public: + void Trace(cppgc::Visitor* visitor) const override { + v8::Object::Wrappable::Trace(visitor); + } +}; + +int main(int argc, char* argv[]) { + std::unique_ptr platform = v8::platform::NewDefaultPlatform(); + v8::V8::InitializePlatform(platform.get()); + cppgc::InitializeProcess(platform->GetPageAllocator()); + v8::V8::Initialize(); + + auto heap = v8::CppHeap::Create(platform.get(), v8::CppHeapCreateParams{{}}); + v8::Isolate::CreateParams create_params; + create_params.array_buffer_allocator = + v8::ArrayBuffer::Allocator::NewDefaultAllocator(); + create_params.cpp_heap = heap.release(); + + v8::Isolate* isolate = v8::Isolate::New(create_params); + { + v8::Isolate::Scope isolate_scope(isolate); + v8::HandleScope handle_scope(isolate); + v8::Local context = v8::Context::New(isolate); + v8::Context::Scope context_scope(context); + + v8::Local obj = v8::Object::New(isolate); + Wrappable* wrappable = cppgc::MakeGarbageCollected( + isolate->GetCppHeap()->GetAllocationHandle()); + v8::Object::Wrap( + isolate, obj, wrappable); + v8::Local source = + v8::String::NewFromUtf8Literal(isolate, "'Hello' + ', World!'"); + v8::Local script = + v8::Script::Compile(context, source).ToLocalChecked(); + v8::Local result = script->Run(context).ToLocalChecked(); + v8::String::Utf8Value utf8(isolate, result); + printf("%s\n", *utf8); + } + + isolate->Dispose(); + cppgc::ShutdownProcess(); + v8::V8::Dispose(); + v8::V8::DisposePlatform(); + delete create_params.array_buffer_allocator; + + return 0; +} diff --git a/test/embedding/test-embedding.js b/test/embedding/test-embedding.js index 49706079fd8b..79d79079b4b8 100644 --- a/test/embedding/test-embedding.js +++ b/test/embedding/test-embedding.js @@ -8,7 +8,6 @@ const { spawnSyncAndExit, spawnSyncAndExitWithoutError, } = require('../common/child_process'); -const path = require('path'); const fs = require('fs'); const os = require('os'); @@ -16,14 +15,7 @@ tmpdir.refresh(); common.allowGlobals(global.require); common.allowGlobals(global.embedVars); -function resolveBuiltBinary(binary) { - if (common.isWindows) { - binary += '.exe'; - } - return path.join(path.dirname(process.execPath), binary); -} - -const binary = resolveBuiltBinary('embedtest'); +const binary = common.resolveBuiltBinary('embedtest'); spawnSyncAndAssert( binary, diff --git a/test/embedding/test-shared-embedding-v8.js b/test/embedding/test-shared-embedding-v8.js new file mode 100644 index 000000000000..4d03a9d4b480 --- /dev/null +++ b/test/embedding/test-shared-embedding-v8.js @@ -0,0 +1,25 @@ +'use strict'; + +// This tests the V8 parts in the shared library work correctly. +// TODO(joyeecheung): also test that the Node.js parts work correctly, +// which can be done in embedtest just built in shared library mode. + +const common = require('../common'); + +if (!common.usesSharedLibrary) { + common.skip('Only tests builds linking against Node.js shared library'); +} + +const { spawnSyncAndAssert } = require('../common/child_process'); +const fs = require('fs'); + +const binary = common.resolveBuiltBinary('shared_embedtest'); + +if (!fs.existsSync(binary)) { + common.skip('shared_embedtest binary not built'); +} + +spawnSyncAndAssert(binary, { + trim: true, + stdout: 'Hello, World!', +}); From f3038b10c96c4c244a310b33f41b2e1add77a312 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Sun, 8 Feb 2026 14:18:27 +0100 Subject: [PATCH 2/2] 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. PR-URL: https://github.com/nodejs/node/pull/61571 Reviewed-By: Luigi Pinca --- .../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 000000000000..28a09f60d99e --- /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 000000000000..d88ae4e39a17 --- /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 000000000000..13492e916947 --- /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 000000000000..35cd7ffc1253 --- /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 000000000000..2627dd34fc1f --- /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 000000000000..dfc5d52a86f6 --- /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 000000000000..5a9b4b1d9283 --- /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 000000000000..8ace784116df --- /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 000000000000..0d60059056ad --- /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 000000000000..577ace1188ff --- /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 000000000000..c6f665eed4d1 --- /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 000000000000..8aacade67d40 --- /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 79d79079b4b8..000000000000 --- 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 a4b90f490c67..f63bc393a6a8 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 000000000000..72f4eee45ef5 --- /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 4dd2aa940247..d27c145dae30 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}]); - }) + }); });