summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnna Henningsen <anna@addaleax.net>2020-03-12 13:11:48 +0100
committerAnna Henningsen <anna@addaleax.net>2020-03-21 10:58:28 +0100
commit2061c336709939fec9549254d6d8b072b3685fbd (patch)
tree6416aad4b9af605c8fd10ecb7cdc58d88257c65c
parente04f599258bb8e733a507867d42d5e46d35d7bca (diff)
downloadnode-new-2061c336709939fec9549254d6d8b072b3685fbd.tar.gz
test: add extended embedder cctest
Add an embedder cctest that also covers a multi-Environment situation, including worker_threads-style inspector support. Co-authored-by: Joyee Cheung <joyeec9h3@gmail.com> PR-URL: https://github.com/nodejs/node/pull/30467 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Gireesh Punathil <gpunathi@in.ibm.com>
-rw-r--r--Makefile4
-rw-r--r--test/cctest/test_environment.cc141
-rw-r--r--test/embedding/test-embedding.js33
-rw-r--r--test/embedding/test.js19
-rw-r--r--test/embedding/testcfg.py6
-rwxr-xr-xtools/test.py1
6 files changed, 183 insertions, 21 deletions
diff --git a/Makefile b/Makefile
index e144d8b81c..71917bb614 100644
--- a/Makefile
+++ b/Makefile
@@ -278,7 +278,7 @@ coverage-report-js:
# Runs the C++ tests using the built `cctest` executable.
cctest: all
@out/$(BUILDTYPE)/$@ --gtest_filter=$(GTEST_FILTER)
- @out/$(BUILDTYPE)/embedtest "require('./test/embedding/test.js')"
+ @out/$(BUILDTYPE)/embedtest "require('./test/embedding/test-embedding.js')"
.PHONY: list-gtests
list-gtests:
@@ -532,7 +532,7 @@ test-ci: | clear-stalled build-addons build-js-native-api-tests build-node-api-t
$(PYTHON) tools/test.py $(PARALLEL_ARGS) -p tap --logfile test.tap \
--mode=$(BUILDTYPE_LOWER) --flaky-tests=$(FLAKY_TESTS) \
$(TEST_CI_ARGS) $(CI_JS_SUITES) $(CI_NATIVE_SUITES) $(CI_DOC)
- out/Release/embedtest 'require("./test/embedding/test.js")'
+ out/Release/embedtest 'require("./test/embedding/test-embedding.js")'
@echo "Clean up any leftover processes, error if found."
ps awwx | grep Release/node | grep -v grep | cat
@PS_OUT=`ps awwx | grep Release/node | grep -v grep | awk '{print $$1}'`; \
diff --git a/test/cctest/test_environment.cc b/test/cctest/test_environment.cc
index 4d8237f103..23b37ee3c6 100644
--- a/test/cctest/test_environment.cc
+++ b/test/cctest/test_environment.cc
@@ -306,3 +306,144 @@ TEST_F(EnvironmentTest, BufferWithFreeCallbackIsDetached) {
CHECK_EQ(callback_calls, 1);
CHECK_EQ(ab->ByteLength(), 0);
}
+
+#if HAVE_INSPECTOR
+TEST_F(EnvironmentTest, InspectorMultipleEmbeddedEnvironments) {
+ // Tests that child Environments can be created through the public API
+ // that are accessible by the inspector.
+ // This test sets a global variable in the child Environment, and reads it
+ // back both through the inspector and inside the child Environment, and
+ // makes sure that those correspond to the value that was originally set.
+ const v8::HandleScope handle_scope(isolate_);
+ const Argv argv;
+ Env env {handle_scope, argv};
+
+ v8::Local<v8::Context> context = isolate_->GetCurrentContext();
+ node::LoadEnvironment(*env,
+ "'use strict';\n"
+ "const { Worker } = require('worker_threads');\n"
+ "const { Session } = require('inspector');\n"
+
+ "const session = new Session();\n"
+ "session.connect();\n"
+ "session.on('NodeWorker.attachedToWorker', (\n"
+ " ({ params: { workerInfo, sessionId } }) => {\n"
+ " session.post('NodeWorker.sendMessageToWorker', {\n"
+ " sessionId,\n"
+ " message: JSON.stringify({\n"
+ " id: 1,\n"
+ " method: 'Runtime.evaluate',\n"
+ " params: {\n"
+ " expression: 'global.variableFromParent = 42;'\n"
+ " }\n"
+ " })\n"
+ " });\n"
+ " session.on('NodeWorker.receivedMessageFromWorker',\n"
+ " ({ params: { message } }) => {\n"
+ " global.messageFromWorker = \n"
+ " JSON.parse(message).result.result.value;\n"
+ " });\n"
+ " }));\n"
+ "session.post('NodeWorker.enable', { waitForDebuggerOnStart: false });\n")
+ .ToLocalChecked();
+
+ struct ChildEnvironmentData {
+ node::ThreadId thread_id;
+ std::unique_ptr<node::InspectorParentHandle> inspector_parent_handle;
+ node::MultiIsolatePlatform* platform;
+ int32_t extracted_value = -1;
+ uv_async_t thread_stopped_async;
+ };
+
+ ChildEnvironmentData data;
+ data.thread_id = node::AllocateEnvironmentThreadId();
+ data.inspector_parent_handle =
+ GetInspectorParentHandle(*env, data.thread_id, "file:///embedded.js");
+ CHECK(data.inspector_parent_handle);
+ data.platform = GetMultiIsolatePlatform(*env);
+ CHECK_NOT_NULL(data.platform);
+
+ bool thread_stopped = false;
+ int err = uv_async_init(
+ &current_loop, &data.thread_stopped_async, [](uv_async_t* async) {
+ *static_cast<bool*>(async->data) = true;
+ uv_close(reinterpret_cast<uv_handle_t*>(async), nullptr);
+ });
+ CHECK_EQ(err, 0);
+ data.thread_stopped_async.data = &thread_stopped;
+
+ uv_thread_t thread;
+ err = uv_thread_create(&thread, [](void* arg) {
+ ChildEnvironmentData* data = static_cast<ChildEnvironmentData*>(arg);
+ std::shared_ptr<node::ArrayBufferAllocator> aba =
+ node::ArrayBufferAllocator::Create();
+ uv_loop_t loop;
+ uv_loop_init(&loop);
+ v8::Isolate* isolate = NewIsolate(aba, &loop, data->platform);
+ CHECK_NOT_NULL(isolate);
+
+ {
+ v8::Isolate::Scope isolate_scope(isolate);
+ v8::HandleScope handle_scope(isolate);
+
+ v8::Local<v8::Context> context = node::NewContext(isolate);
+ CHECK(!context.IsEmpty());
+ v8::Context::Scope context_scope(context);
+
+ node::IsolateData* isolate_data = node::CreateIsolateData(
+ isolate,
+ &loop,
+ data->platform);
+ CHECK_NOT_NULL(isolate_data);
+ node::Environment* environment = node::CreateEnvironment(
+ isolate_data,
+ context,
+ { "dummy" },
+ {},
+ node::EnvironmentFlags::kNoFlags,
+ data->thread_id);
+ CHECK_NOT_NULL(environment);
+
+ v8::Local<v8::Value> extracted_value = LoadEnvironment(
+ environment,
+ "return global.variableFromParent;",
+ std::move(data->inspector_parent_handle)).ToLocalChecked();
+
+ uv_run(&loop, UV_RUN_DEFAULT);
+ CHECK(extracted_value->IsInt32());
+ data->extracted_value = extracted_value.As<v8::Int32>()->Value();
+
+ node::FreeEnvironment(environment);
+ node::FreeIsolateData(isolate_data);
+ }
+
+ data->platform->UnregisterIsolate(isolate);
+ isolate->Dispose();
+ uv_run(&loop, UV_RUN_DEFAULT);
+ CHECK_EQ(uv_loop_close(&loop), 0);
+
+ uv_async_send(&data->thread_stopped_async);
+ }, &data);
+ CHECK_EQ(err, 0);
+
+ bool more;
+ do {
+ uv_run(&current_loop, UV_RUN_DEFAULT);
+ data.platform->DrainTasks(isolate_);
+ more = uv_loop_alive(&current_loop);
+ } while (!thread_stopped || more);
+
+ uv_thread_join(&thread);
+
+ v8::Local<v8::Value> from_inspector =
+ context->Global()->Get(
+ context,
+ v8::String::NewFromOneByte(
+ isolate_,
+ reinterpret_cast<const uint8_t*>("messageFromWorker"),
+ v8::NewStringType::kNormal).ToLocalChecked())
+ .ToLocalChecked();
+ CHECK_EQ(data.extracted_value, 42);
+ CHECK_EQ(from_inspector->IntegerValue(context).FromJust(), 42);
+}
+#endif // HAVE_INSPECTOR
diff --git a/test/embedding/test-embedding.js b/test/embedding/test-embedding.js
new file mode 100644
index 0000000000..43dab0ab24
--- /dev/null
+++ b/test/embedding/test-embedding.js
@@ -0,0 +1,33 @@
+'use strict';
+const common = require('../common');
+const fixtures = require('../common/fixtures');
+const assert = require('assert');
+const child_process = require('child_process');
+const path = require('path');
+
+common.allowGlobals(global.require);
+let binary = process.features.debug ?
+ 'out/Debug/embedtest' : 'out/Release/embedtest';
+if (common.isWindows) {
+ binary += '.exe';
+}
+binary = path.resolve(__dirname, '..', '..', binary);
+
+assert.strictEqual(
+ child_process.spawnSync(binary, ['console.log(42)'])
+ .stdout.toString().trim(),
+ '42');
+
+assert.strictEqual(
+ child_process.spawnSync(binary, ['throw new Error()']).status,
+ 1);
+
+assert.strictEqual(
+ child_process.spawnSync(binary, ['process.exitCode = 8']).status,
+ 8);
+
+
+const fixturePath = JSON.stringify(fixtures.path('exit.js'));
+assert.strictEqual(
+ child_process.spawnSync(binary, [`require(${fixturePath})`, 92]).status,
+ 92);
diff --git a/test/embedding/test.js b/test/embedding/test.js
deleted file mode 100644
index a802de1849..0000000000
--- a/test/embedding/test.js
+++ /dev/null
@@ -1,19 +0,0 @@
-'use strict';
-const common = require('../common');
-const assert = require('assert');
-const child_process = require('child_process');
-
-common.allowGlobals(global.require);
-
-assert.strictEqual(
- child_process.spawnSync(process.execPath, ['console.log(42)'])
- .stdout.toString().trim(),
- '42');
-
-assert.strictEqual(
- child_process.spawnSync(process.execPath, ['throw new Error()']).status,
- 1);
-
-assert.strictEqual(
- child_process.spawnSync(process.execPath, ['process.exitCode = 8']).status,
- 8);
diff --git a/test/embedding/testcfg.py b/test/embedding/testcfg.py
new file mode 100644
index 0000000000..a4b90f490c
--- /dev/null
+++ b/test/embedding/testcfg.py
@@ -0,0 +1,6 @@
+import sys, os
+sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
+import testpy
+
+def GetConfiguration(context, root):
+ return testpy.SimpleTestConfiguration(context, root, 'embedding')
diff --git a/tools/test.py b/tools/test.py
index 112d5edaff..5eb1fa7672 100755
--- a/tools/test.py
+++ b/tools/test.py
@@ -1491,6 +1491,7 @@ IGNORED_SUITES = [
'addons',
'benchmark',
'doctool',
+ 'embedding',
'internet',
'js-native-api',
'node-api',