@@ -266,10 +266,10 @@ TEST_F(EnvironmentTest, SetImmediateCleanup) {
266266 EXPECT_EQ (env_arg, *env);
267267 called++;
268268 });
269- (*env)->SetUnrefImmediate ([&](node::Environment* env_arg) {
269+ (*env)->SetImmediate ([&](node::Environment* env_arg) {
270270 EXPECT_EQ (env_arg, *env);
271271 called_unref++;
272- });
272+ }, node::CallbackFlags:: kUnrefed );
273273 }
274274
275275 EXPECT_EQ (called, 1 );
@@ -307,25 +307,143 @@ TEST_F(EnvironmentTest, BufferWithFreeCallbackIsDetached) {
307307 CHECK_EQ (ab->ByteLength (), 0 );
308308}
309309
310- TEST_F (EnvironmentTest, SetImmediateCleanup) {
311- int called = 0 ;
312- int called_unref = 0 ;
313-
314- {
315- const v8::HandleScope handle_scope (isolate_);
316- const Argv argv;
317- Env env {handle_scope, argv};
318-
319- (*env)->SetImmediate ([&](node::Environment* env_arg) {
320- EXPECT_EQ (env_arg, *env);
321- called++;
322- });
323- (*env)->SetImmediate ([&](node::Environment* env_arg) {
324- EXPECT_EQ (env_arg, *env);
325- called_unref++;
326- }, node::CallbackFlags::kUnrefed );
327- }
310+ #if HAVE_INSPECTOR
311+ TEST_F (EnvironmentTest, InspectorMultipleEmbeddedEnvironments) {
312+ // Tests that child Environments can be created through the public API
313+ // that are accessible by the inspector.
314+ // This test sets a global variable in the child Environment, and reads it
315+ // back both through the inspector and inside the child Environment, and
316+ // makes sure that those correspond to the value that was originally set.
317+ const v8::HandleScope handle_scope (isolate_);
318+ const Argv argv;
319+ Env env {handle_scope, argv};
328320
329- EXPECT_EQ (called, 1 );
330- EXPECT_EQ (called_unref, 0 );
321+ v8::Local<v8::Context> context = isolate_->GetCurrentContext ();
322+ node::LoadEnvironment (*env,
323+ " 'use strict';\n "
324+ " const { Worker } = require('worker_threads');\n "
325+ " const { Session } = require('inspector');\n "
326+
327+ " const session = new Session();\n "
328+ " session.connect();\n "
329+ " session.on('NodeWorker.attachedToWorker', (\n "
330+ " ({ params: { workerInfo, sessionId } }) => {\n "
331+ " session.post('NodeWorker.sendMessageToWorker', {\n "
332+ " sessionId,\n "
333+ " message: JSON.stringify({\n "
334+ " id: 1,\n "
335+ " method: 'Runtime.evaluate',\n "
336+ " params: {\n "
337+ " expression: 'global.variableFromParent = 42;'\n "
338+ " }\n "
339+ " })\n "
340+ " });\n "
341+ " session.on('NodeWorker.receivedMessageFromWorker',\n "
342+ " ({ params: { message } }) => {\n "
343+ " global.messageFromWorker = \n "
344+ " JSON.parse(message).result.result.value;\n "
345+ " });\n "
346+ " }));\n "
347+ " session.post('NodeWorker.enable', { waitForDebuggerOnStart: false });\n " )
348+ .ToLocalChecked ();
349+
350+ struct ChildEnvironmentData {
351+ node::ThreadId thread_id;
352+ std::unique_ptr<node::InspectorParentHandle> inspector_parent_handle;
353+ node::MultiIsolatePlatform* platform;
354+ int32_t extracted_value = -1 ;
355+ uv_async_t thread_stopped_async;
356+ };
357+
358+ ChildEnvironmentData data;
359+ data.thread_id = node::AllocateEnvironmentThreadId ();
360+ data.inspector_parent_handle =
361+ GetInspectorParentHandle (*env, data.thread_id , " file:///embedded.js" );
362+ CHECK (data.inspector_parent_handle );
363+ data.platform = GetMultiIsolatePlatform (*env);
364+ CHECK_NOT_NULL (data.platform );
365+
366+ bool thread_stopped = false ;
367+ int err = uv_async_init (
368+ ¤t_loop, &data.thread_stopped_async , [](uv_async_t * async) {
369+ *static_cast <bool *>(async->data ) = true ;
370+ uv_close (reinterpret_cast <uv_handle_t *>(async), nullptr );
371+ });
372+ CHECK_EQ (err, 0 );
373+ data.thread_stopped_async .data = &thread_stopped;
374+
375+ uv_thread_t thread;
376+ err = uv_thread_create (&thread, [](void * arg) {
377+ ChildEnvironmentData* data = static_cast <ChildEnvironmentData*>(arg);
378+ std::shared_ptr<node::ArrayBufferAllocator> aba =
379+ node::ArrayBufferAllocator::Create ();
380+ uv_loop_t loop;
381+ uv_loop_init (&loop);
382+ v8::Isolate* isolate = NewIsolate (aba.get (), &loop, data->platform );
383+ CHECK_NOT_NULL (isolate);
384+
385+ {
386+ v8::Isolate::Scope isolate_scope (isolate);
387+ v8::HandleScope handle_scope (isolate);
388+
389+ v8::Local<v8::Context> context = node::NewContext (isolate);
390+ CHECK (!context.IsEmpty ());
391+ v8::Context::Scope context_scope (context);
392+
393+ node::IsolateData* isolate_data = node::CreateIsolateData (
394+ isolate,
395+ &loop,
396+ data->platform );
397+ CHECK_NOT_NULL (isolate_data);
398+ node::Environment* environment = node::CreateEnvironment (
399+ isolate_data,
400+ context,
401+ { " dummy" },
402+ {},
403+ node::EnvironmentFlags::kNoFlags ,
404+ data->thread_id );
405+ CHECK_NOT_NULL (environment);
406+
407+ v8::Local<v8::Value> extracted_value = LoadEnvironment (
408+ environment,
409+ " return global.variableFromParent;" ,
410+ std::move (data->inspector_parent_handle )).ToLocalChecked ();
411+
412+ uv_run (&loop, UV_RUN_DEFAULT);
413+ CHECK (extracted_value->IsInt32 ());
414+ data->extracted_value = extracted_value.As <v8::Int32>()->Value ();
415+
416+ node::FreeEnvironment (environment);
417+ node::FreeIsolateData (isolate_data);
418+ }
419+
420+ data->platform ->UnregisterIsolate (isolate);
421+ isolate->Dispose ();
422+ uv_run (&loop, UV_RUN_DEFAULT);
423+ CHECK_EQ (uv_loop_close (&loop), 0 );
424+
425+ uv_async_send (&data->thread_stopped_async );
426+ }, &data);
427+ CHECK_EQ (err, 0 );
428+
429+ bool more;
430+ do {
431+ uv_run (¤t_loop, UV_RUN_DEFAULT);
432+ data.platform ->DrainTasks (isolate_);
433+ more = uv_loop_alive (¤t_loop);
434+ } while (!thread_stopped || more);
435+
436+ uv_thread_join (&thread);
437+
438+ v8::Local<v8::Value> from_inspector =
439+ context->Global ()->Get (
440+ context,
441+ v8::String::NewFromOneByte (
442+ isolate_,
443+ reinterpret_cast <const uint8_t *>(" messageFromWorker" ),
444+ v8::NewStringType::kNormal ).ToLocalChecked ())
445+ .ToLocalChecked ();
446+ CHECK_EQ (data.extracted_value , 42 );
447+ CHECK_EQ (from_inspector->IntegerValue (context).FromJust (), 42 );
331448}
449+ #endif // HAVE_INSPECTOR
0 commit comments