From c4032b2f25c9dbb912d07744382d562ff6afdccd Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Mon, 23 Oct 2017 00:52:55 +0200 Subject: [PATCH 1/2] src: cancel pending delayed platform tasks on exit Worker threads need an event loop without active libuv handles in order to shut down. One source of handles that was previously not accounted for were delayed V8 tasks; these create timers that would be standing in the way of clearing the event loop. To solve this, keep track of the scheduled tasks in a list and close their timer handles before the corresponding isolate/loop is removed from the platform. It is not clear from the V8 documentation what the expectation is with respect to pending background tasks at the end of the isolate lifetime; however, an alternative approach of executing these scheduled tasks when flushing them led to an infinite loop of tasks scheduling each other; so it seems safe to assume that the behaviour implemented in this patch is at least acceptable. --- src/node.cc | 6 +++++ src/node.h | 1 + src/node_platform.cc | 54 ++++++++++++++++++++++++++++++++------------ src/node_platform.h | 16 ++++++++++++- src/node_worker.cc | 1 + 5 files changed, 62 insertions(+), 16 deletions(-) diff --git a/src/node.cc b/src/node.cc index 640fbdf8a8..5ab020b213 100644 --- a/src/node.cc +++ b/src/node.cc @@ -289,6 +289,10 @@ static struct { platform_->DrainBackgroundTasks(isolate); } + void CancelVMTasks(Isolate* isolate) { + platform_->CancelPendingDelayedTasks(isolate); + } + #if HAVE_INSPECTOR bool StartInspector(Environment *env, const char* script_path, const node::DebugOptions& options) { @@ -321,6 +325,7 @@ static struct { void Initialize(int thread_pool_size) {} void Dispose() {} void DrainVMTasks(Isolate* isolate) {} + void CancelVMTasks(Isolate* isolate) {} bool StartInspector(Environment *env, const char* script_path, const node::DebugOptions& options) { env->ThrowError("Node compiled with NODE_USE_V8_PLATFORM=0"); @@ -4924,6 +4929,7 @@ inline int Start(Isolate* isolate, IsolateData* isolate_data, uv_key_delete(&thread_local_env); v8_platform.DrainVMTasks(isolate); + v8_platform.CancelVMTasks(isolate); WaitForInspectorDisconnect(&env); #if defined(LEAK_SANITIZER) __lsan_do_leak_check(); diff --git a/src/node.h b/src/node.h index 7531c97a33..511dcb6242 100644 --- a/src/node.h +++ b/src/node.h @@ -214,6 +214,7 @@ class MultiIsolatePlatform : public v8::Platform { public: virtual ~MultiIsolatePlatform() { } virtual void DrainBackgroundTasks(v8::Isolate* isolate) = 0; + virtual void CancelPendingDelayedTasks(v8::Isolate* isolate) = 0; // These will be called by the `IsolateData` creation/destruction functions. virtual void RegisterIsolate(IsolateData* isolate_data, diff --git a/src/node_platform.cc b/src/node_platform.cc index ec2fca6c41..7cec43cbf4 100644 --- a/src/node_platform.cc +++ b/src/node_platform.cc @@ -4,6 +4,7 @@ #include "env.h" #include "env-inl.h" #include "util.h" +#include namespace node { @@ -45,13 +46,17 @@ void PerIsolatePlatformData::CallOnForegroundThread(Task* task) { void PerIsolatePlatformData::CallDelayedOnForegroundThread( Task* task, double delay_in_seconds) { - auto pair = new std::pair(task, delay_in_seconds); - foreground_delayed_tasks_.Push(pair); + auto delayed = new DelayedTask(); + delayed->task = task; + delayed->platform_data = this; + delayed->timeout = delay_in_seconds; + foreground_delayed_tasks_.Push(delayed); uv_async_send(flush_tasks_); } PerIsolatePlatformData::~PerIsolatePlatformData() { FlushForegroundTasksInternal(); + CancelPendingDelayedTasks(); uv_close(reinterpret_cast(flush_tasks_), [](uv_handle_t* handle) { @@ -120,7 +125,7 @@ size_t NodePlatform::NumberOfAvailableBackgroundThreads() { return threads_.size(); } -static void RunForegroundTask(Task* task) { +void PerIsolatePlatformData::RunForegroundTask(Task* task) { Isolate* isolate = Isolate::GetCurrent(); HandleScope scope(isolate); Environment* env = Environment::GetCurrent(isolate); @@ -130,14 +135,29 @@ static void RunForegroundTask(Task* task) { delete task; } -static void RunForegroundTask(uv_timer_t* handle) { - Task* task = static_cast(handle->data); - RunForegroundTask(task); - uv_close(reinterpret_cast(handle), [](uv_handle_t* handle) { - delete reinterpret_cast(handle); +void PerIsolatePlatformData::RunForegroundTask(uv_timer_t* handle) { + DelayedTask* delayed = static_cast(handle->data); + auto& tasklist = delayed->platform_data->scheduled_delayed_tasks_; + auto it = std::find(tasklist.begin(), tasklist.end(), delayed); + CHECK_NE(it, tasklist.end()); + tasklist.erase(it); + RunForegroundTask(delayed->task); + uv_close(reinterpret_cast(&delayed->timer), + [](uv_handle_t* handle) { + delete static_cast(handle->data); }); } +void PerIsolatePlatformData::CancelPendingDelayedTasks() { + for (auto delayed : scheduled_delayed_tasks_) { + uv_close(reinterpret_cast(&delayed->timer), + [](uv_handle_t* handle) { + delete static_cast(handle->data); + }); + } + scheduled_delayed_tasks_.clear(); +} + void NodePlatform::DrainBackgroundTasks(Isolate* isolate) { PerIsolatePlatformData* per_isolate = ForIsolate(isolate); @@ -152,18 +172,18 @@ void NodePlatform::DrainBackgroundTasks(Isolate* isolate) { bool PerIsolatePlatformData::FlushForegroundTasksInternal() { bool did_work = false; + while (auto delayed = foreground_delayed_tasks_.Pop()) { did_work = true; uint64_t delay_millis = - static_cast(delayed->second + 0.5) * 1000; - uv_timer_t* handle = new uv_timer_t(); - handle->data = static_cast(delayed->first); - uv_timer_init(loop_, handle); + static_cast(delayed->timeout + 0.5) * 1000; + delayed->timer.data = static_cast(delayed); + uv_timer_init(loop_, &delayed->timer); // Timers may not guarantee queue ordering of events with the same delay if // the delay is non-zero. This should not be a problem in practice. - uv_timer_start(handle, RunForegroundTask, delay_millis, 0); - uv_unref(reinterpret_cast(handle)); - delete delayed; + uv_timer_start(&delayed->timer, RunForegroundTask, delay_millis, 0); + uv_unref(reinterpret_cast(&delayed->timer)); + scheduled_delayed_tasks_.push_back(delayed); } while (Task* task = foreground_tasks_.Pop()) { did_work = true; @@ -199,6 +219,10 @@ void NodePlatform::FlushForegroundTasks(v8::Isolate* isolate) { ForIsolate(isolate)->FlushForegroundTasksInternal(); } +void NodePlatform::CancelPendingDelayedTasks(v8::Isolate* isolate) { + ForIsolate(isolate)->CancelPendingDelayedTasks(); +} + bool NodePlatform::IdleTasksEnabled(Isolate* isolate) { return false; } double NodePlatform::MonotonicallyIncreasingTime() { diff --git a/src/node_platform.h b/src/node_platform.h index aa9bf327d7..73c2509e1a 100644 --- a/src/node_platform.h +++ b/src/node_platform.h @@ -14,6 +14,7 @@ namespace node { class NodePlatform; class IsolateData; +class PerIsolatePlatformData; template class TaskQueue { @@ -37,6 +38,13 @@ class TaskQueue { std::queue task_queue_; }; +struct DelayedTask { + v8::Task* task; + uv_timer_t timer; + double timeout; + PerIsolatePlatformData* platform_data; +}; + class PerIsolatePlatformData { public: PerIsolatePlatformData(v8::Isolate* isolate, uv_loop_t* loop); @@ -52,15 +60,20 @@ class PerIsolatePlatformData { // Returns true iff work was dispatched or executed. bool FlushForegroundTasksInternal(); + void CancelPendingDelayedTasks(); + private: static void FlushTasks(uv_async_t* handle); + static void RunForegroundTask(v8::Task* task); + static void RunForegroundTask(uv_timer_t* timer); int ref_count_ = 1; v8::Isolate* isolate_; uv_loop_t* const loop_; uv_async_t* flush_tasks_ = nullptr; TaskQueue foreground_tasks_; - TaskQueue> foreground_delayed_tasks_; + TaskQueue foreground_delayed_tasks_; + std::vector scheduled_delayed_tasks_; }; class NodePlatform : public MultiIsolatePlatform { @@ -69,6 +82,7 @@ class NodePlatform : public MultiIsolatePlatform { virtual ~NodePlatform() {} void DrainBackgroundTasks(v8::Isolate* isolate) override; + void CancelPendingDelayedTasks(v8::Isolate* isolate) override; void Shutdown(); // v8::Platform implementation. diff --git a/src/node_worker.cc b/src/node_worker.cc index 03c9f59aae..759e2a8d20 100644 --- a/src/node_worker.cc +++ b/src/node_worker.cc @@ -300,6 +300,7 @@ void Worker::Run() { Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE); platform->DrainBackgroundTasks(isolate_); + platform->CancelPendingDelayedTasks(isolate_); // Grab the parent-to-child channel and render is unusable. MessagePort* child_port; From 3e3947f1fa93bb24e6c004abe41962178a2a1609 Mon Sep 17 00:00:00 2001 From: Petka Antonov Date: Sat, 13 Feb 2016 16:58:12 +0200 Subject: [PATCH 2/2] test: add more tests for workers Taken from https://github.com/petkaantonov/io.js/commit/ea143f72fc6845668716bd7a5da22771011defe4 and modified to fit current linter rules and coding style. Also, some new tests were added to the suite. --- Makefile | 2 + test/common/index.js | 10 +- test/parallel/test-worker-termination-2.js | 13 ++ test/parallel/test-worker-termination-3.js | 22 ++ .../test-worker-termination-exit-2.js | 30 +++ test/parallel/test-worker-termination-exit.js | 26 +++ .../test-worker-termination-grand-parent.js | 54 +++++ .../parallel/test-worker-termination-owner.js | 31 +++ .../parallel/test-worker-termination-races.js | 114 ++++++++++ test/parallel/test-worker-termination.js | 18 ++ test/parallel/test-worker-unref-2.js | 35 +++ test/parallel/test-worker-unref.js | 28 +++ test/workers/index.js | 38 ++++ test/workers/test-child-process.js | 48 +++++ test/workers/test-crypto.js | 35 +++ test/workers/test-fs.js | 59 ++++++ test/workers/test-http.js | 199 ++++++++++++++++++ test/workers/test-http2.js | 136 ++++++++++++ test/workers/test-process.js | 35 +++ test/workers/test-stream.js | 96 +++++++++ test/workers/test-vm.js | 38 ++++ test/workers/test-zlib.js | 38 ++++ test/workers/testcfg.py | 6 + 23 files changed, 1108 insertions(+), 3 deletions(-) create mode 100644 test/parallel/test-worker-termination-2.js create mode 100644 test/parallel/test-worker-termination-3.js create mode 100644 test/parallel/test-worker-termination-exit-2.js create mode 100644 test/parallel/test-worker-termination-exit.js create mode 100644 test/parallel/test-worker-termination-grand-parent.js create mode 100644 test/parallel/test-worker-termination-owner.js create mode 100644 test/parallel/test-worker-termination-races.js create mode 100644 test/parallel/test-worker-termination.js create mode 100644 test/parallel/test-worker-unref-2.js create mode 100644 test/parallel/test-worker-unref.js create mode 100644 test/workers/index.js create mode 100644 test/workers/test-child-process.js create mode 100644 test/workers/test-crypto.js create mode 100644 test/workers/test-fs.js create mode 100644 test/workers/test-http.js create mode 100644 test/workers/test-http2.js create mode 100644 test/workers/test-process.js create mode 100644 test/workers/test-stream.js create mode 100644 test/workers/test-vm.js create mode 100644 test/workers/test-zlib.js create mode 100644 test/workers/testcfg.py diff --git a/Makefile b/Makefile index fb978380e5..850db10783 100644 --- a/Makefile +++ b/Makefile @@ -465,6 +465,8 @@ test-with-async-hooks: $(CI_JS_SUITES) \ $(CI_NATIVE_SUITES) +test-worker: + $(PYTHON) tools/test.py --mode=release workers ifneq ("","$(wildcard deps/v8/tools/run-tests.py)") test-v8: v8 diff --git a/test/common/index.js b/test/common/index.js index 05f21e25ca..a8373f3c52 100644 --- a/test/common/index.js +++ b/test/common/index.js @@ -159,9 +159,13 @@ exports.refreshTmpDir = function() { fs.mkdirSync(exports.tmpDir); }; -if (process.env.TEST_THREAD_ID) { - exports.PORT += process.env.TEST_THREAD_ID * 100; - exports.tmpDirName += `.${process.env.TEST_THREAD_ID}`; +const { workerData } = require('worker'); +if ((workerData && workerData.testThreadId) || process.env.TEST_THREAD_ID) { + const id = +((workerData && workerData.testThreadId) || + process.env.TEST_THREAD_ID); + + exports.PORT += id * 100; + exports.tmpDirName += `.${id}`; } exports.tmpDir = path.join(testRoot, exports.tmpDirName); diff --git a/test/parallel/test-worker-termination-2.js b/test/parallel/test-worker-termination-2.js new file mode 100644 index 0000000000..11330a550f --- /dev/null +++ b/test/parallel/test-worker-termination-2.js @@ -0,0 +1,13 @@ +'use strict'; + +const common = require('../common'); +const { Worker, isMainThread, postMessage } = require('worker'); + +if (isMainThread) { + const aWorker = new Worker(__filename); + aWorker.terminate(common.mustCall()); + aWorker.on('message', common.mustNotCall()); +} else { + while (true) + postMessage({ hello: 'world' }); +} diff --git a/test/parallel/test-worker-termination-3.js b/test/parallel/test-worker-termination-3.js new file mode 100644 index 0000000000..c6f0311a47 --- /dev/null +++ b/test/parallel/test-worker-termination-3.js @@ -0,0 +1,22 @@ +'use strict'; + +const common = require('../common'); +const { Worker, isMainThread, postMessage } = require('worker'); + +if (isMainThread) { + const aWorker = new Worker(__filename); + aWorker.on('message', common.mustCallAtLeast(function() { + aWorker.postMessage(); + aWorker.postMessage(); + aWorker.postMessage(); + aWorker.postMessage(); + aWorker.terminate(common.mustCall()); + })); +} else { + require('worker').on('workerMessage', function() { + while (true) + postMessage({ hello: 'world' }); + }); + + postMessage(); +} diff --git a/test/parallel/test-worker-termination-exit-2.js b/test/parallel/test-worker-termination-exit-2.js new file mode 100644 index 0000000000..da191e07f1 --- /dev/null +++ b/test/parallel/test-worker-termination-exit-2.js @@ -0,0 +1,30 @@ +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const { Worker, isMainThread, postMessage } = require('worker'); + +if (isMainThread) { + const aWorker = new Worker(__filename, { keepAlive: false }); + aWorker.on('exit', common.mustCall((code) => { + assert.strictEqual(1337, code); + })); + aWorker.on('message', common.mustCall((data) => { + assert.strictEqual(data, 0); + })); +} else { + process.on('beforeExit', () => { + setInterval(function() { + postMessage({ hello: 'world' }); + }, 5000); + setImmediate(function f() { + postMessage({ hello: 'world' }); + setImmediate(f); + }); + process.exit(1337); + }); + let emits = 0; + process.on('exit', function() { + postMessage(emits++); + }); +} diff --git a/test/parallel/test-worker-termination-exit.js b/test/parallel/test-worker-termination-exit.js new file mode 100644 index 0000000000..f09618f2e5 --- /dev/null +++ b/test/parallel/test-worker-termination-exit.js @@ -0,0 +1,26 @@ +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const { Worker, isMainThread, postMessage } = require('worker'); + +if (isMainThread) { + const aWorker = new Worker(__filename); + aWorker.on('exit', common.mustCall((code) => { + assert.strictEqual(1337, code); + })); + aWorker.on('message', common.mustNotCall()); +} else { + setInterval(function() { + postMessage({ hello: 'world' }); + }, 5000); + setImmediate(function f() { + postMessage({ hello: 'world' }); + setImmediate(f); + }); + (function() { + [1337, 2, 3].map(function(value) { + process.exit(value); + }); + })(); +} diff --git a/test/parallel/test-worker-termination-grand-parent.js b/test/parallel/test-worker-termination-grand-parent.js new file mode 100644 index 0000000000..fac40f25ea --- /dev/null +++ b/test/parallel/test-worker-termination-grand-parent.js @@ -0,0 +1,54 @@ +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const { Worker, isMainThread, postMessage } = require('worker'); +const ids = []; + +if (isMainThread) { + const aWorker = new Worker(__filename); + aWorker.postMessage({ + init: true, + subWorker: false + }); + aWorker.on('message', common.mustCall((data) => { + ids.push(data.id); + if (ids.length === 4) { + // Terminating the main worker should terminate its 4 sub-workers + aWorker.terminate(); + } + }, 4)); + process.on('beforeExit', function() { + assert.deepStrictEqual([0, 1, 2, 3].sort(), ids.sort()); + }); +} else { + require('worker').on('workerMessage', function(data) { + if (data.init) { + if (data.subWorker) { + subWorker(data.id); + } else { + mainWorker(); + } + } + }); +} + +function mainWorker() { + let l = 4; + while (l--) { + const worker = new Worker(__filename); + worker.postMessage({ + init: true, + subWorker: true, + id: l + }); + worker.on('message', function(payload) { + postMessage(payload); + }); + } +} + +function subWorker(id) { + postMessage({ id: id }); + while (true); +} diff --git a/test/parallel/test-worker-termination-owner.js b/test/parallel/test-worker-termination-owner.js new file mode 100644 index 0000000000..ed0d87bad4 --- /dev/null +++ b/test/parallel/test-worker-termination-owner.js @@ -0,0 +1,31 @@ +'use strict'; + +const common = require('../common'); +const { Worker, isMainThread, postMessage } = require('worker'); + +// Test that termination of a worker that is in the middle of processing +// messages from its sub-worker works. + +if (isMainThread) { + const worker = new Worker(__filename); + worker.postMessage({ main: true }); + worker.on('message', common.mustCall(() => { + worker.terminate(common.mustCall()); + })); +} else { + require('worker').on('workerMessage', function(data) { + if (data.main) { + let messagesReceived = 0; + const subworker = new Worker(__filename); + subworker.postMessage({ main: false }); + subworker.on('message', function() { + messagesReceived++; + + if (messagesReceived === 512) + postMessage(); + }); + } else { + while (true) postMessage(); + } + }); +} diff --git a/test/parallel/test-worker-termination-races.js b/test/parallel/test-worker-termination-races.js new file mode 100644 index 0000000000..953f6bf660 --- /dev/null +++ b/test/parallel/test-worker-termination-races.js @@ -0,0 +1,114 @@ +'use strict'; + +const common = require('../common'); + +if (!common.hasCrypto) + common.skip('missing crypto'); + +const { Worker, isMainThread, postMessage } = require('worker'); +const MESSAGES_PER_GRAND_CHILD_WORKER = 20; + +if (isMainThread) { + let l = 4; + const workers = {}; + while (l--) { + const worker = new Worker(__filename); + worker.on('message', common.mustCallAtLeast((data) => { + if (workers[data.id]) return; + worker.terminate(); + workers[data.id] = true; + })); + worker.postMessage({ id: l }); + } +} else { + require('worker').on('workerMessage', function(data) { + if (data.id <= 3) { + runImmediateChildWorker(data); + } else { + runGrandChildWorker(data); + } + }); +} + +function runImmediateChildWorker(mainData) { + const messages = {}; + let l = 4; + while (l--) { + const subWorkerId = mainData.id * 4 + 4 + l; + messages[subWorkerId] = 0; + const worker = new Worker(__filename); + worker.on('message', function(data) { + const count = ++messages[data.id]; + if (count === MESSAGES_PER_GRAND_CHILD_WORKER) { + process.postMessage({ id: mainData.id }); + } + }); + postMessage({ id: subWorkerId }); + } +} + +function runGrandChildWorker(data) { + let l = MESSAGES_PER_GRAND_CHILD_WORKER; + process.stdout; + process.stderr; + process.stdin; + try { require('assert'); } catch (e) {} + try { require('buffer'); } catch (e) {} + try { require('child_process'); } catch (e) {} + try { require('cluster'); } catch (e) {} + try { require('console'); } catch (e) {} + try { require('constants'); } catch (e) {} + try { require('crypto'); } catch (e) {} + try { require('_debug_agent'); } catch (e) {} + try { require('_debugger'); } catch (e) {} + try { require('dgram'); } catch (e) {} + try { require('dns'); } catch (e) {} + try { require('domain'); } catch (e) {} + try { require('events'); } catch (e) {} + try { require('freelist'); } catch (e) {} + try { require('fs'); } catch (e) {} + try { require('_http_agent'); } catch (e) {} + try { require('_http_client'); } catch (e) {} + try { require('_http_common'); } catch (e) {} + try { require('_http_incoming'); } catch (e) {} + try { require('http'); } catch (e) {} + try { require('_http_outgoing'); } catch (e) {} + try { require('_http_server'); } catch (e) {} + try { require('https'); } catch (e) {} + try { require('_linklist'); } catch (e) {} + try { require('module'); } catch (e) {} + try { require('net'); } catch (e) {} + try { require('os'); } catch (e) {} + try { require('path'); } catch (e) {} + try { require('process'); } catch (e) {} + try { require('punycode'); } catch (e) {} + try { require('querystring'); } catch (e) {} + try { require('readline'); } catch (e) {} + try { require('repl'); } catch (e) {} + try { require('smalloc'); } catch (e) {} + try { require('_stream_duplex'); } catch (e) {} + try { require('stream'); } catch (e) {} + try { require('_stream_passthrough'); } catch (e) {} + try { require('_stream_readable'); } catch (e) {} + try { require('_stream_transform'); } catch (e) {} + try { require('_stream_wrap'); } catch (e) {} + try { require('_stream_writable'); } catch (e) {} + try { require('string_decoder'); } catch (e) {} + try { require('timers'); } catch (e) {} + try { require('_tls_common'); } catch (e) {} + try { require('tls'); } catch (e) {} + try { require('_tls_legacy'); } catch (e) {} + try { require('_tls_wrap'); } catch (e) {} + try { require('tty'); } catch (e) {} + try { require('url'); } catch (e) {} + try { require('util'); } catch (e) {} + try { require('v8'); } catch (e) {} + try { require('vm'); } catch (e) {} + try { require('worker'); } catch (e) {} + try { require('zlib'); } catch (e) {} + while (l--) { + postMessage({ + id: data.id + }); + } +} diff --git a/test/parallel/test-worker-termination.js b/test/parallel/test-worker-termination.js new file mode 100644 index 0000000000..ba42843ccf --- /dev/null +++ b/test/parallel/test-worker-termination.js @@ -0,0 +1,18 @@ +'use strict'; + +const common = require('../common'); +const { Worker, isMainThread, postMessage } = require('worker'); + +if (isMainThread) { + const aWorker = new Worker(__filename); + aWorker.terminate(common.mustCall()); + aWorker.on('message', common.mustNotCall()); +} else { + setInterval(function() { + postMessage({ hello: 'world' }); + }, 5000); + setImmediate(function f() { + postMessage({ hello: 'world' }); + setImmediate(f); + }); +} diff --git a/test/parallel/test-worker-unref-2.js b/test/parallel/test-worker-unref-2.js new file mode 100644 index 0000000000..3505aa637a --- /dev/null +++ b/test/parallel/test-worker-unref-2.js @@ -0,0 +1,35 @@ +'use strict'; + +require('../common'); +const assert = require('assert'); +const { Worker, isMainThread, postMessage } = require('worker'); +let checks = 0; + +if (isMainThread) { + const timer = setInterval(function() {}, 1000); + const aWorker = new Worker(__filename); + aWorker.on('exit', function() { + checks++; + }); + aWorker.on('message', function() { + checks++; + setTimeout(function() { + checks++; + aWorker.terminate(function() { + checks++; + clearInterval(timer); + }); + }, 5); + }); + process.on('beforeExit', function() { + assert.strictEqual(4, checks); + }); + aWorker.unref(); + aWorker.postMessage(); +} else { + require('worker').on('workerMessage', function() { + setTimeout(function() { + postMessage(); + }, 1); + }); +} diff --git a/test/parallel/test-worker-unref.js b/test/parallel/test-worker-unref.js new file mode 100644 index 0000000000..5030ca1f76 --- /dev/null +++ b/test/parallel/test-worker-unref.js @@ -0,0 +1,28 @@ +'use strict'; + +require('../common'); +const assert = require('assert'); +const { Worker, isMainThread, postMessage } = require('worker'); +let checks = 0; + +if (isMainThread) { + const aWorker = new Worker(__filename); + aWorker.on('exit', function() { + checks++; + }); + aWorker.on('message', function() { + checks++; + setTimeout(function() { + checks++; + aWorker.terminate(); + }, 5); + }); + process.on('beforeExit', function() { + assert.strictEqual(0, checks); + }); + aWorker.unref(); +} else { + setInterval(function() { + postMessage(); + }, 5); +} diff --git a/test/workers/index.js b/test/workers/index.js new file mode 100644 index 0000000000..d71fb722be --- /dev/null +++ b/test/workers/index.js @@ -0,0 +1,38 @@ +'use strict'; +const common = require('../common'); +const path = require('path'); +const { Worker } = require('worker'); + +common.crashOnUnhandledRejection(); + +exports.runTestInsideWorker = function(testFilePath, workerData) { + return new Promise(function(resolve, reject) { + const worker = new Worker(path.resolve(__dirname, '../../', testFilePath), { + keepAlive: false, + workerData + }); + worker.on('exit', function(exitCode) { + if (exitCode === 0) + resolve(); + else + reject(new Error(`${testFilePath} exited with code ${exitCode}`)); + }); + + worker.on('error', function(e) { + reject(new Error(`Running ${testFilePath} inside worker failed:\n` + + e/*.stack*/)); + }); + }); +}; + +exports.runTestsInsideWorker = async function(tests) { + const parallelism = +process.env.JOBS || require('os').cpus().length; + const testsPerThread = Math.ceil(tests.length / parallelism); + await Promise.all([...Array(parallelism).keys()].map(async (i) => { + const shareOfTests = tests.slice(i * testsPerThread, + (i + 1) * testsPerThread); + for (const testFile of shareOfTests) { + await exports.runTestInsideWorker(testFile, { testThreadId: i }); + } + })); +}; diff --git a/test/workers/test-child-process.js b/test/workers/test-child-process.js new file mode 100644 index 0000000000..be424e7b27 --- /dev/null +++ b/test/workers/test-child-process.js @@ -0,0 +1,48 @@ +'use strict'; + +require('../common'); + +require('./index.js').runTestsInsideWorker([ + 'test/parallel/test-child-process-buffering.js', + 'test/parallel/test-child-process-cwd.js', + // TODO(addaleax): currently leaves a zombie + // 'test/parallel/test-child-process-detached.js', + 'test/parallel/test-child-process-disconnect.js', + 'test/parallel/test-child-process-env.js', + 'test/parallel/test-child-process-exec-cwd.js', + 'test/parallel/test-child-process-exec-env.js', + 'test/parallel/test-child-process-exec-error.js', + 'test/parallel/test-child-process-exit-code.js', + 'test/parallel/test-child-process-fork3.js', + // TODO(addaleax): doesn’t handle tmp dirs correctly for workers + // 'test/parallel/test-child-process-fork-and-spawn.js', + 'test/parallel/test-child-process-fork-close.js', + 'test/parallel/test-child-process-fork-dgram.js', + // TODO(addaleax): doesn’t handle tmp dirs correctly for workers + // 'test/parallel/test-child-process-fork-exec-argv.js', + // TODO(addaleax): doesn’t handle tmp dirs correctly for workers + // 'test/parallel/test-child-process-fork-exec-path.js', + 'test/parallel/test-child-process-fork.js', + 'test/parallel/test-child-process-fork-net2.js', + 'test/parallel/test-child-process-fork-net.js', + 'test/parallel/test-child-process-fork-ref2.js', + 'test/parallel/test-child-process-fork-ref.js', + 'test/parallel/test-child-process-internal.js', + 'test/parallel/test-child-process-ipc.js', + 'test/parallel/test-child-process-kill.js', + 'test/parallel/test-child-process-send-utf8.js', + 'test/parallel/test-child-process-set-blocking.js', + 'test/parallel/test-child-process-spawn-error.js', + 'test/parallel/test-child-process-spawnsync-env.js', + 'test/parallel/test-child-process-spawnsync-input.js', + 'test/parallel/test-child-process-spawnsync.js', + 'test/parallel/test-child-process-spawnsync-timeout.js', + 'test/parallel/test-child-process-spawn-typeerror.js', + 'test/parallel/test-child-process-stdin-ipc.js', + 'test/parallel/test-child-process-stdin.js', + 'test/parallel/test-child-process-stdio-big-write-end.js', + // TODO(addaleax): currently fails + //'test/parallel/test-child-process-stdio.js', + 'test/parallel/test-child-process-stdout-flush-exit.js', + 'test/parallel/test-child-process-stdout-flush.js' +]); diff --git a/test/workers/test-crypto.js b/test/workers/test-crypto.js new file mode 100644 index 0000000000..776a2d5952 --- /dev/null +++ b/test/workers/test-crypto.js @@ -0,0 +1,35 @@ +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); + +require('./index.js').runTestsInsideWorker([ + 'test/parallel/test-crypto-authenticated.js', + 'test/parallel/test-crypto-binary-default.js', + 'test/parallel/test-crypto-certificate.js', + 'test/parallel/test-crypto-cipher-decipher.js', + 'test/parallel/test-crypto-cipheriv-decipheriv.js', + 'test/parallel/test-crypto-classes.js', + 'test/parallel/test-crypto-deprecated.js', + 'test/parallel/test-crypto-dh.js', + 'test/parallel/test-crypto-dh-odd-key.js', + 'test/parallel/test-crypto-dh-padding.js', + 'test/parallel/test-crypto-ecb.js', + 'test/parallel/test-crypto-engine.js', + 'test/parallel/test-crypto-fips.js', + 'test/parallel/test-crypto-from-binary.js', + 'test/parallel/test-crypto-hash.js', + 'test/parallel/test-crypto-hash-stream-pipe.js', + 'test/parallel/test-crypto-hmac.js', + 'test/parallel/test-crypto.js', + 'test/parallel/test-crypto-lazy-transform-writable.js', + 'test/parallel/test-crypto-padding-aes256.js', + 'test/parallel/test-crypto-padding.js', + 'test/parallel/test-crypto-pbkdf2.js', + 'test/parallel/test-crypto-random.js', + 'test/parallel/test-crypto-rsa-dsa.js', + 'test/parallel/test-crypto-sign-verify.js', + 'test/parallel/test-crypto-stream.js', + 'test/parallel/test-crypto-verify-failure.js' +]); diff --git a/test/workers/test-fs.js b/test/workers/test-fs.js new file mode 100644 index 0000000000..4164ab85ea --- /dev/null +++ b/test/workers/test-fs.js @@ -0,0 +1,59 @@ +'use strict'; + +require('../common'); + +require('./index.js').runTestsInsideWorker([ + 'test/parallel/test-fs-access.js', + 'test/parallel/test-fs-append-file.js', + 'test/parallel/test-fs-append-file-sync.js', + 'test/parallel/test-fs-chmod.js', + 'test/parallel/test-fs-empty-readStream.js', + 'test/parallel/test-fs-error-messages.js', + 'test/parallel/test-fs-exists.js', + 'test/parallel/test-fs-fsync.js', + 'test/parallel/test-fs-long-path.js', + 'test/parallel/test-fs-make-callback.js', + 'test/parallel/test-fs-mkdir.js', + 'test/parallel/test-fs-non-number-arguments-throw.js', + 'test/parallel/test-fs-null-bytes.js', + 'test/parallel/test-fs-open.js', + 'test/parallel/test-fs-readfile-empty.js', + 'test/parallel/test-fs-readfile-error.js', + 'test/parallel/test-fs-readfile-pipe.js', + 'test/parallel/test-fs-read-file-sync-hostname.js', + 'test/parallel/test-fs-read-file-sync.js', + 'test/parallel/test-fs-readfile-unlink.js', + 'test/parallel/test-fs-readfile-zero-byte-liar.js', + 'test/parallel/test-fs-read.js', + 'test/parallel/test-fs-read-stream-err.js', + 'test/parallel/test-fs-read-stream-fd.js', + 'test/parallel/test-fs-read-stream-fd-leak.js', + 'test/parallel/test-fs-read-stream-inherit.js', + 'test/parallel/test-fs-read-stream.js', + 'test/parallel/test-fs-read-stream-resume.js', + // Workers cannot chdir. + // 'test/parallel/test-fs-realpath.js', + 'test/parallel/test-fs-sir-writes-alot.js', + 'test/parallel/test-fs-stat.js', + 'test/parallel/test-fs-stream-double-close.js', + 'test/parallel/test-fs-symlink-dir-junction.js', + 'test/parallel/test-fs-symlink-dir-junction-relative.js', + 'test/parallel/test-fs-symlink.js', + 'test/parallel/test-fs-sync-fd-leak.js', + 'test/parallel/test-fs-truncate-fd.js', + 'test/parallel/test-fs-truncate-GH-6233.js', + 'test/parallel/test-fs-truncate.js', + 'test/parallel/test-fs-utimes.js', + 'test/parallel/test-fs-write-buffer.js', + 'test/parallel/test-fs-write-file-buffer.js', + 'test/parallel/test-fs-write-file.js', + // Workers cannot change umask. + // 'test/parallel/test-fs-write-file-sync.js', + 'test/parallel/test-fs-write.js', + 'test/parallel/test-fs-write-stream-change-open.js', + 'test/parallel/test-fs-write-stream-end.js', + 'test/parallel/test-fs-write-stream-err.js', + 'test/parallel/test-fs-write-stream.js', + 'test/parallel/test-fs-write-string-coerce.js', + 'test/parallel/test-fs-write-sync.js' +]); diff --git a/test/workers/test-http.js b/test/workers/test-http.js new file mode 100644 index 0000000000..d5fd0c49b9 --- /dev/null +++ b/test/workers/test-http.js @@ -0,0 +1,199 @@ +'use strict'; +require('../common'); + +require('./index.js').runTestsInsideWorker([ + 'test/parallel/test-http-1.0.js', + 'test/parallel/test-http-1.0-keep-alive.js', + 'test/parallel/test-http-abort-before-end.js', + 'test/parallel/test-http-abort-client.js', + 'test/parallel/test-http-abort-queued-2.js', + 'test/parallel/test-http-abort-queued.js', + 'test/parallel/test-http-abort-stream-end.js', + 'test/parallel/test-http-after-connect.js', + 'test/parallel/test-http-agent-destroyed-socket.js', + 'test/parallel/test-http-agent-error-on-idle.js', + 'test/parallel/test-http-agent-false.js', + 'test/parallel/test-http-agent-getname.js', + 'test/parallel/test-http-agent.js', + 'test/parallel/test-http-agent-keepalive.js', + 'test/parallel/test-http-agent-maxsockets.js', + 'test/parallel/test-http-agent-maxsockets-regress-4050.js', + 'test/parallel/test-http-agent-no-protocol.js', + 'test/parallel/test-http-agent-null.js', + 'test/parallel/test-http-agent-uninitialized.js', + 'test/parallel/test-http-agent-uninitialized-with-handle.js', + 'test/parallel/test-http-allow-req-after-204-res.js', + 'test/parallel/test-http-automatic-headers.js', + 'test/parallel/test-http-bind-twice.js', + 'test/parallel/test-http-blank-header.js', + 'test/parallel/test-http-buffer-sanity.js', + 'test/parallel/test-http-byteswritten.js', + 'test/parallel/test-http-chunked-304.js', + 'test/parallel/test-http-chunked.js', + 'test/parallel/test-http-chunk-problem.js', + 'test/parallel/test-http-client-abort2.js', + 'test/parallel/test-http-client-aborted-event.js', + 'test/parallel/test-http-client-abort-event.js', + 'test/parallel/test-http-client-abort.js', + 'test/parallel/test-http-client-abort-no-agent.js', + 'test/parallel/test-http-client-abort-unix-socket.js', + 'test/parallel/test-http-client-agent.js', + 'test/parallel/test-http-client-check-http-token.js', + 'test/parallel/test-http-client-default-headers-exist.js', + 'test/parallel/test-http-client-defaults.js', + 'test/parallel/test-http-client-encoding.js', + 'test/parallel/test-http-client-get-url.js', + 'test/parallel/test-http-client-immediate-error.js', + 'test/parallel/test-http-client-keep-alive-release-before-finish.js', + 'test/parallel/test-http-client-parse-error.js', + 'test/parallel/test-http-client-pipe-end.js', + 'test/parallel/test-http-client-race-2.js', + 'test/parallel/test-http-client-race.js', + 'test/parallel/test-http-client-readable.js', + 'test/parallel/test-http-client-read-in-error.js', + 'test/parallel/test-http-client-reject-chunked-with-content-length.js', + 'test/parallel/test-http-client-reject-cr-no-lf.js', + 'test/parallel/test-http-client-reject-unexpected-agent.js', + 'test/parallel/test-http-client-timeout-agent.js', + 'test/parallel/test-http-client-timeout-event.js', + 'test/parallel/test-http-client-timeout.js', + 'test/parallel/test-http-client-timeout-on-connect.js', + 'test/parallel/test-http-client-timeout-option.js', + 'test/parallel/test-http-client-timeout-option-listeners.js', + 'test/parallel/test-http-client-timeout-with-data.js', + 'test/parallel/test-http-client-unescaped-path.js', + 'test/parallel/test-http-client-upload-buf.js', + 'test/parallel/test-http-client-upload.js', + 'test/parallel/test-http-common.js', + 'test/parallel/test-http-connect.js', + 'test/parallel/test-http-connect-req-res.js', + 'test/parallel/test-http-conn-reset.js', + 'test/parallel/test-http-contentLength0.js', + 'test/parallel/test-http-content-length.js', + 'test/parallel/test-http-createConnection.js', + 'test/parallel/test-http-date-header.js', + 'test/parallel/test-http-default-encoding.js', + 'test/parallel/test-http-default-port.js', + 'test/parallel/test-http-destroyed-socket-write2.js', + 'test/parallel/test-http-dns-error.js', + 'test/parallel/test-http-double-content-length.js', + 'test/parallel/test-http-eof-on-connect.js', + 'test/parallel/test-http-expect-continue.js', + 'test/parallel/test-http-expect-handling.js', + 'test/parallel/test-http-extra-response.js', + 'test/parallel/test-http-flush-headers.js', + 'test/parallel/test-http-flush.js', + 'test/parallel/test-http-flush-response-headers.js', + 'test/parallel/test-http-full-response.js', + 'test/parallel/test-http-get-pipeline-problem.js', + 'test/parallel/test-http-header-obstext.js', + 'test/parallel/test-http-header-read.js', + 'test/parallel/test-http-head-request.js', + 'test/parallel/test-http-head-response-has-no-body-end.js', + 'test/parallel/test-http-head-response-has-no-body.js', + 'test/parallel/test-http-hex-write.js', + 'test/parallel/test-http-host-header-ipv6-fail.js', + 'test/parallel/test-http-host-headers.js', + 'test/parallel/test-http-hostname-typechecking.js', + 'test/parallel/test-http-incoming-matchKnownFields.js', + 'test/parallel/test-http-incoming-pipelined-socket-destroy.js', + 'test/parallel/test-http-invalidheaderfield2.js', + 'test/parallel/test-http-invalidheaderfield.js', + 'test/parallel/test-http-invalid-path-chars.js', + 'test/parallel/test-http-invalid-urls.js', + 'test/parallel/test-http-keepalive-client.js', + 'test/parallel/test-http-keep-alive-close-on-header.js', + 'test/parallel/test-http-keep-alive.js', + 'test/parallel/test-http-keepalive-maxsockets.js', + 'test/parallel/test-http-keepalive-override.js', + 'test/parallel/test-http-keepalive-request.js', + 'test/parallel/test-http-listening.js', + 'test/parallel/test-http-localaddress-bind-error.js', + 'test/parallel/test-http-localaddress.js', + 'test/parallel/test-http-malformed-request.js', + 'test/parallel/test-http-max-headers-count.js', + 'test/parallel/test-http-methods.js', + 'test/parallel/test-http-multi-line-headers.js', + 'test/parallel/test-http-mutable-headers.js', + 'test/parallel/test-http-no-content-length.js', + 'test/parallel/test-http-no-read-no-dump.js', + 'test/parallel/test-http-outgoing-finish.js', + 'test/parallel/test-http-outgoing-finish-writable.js', + 'test/parallel/test-http-outgoing-first-chunk-singlebyte-encoding.js', + 'test/parallel/test-http-outgoing-message-inheritance.js', + 'test/parallel/test-http-outgoing-proto.js', + 'test/parallel/test-http-parser-free.js', + 'test/parallel/test-http-parser.js', + 'test/parallel/test-http-pause.js', + 'test/parallel/test-http-pause-resume-one-end.js', + 'test/parallel/test-http-pipe-fs.js', + 'test/parallel/test-http-pipeline-flood.js', + 'test/parallel/test-http-pipeline-regr-2639.js', + 'test/parallel/test-http-pipeline-regr-3332.js', + 'test/parallel/test-http-pipeline-regr-3508.js', + 'test/parallel/test-http-proxy.js', + 'test/parallel/test-http-raw-headers.js', + 'test/parallel/test-http-regr-gh-2821.js', + 'test/parallel/test-http-remove-header-stays-removed.js', + 'test/parallel/test-http-request-dont-override-options.js', + 'test/parallel/test-http-request-end.js', + 'test/parallel/test-http-request-end-twice.js', + 'test/parallel/test-http-request-invalid-method-error.js', + 'test/parallel/test-http-request-methods.js', + 'test/parallel/test-http-response-add-header-after-sent.js', + 'test/parallel/test-http-response-close.js', + 'test/parallel/test-http-response-multi-content-length.js', + 'test/parallel/test-http-response-multiheaders.js', + 'test/parallel/test-http-response-no-headers.js', + 'test/parallel/test-http-response-readable.js', + 'test/parallel/test-http-response-remove-header-after-sent.js', + 'test/parallel/test-http-response-splitting.js', + 'test/parallel/test-http-response-statuscode.js', + 'test/parallel/test-http-response-status-message.js', + 'test/parallel/test-http-res-write-after-end.js', + 'test/parallel/test-http-res-write-end-dont-take-array.js', + 'test/parallel/test-http-server-client-error.js', + 'test/parallel/test-http-server-de-chunked-trailer.js', + 'test/parallel/test-http-server.js', + 'test/parallel/test-http-server-keep-alive-timeout.js', + 'test/parallel/test-http-server-multiheaders2.js', + 'test/parallel/test-http-server-multiheaders.js', + 'test/parallel/test-http-server-reject-chunked-with-content-length.js', + 'test/parallel/test-http-server-reject-cr-no-lf.js', + 'test/parallel/test-http-server-response-standalone.js', + 'test/parallel/test-http-server-stale-close.js', + 'test/parallel/test-http-server-unconsume-consume.js', + 'test/parallel/test-http-server-unconsume.js', + 'test/parallel/test-http-server-write-after-end.js', + 'test/parallel/test-http-set-cookies.js', + 'test/parallel/test-http-set-timeout.js', + 'test/parallel/test-http-set-timeout-server.js', + 'test/parallel/test-http-set-trailers.js', + 'test/parallel/test-http-should-keep-alive.js', + 'test/parallel/test-http-status-code.js', + 'test/parallel/test-http-status-message.js', + 'test/parallel/test-http-status-reason-invalid-chars.js', + 'test/parallel/test-http-timeout.js', + 'test/parallel/test-http-timeout-overflow.js', + 'test/parallel/test-http-unix-socket.js', + 'test/parallel/test-http-unix-socket-keep-alive.js', + 'test/parallel/test-http-upgrade-advertise.js', + 'test/parallel/test-http-upgrade-agent.js', + 'test/parallel/test-http-upgrade-client2.js', + 'test/parallel/test-http-upgrade-client.js', + 'test/parallel/test-http-upgrade-reconsume-stream.js', + 'test/parallel/test-http-upgrade-server.js', + 'test/parallel/test-http-url.parse-auth.js', + 'test/parallel/test-http-url.parse-auth-with-header-in-request.js', + 'test/parallel/test-http-url.parse-basic.js', + 'test/parallel/test-http-url.parse-https.request.js', + 'test/parallel/test-http-url.parse-only-support-http-https-protocol.js', + 'test/parallel/test-http-url.parse-path.js', + 'test/parallel/test-http-url.parse-post.js', + 'test/parallel/test-http-url.parse-search.js', + 'test/parallel/test-http-wget.js', + 'test/parallel/test-http-write-callbacks.js', + 'test/parallel/test-http-write-empty-string.js', + 'test/parallel/test-http-write-head.js', + 'test/parallel/test-http-zero-length-write.js' +]); diff --git a/test/workers/test-http2.js b/test/workers/test-http2.js new file mode 100644 index 0000000000..52e19fc34b --- /dev/null +++ b/test/workers/test-http2.js @@ -0,0 +1,136 @@ +/* eslint-disable max-len */ +'use strict'; +require('../common'); + +require('./index.js').runTestsInsideWorker([ + 'test/parallel/test-http2-binding.js', + 'test/parallel/test-http2-client-data-end.js', + 'test/parallel/test-http2-client-destroy.js', + 'test/parallel/test-http2-client-onconnect-errors.js', + 'test/parallel/test-http2-client-priority-before-connect.js', + 'test/parallel/test-http2-client-promisify-connect.js', + 'test/parallel/test-http2-client-request-options-errors.js', + 'test/parallel/test-http2-client-rststream-before-connect.js', + 'test/parallel/test-http2-client-set-priority.js', + 'test/parallel/test-http2-client-settings-before-connect.js', + 'test/parallel/test-http2-client-settings-errors.js', + 'test/parallel/test-http2-client-shutdown-before-connect.js', + 'test/parallel/test-http2-client-socket-destroy.js', + 'test/parallel/test-http2-client-stream-destroy-before-connect.js', + 'test/parallel/test-http2-client-unescaped-path.js', + 'test/parallel/test-http2-client-upload.js', + 'test/parallel/test-http2-client-write-before-connect.js', + 'test/parallel/test-http2-compat-expect-continue-check.js', + 'test/parallel/test-http2-compat-expect-continue.js', + 'test/parallel/test-http2-compat-expect-handling.js', + 'test/parallel/test-http2-compat-method-connect.js', + 'test/parallel/test-http2-compat-serverrequest-end.js', + 'test/parallel/test-http2-compat-serverrequest-headers.js', + 'test/parallel/test-http2-compat-serverrequest.js', + 'test/parallel/test-http2-compat-serverrequest-pause.js', + 'test/parallel/test-http2-compat-serverrequest-pipe.js', + 'test/parallel/test-http2-compat-serverrequest-settimeout.js', + 'test/parallel/test-http2-compat-serverrequest-trailers.js', + 'test/parallel/test-http2-compat-serverresponse-close.js', + 'test/parallel/test-http2-compat-serverresponse-createpushresponse.js', + 'test/parallel/test-http2-compat-serverresponse-destroy.js', + 'test/parallel/test-http2-compat-serverresponse-drain.js', + 'test/parallel/test-http2-compat-serverresponse-end.js', + 'test/parallel/test-http2-compat-serverresponse-finished.js', + 'test/parallel/test-http2-compat-serverresponse-flushheaders.js', + 'test/parallel/test-http2-compat-serverresponse-headers-after-destroy.js', + 'test/parallel/test-http2-compat-serverresponse-headers.js', + 'test/parallel/test-http2-compat-serverresponse-settimeout.js', + 'test/parallel/test-http2-compat-serverresponse-statuscode.js', + 'test/parallel/test-http2-compat-serverresponse-statusmessage.js', + 'test/parallel/test-http2-compat-serverresponse-statusmessage-property.js', + 'test/parallel/test-http2-compat-serverresponse-statusmessage-property-set.js', + 'test/parallel/test-http2-compat-serverresponse-trailers.js', + 'test/parallel/test-http2-compat-serverresponse-writehead.js', + 'test/parallel/test-http2-compat-serverresponse-write-no-cb.js', + 'test/parallel/test-http2-compat-socket.js', + 'test/parallel/test-http2-compat-socket-set.js', + 'test/parallel/test-http2-connect.js', + 'test/parallel/test-http2-connect-method.js', + 'test/parallel/test-http2-cookies.js', + 'test/parallel/test-http2-create-client-connect.js', + 'test/parallel/test-http2-create-client-secure-session.js', + 'test/parallel/test-http2-create-client-session.js', + 'test/parallel/test-http2-createsecureserver-nooptions.js', + 'test/parallel/test-http2-createwritereq.js', + 'test/parallel/test-http2-date-header.js', + 'test/parallel/test-http2-dont-override.js', + 'test/parallel/test-http2-getpackedsettings.js', + 'test/parallel/test-http2-goaway-opaquedata.js', + 'test/parallel/test-http2-head-request.js', + 'test/parallel/test-http2-https-fallback.js', + 'test/parallel/test-http2-info-headers-errors.js', + 'test/parallel/test-http2-info-headers.js', + 'test/parallel/test-http2-invalidargtypes-errors.js', + 'test/parallel/test-http2-max-concurrent-streams.js', + 'test/parallel/test-http2-methods.js', + 'test/parallel/test-http2-misused-pseudoheaders.js', + 'test/parallel/test-http2-multi-content-length.js', + 'test/parallel/test-http2-multiheaders.js', + 'test/parallel/test-http2-multiheaders-raw.js', + 'test/parallel/test-http2-multiplex.js', + 'test/parallel/test-http2-options-max-headers-block-length.js', + 'test/parallel/test-http2-options-max-reserved-streams.js', + 'test/parallel/test-http2-padding-callback.js', + 'test/parallel/test-http2-priority-errors.js', + 'test/parallel/test-http2-priority-event.js', + 'test/parallel/test-http2-priority-parent-self.js', + 'test/parallel/test-http2-request-response-proto.js', + 'test/parallel/test-http2-respond-errors.js', + 'test/parallel/test-http2-respond-file-204.js', + 'test/parallel/test-http2-respond-file-304.js', + 'test/parallel/test-http2-respond-file-404.js', + 'test/parallel/test-http2-respond-file-compat.js', + 'test/parallel/test-http2-respond-file-error-dir.js', + 'test/parallel/test-http2-respond-file-errors.js', + 'test/parallel/test-http2-respond-file-fd-errors.js', + 'test/parallel/test-http2-respond-file-fd-invalid.js', + 'test/parallel/test-http2-respond-file-fd.js', + 'test/parallel/test-http2-respond-file-fd-range.js', + 'test/parallel/test-http2-respond-file.js', + 'test/parallel/test-http2-respond-file-push.js', + 'test/parallel/test-http2-respond-file-range.js', + 'test/parallel/test-http2-respond-no-data.js', + 'test/parallel/test-http2-respond-with-fd-errors.js', + 'test/parallel/test-http2-response-splitting.js', + 'test/parallel/test-http2-rststream-errors.js', + 'test/parallel/test-http2-serve-file.js', + 'test/parallel/test-http2-server-push-disabled.js', + 'test/parallel/test-http2-server-push-stream-errors-args.js', + 'test/parallel/test-http2-server-push-stream-errors.js', + 'test/parallel/test-http2-server-push-stream-head.js', + 'test/parallel/test-http2-server-push-stream.js', + 'test/parallel/test-http2-server-rst-before-respond.js', + 'test/parallel/test-http2-server-rst-stream.js', + 'test/parallel/test-http2-server-set-header.js', + 'test/parallel/test-http2-server-settimeout-no-callback.js', + 'test/parallel/test-http2-server-shutdown-before-respond.js', + 'test/parallel/test-http2-server-shutdown-options-errors.js', + 'test/parallel/test-http2-server-shutdown-redundant.js', + 'test/parallel/test-http2-server-socket-destroy.js', + 'test/parallel/test-http2-server-socketerror.js', + 'test/parallel/test-http2-server-startup.js', + 'test/parallel/test-http2-server-stream-session-destroy.js', + 'test/parallel/test-http2-server-timeout.js', + 'test/parallel/test-http2-session-settings.js', + 'test/parallel/test-http2-session-stream-state.js', + 'test/parallel/test-http2-shutdown-errors.js', + 'test/parallel/test-http2-single-headers.js', + 'test/parallel/test-http2-status-code-invalid.js', + 'test/parallel/test-http2-status-code.js', + 'test/parallel/test-http2-stream-client.js', + 'test/parallel/test-http2-stream-destroy-event-order.js', + 'test/parallel/test-http2-timeouts.js', + 'test/parallel/test-http2-too-many-settings.js', + 'test/parallel/test-http2-trailers.js', + 'test/parallel/test-http2-window-size.js', + 'test/parallel/test-http2-withflag.js', + 'test/parallel/test-http2-write-callbacks.js', + 'test/parallel/test-http2-write-empty-string.js', + 'test/parallel/test-http2-zero-length-write.js' +]); diff --git a/test/workers/test-process.js b/test/workers/test-process.js new file mode 100644 index 0000000000..19cb8f39d8 --- /dev/null +++ b/test/workers/test-process.js @@ -0,0 +1,35 @@ +'use strict'; + +require('../common'); + +require('./index.js').runTestsInsideWorker([ + 'test/parallel/test-process-argv-0.js', + 'test/parallel/test-process-assert.js', + 'test/parallel/test-process-beforeexit.js', + 'test/parallel/test-process-binding.js', + 'test/parallel/test-process-config.js', + 'test/parallel/test-process-constants-noatime.js', + 'test/parallel/test-process-cpuUsage.js', + 'test/parallel/test-process-emit.js', + 'test/parallel/test-process-exec-argv.js', + 'test/parallel/test-process-execpath.js', + 'test/parallel/test-process-exit-code.js', + 'test/parallel/test-process-exit-from-before-exit.js', + 'test/parallel/test-process-exit.js', + 'test/parallel/test-process-exit-recursive.js', + 'test/parallel/test-process-external-stdio-close.js', + 'test/parallel/test-process-external-stdio-close-spawn.js', + 'test/parallel/test-process-getactivehandles.js', + 'test/parallel/test-process-getactiverequests.js', + 'test/parallel/test-process-hrtime.js', + 'test/parallel/test-process-kill-null.js', + 'test/parallel/test-process-kill-pid.js', + 'test/parallel/test-process-no-deprecation.js', + 'test/parallel/test-process-prototype.js', + 'test/parallel/test-process-raw-debug.js', + 'test/parallel/test-process-redirect-warnings-env.js', + 'test/parallel/test-process-redirect-warnings.js', + 'test/parallel/test-process-remove-all-signal-listeners.js', + 'test/parallel/test-process-versions.js', + 'test/parallel/test-process-wrap.js' +]); diff --git a/test/workers/test-stream.js b/test/workers/test-stream.js new file mode 100644 index 0000000000..325fd0b984 --- /dev/null +++ b/test/workers/test-stream.js @@ -0,0 +1,96 @@ +'use strict'; + +require('../common'); + +require('./index.js').runTestsInsideWorker([ + 'test/parallel/test-stream2-base64-single-char-read-end.js', + 'test/parallel/test-stream2-basic.js', + 'test/parallel/test-stream2-compatibility.js', + 'test/parallel/test-stream2-decode-partial.js', + 'test/parallel/test-stream2-finish-pipe.js', + 'test/parallel/test-stream2-httpclient-response-end.js', + 'test/parallel/test-stream2-large-read-stall.js', + 'test/parallel/test-stream2-objects.js', + 'test/parallel/test-stream2-pipe-error-handling.js', + 'test/parallel/test-stream2-pipe-error-once-listener.js', + 'test/parallel/test-stream2-push.js', + 'test/parallel/test-stream2-readable-empty-buffer-no-eof.js', + 'test/parallel/test-stream2-readable-legacy-drain.js', + 'test/parallel/test-stream2-readable-non-empty-end.js', + 'test/parallel/test-stream2-readable-wrap-empty.js', + 'test/parallel/test-stream2-readable-wrap.js', + 'test/parallel/test-stream2-read-sync-stack.js', + 'test/parallel/test-stream2-set-encoding.js', + 'test/parallel/test-stream2-transform.js', + 'test/parallel/test-stream2-unpipe-drain.js', + 'test/parallel/test-stream2-unpipe-leak.js', + 'test/parallel/test-stream3-cork-end.js', + 'test/parallel/test-stream3-cork-uncork.js', + 'test/parallel/test-stream3-pause-then-read.js', + 'test/parallel/test-stream-base-typechecking.js', + 'test/parallel/test-stream-big-packet.js', + 'test/parallel/test-stream-big-push.js', + 'test/parallel/test-stream-decoder-objectmode.js', + 'test/parallel/test-stream-duplex-destroy.js', + 'test/parallel/test-stream-duplex.js', + 'test/parallel/test-stream-end-paused.js', + 'test/parallel/test-stream-events-prepend.js', + 'test/parallel/test-stream-inheritance.js', + 'test/parallel/test-stream-ispaused.js', + 'test/parallel/test-stream-objectmode-undefined.js', + 'test/parallel/test-stream-pipe-after-end.js', + 'test/parallel/test-stream-pipe-await-drain.js', + 'test/parallel/test-stream-pipe-await-drain-manual-resume.js', + 'test/parallel/test-stream-pipe-await-drain-push-while-write.js', + 'test/parallel/test-stream-pipe-cleanup.js', + 'test/parallel/test-stream-pipe-cleanup-pause.js', + 'test/parallel/test-stream-pipe-error-handling.js', + 'test/parallel/test-stream-pipe-event.js', + 'test/parallel/test-stream-pipe-multiple-pipes.js', + 'test/parallel/test-stream-pipe-same-destination-twice.js', + 'test/parallel/test-stream-pipe-unpipe-streams.js', + 'test/parallel/test-stream-pipe-without-listenerCount.js', + 'test/parallel/test-stream-preprocess.js', + 'test/parallel/test-stream-push-order.js', + 'test/parallel/test-stream-push-strings.js', + 'test/parallel/test-stream-readable-constructor-set-methods.js', + 'test/parallel/test-stream-readable-destroy.js', + 'test/parallel/test-stream-readable-emittedReadable.js', + 'test/parallel/test-stream-readable-event.js', + 'test/parallel/test-stream-readable-flow-recursion.js', + 'test/parallel/test-stream-readable-invalid-chunk.js', + 'test/parallel/test-stream-readableListening-state.js', + 'test/parallel/test-stream-readable-needReadable.js', + 'test/parallel/test-stream-readable-reading-readingMore.js', + 'test/parallel/test-stream-readable-resumeScheduled.js', + 'test/parallel/test-stream-readable-with-unimplemented-_read.js', + 'test/parallel/test-streams-highwatermark.js', + 'test/parallel/test-stream-transform-callback-twice.js', + 'test/parallel/test-stream-transform-constructor-set-methods.js', + 'test/parallel/test-stream-transform-destroy.js', + 'test/parallel/test-stream-transform-final.js', + 'test/parallel/test-stream-transform-final-sync.js', + 'test/parallel/test-stream-transform-flush-data.js', + 'test/parallel/test-stream-transform-objectmode-falsey-value.js', + 'test/parallel/test-stream-transform-split-highwatermark.js', + 'test/parallel/test-stream-transform-split-objectmode.js', + 'test/parallel/test-stream-uint8array.js', + 'test/parallel/test-stream-unpipe-event.js', + 'test/parallel/test-stream-unshift-empty-chunk.js', + 'test/parallel/test-stream-unshift-read-race.js', + 'test/parallel/test-stream-wrap-encoding.js', + 'test/parallel/test-stream-wrap.js', + 'test/parallel/test-stream-writable-change-default-encoding.js', + 'test/parallel/test-stream-writable-constructor-set-methods.js', + 'test/parallel/test-stream-writable-decoded-encoding.js', + 'test/parallel/test-stream-writable-destroy.js', + 'test/parallel/test-stream-writable-ended-state.js', + 'test/parallel/test-stream-writable-finished-state.js', + 'test/parallel/test-stream-writable-needdrain-state.js', + 'test/parallel/test-stream-writable-null.js', + 'test/parallel/test-stream-writableState-ending.js', + 'test/parallel/test-stream-writableState-uncorked-bufferedRequestCount.js', + 'test/parallel/test-stream-writable-write-writev-finish.js', + 'test/parallel/test-stream-write-final.js', + 'test/parallel/test-stream-writev.js' +]); diff --git a/test/workers/test-vm.js b/test/workers/test-vm.js new file mode 100644 index 0000000000..22bed99412 --- /dev/null +++ b/test/workers/test-vm.js @@ -0,0 +1,38 @@ +'use strict'; +require('../common'); + +require('./index.js').runTestsInsideWorker([ + 'test/parallel/test-vm-basic.js', + 'test/parallel/test-vm-cached-data.js', + 'test/parallel/test-vm-context-async-script.js', + 'test/parallel/test-vm-context.js', + 'test/parallel/test-vm-context-property-forwarding.js', + 'test/parallel/test-vm-create-context-accessors.js', + 'test/parallel/test-vm-create-context-arg.js', + 'test/parallel/test-vm-create-context-circular-reference.js', + 'test/parallel/test-vm-cross-context.js', + 'test/parallel/test-vm-debug-context.js', + 'test/parallel/test-vm-deleting-property.js', + 'test/parallel/test-vm-function-declaration.js', + 'test/parallel/test-vm-function-redefinition.js', + 'test/parallel/test-vm-global-assignment.js', + 'test/parallel/test-vm-global-define-property.js', + 'test/parallel/test-vm-global-identity.js', + 'test/parallel/test-vm-harmony-symbols.js', + 'test/parallel/test-vm-indexed-properties.js', + 'test/parallel/test-vm-is-context.js', + 'test/parallel/test-vm-low-stack-space.js', + 'test/parallel/test-vm-new-script-new-context.js', + 'test/parallel/test-vm-new-script-this-context.js', + 'test/parallel/test-vm-preserves-property.js', + 'test/parallel/test-vm-property-not-on-sandbox.js', + 'test/parallel/test-vm-proxies.js', + 'test/parallel/test-vm-sigint-existing-handler.js', + 'test/parallel/test-vm-sigint.js', + 'test/parallel/test-vm-static-this.js', + 'test/parallel/test-vm-strict-mode.js', + 'test/parallel/test-vm-symbols.js', + 'test/parallel/test-vm-syntax-error-message.js', + 'test/parallel/test-vm-syntax-error-stderr.js', + 'test/parallel/test-vm-timeout.js' +]); diff --git a/test/workers/test-zlib.js b/test/workers/test-zlib.js new file mode 100644 index 0000000000..00aa0ca98e --- /dev/null +++ b/test/workers/test-zlib.js @@ -0,0 +1,38 @@ +'use strict'; + +require('../common'); + +require('./index.js').runTestsInsideWorker([ + 'test/parallel/test-zlib-bytes-read.js', + 'test/parallel/test-zlib-close-after-error.js', + 'test/parallel/test-zlib-close-after-write.js', + 'test/parallel/test-zlib-const.js', + 'test/parallel/test-zlib-convenience-methods.js', + 'test/parallel/test-zlib-create-raw.js', + 'test/parallel/test-zlib-deflate-constructors.js', + 'test/parallel/test-zlib-deflate-raw-inherits.js', + 'test/parallel/test-zlib-destroy-pipe.js', + 'test/parallel/test-zlib-dictionary-fail.js', + 'test/parallel/test-zlib-dictionary.js', + 'test/parallel/test-zlib-failed-init.js', + 'test/parallel/test-zlib-flush-drain.js', + 'test/parallel/test-zlib-flush-drain-longblock.js', + 'test/parallel/test-zlib-flush-flags.js', + 'test/parallel/test-zlib-flush.js', + 'test/parallel/test-zlib-flush-multiple-scheduled.js', + 'test/parallel/test-zlib-from-concatenated-gzip.js', + 'test/parallel/test-zlib-from-gzip.js', + 'test/parallel/test-zlib-from-gzip-with-trailing-garbage.js', + 'test/parallel/test-zlib-from-string.js', + 'test/parallel/test-zlib-invalid-input.js', + 'test/parallel/test-zlib.js', + 'test/parallel/test-zlib-not-string-or-buffer.js', + 'test/parallel/test-zlib-params.js', + 'test/parallel/test-zlib-random-byte-pipes.js', + 'test/parallel/test-zlib-sync-no-event.js', + 'test/parallel/test-zlib-truncated.js', + 'test/parallel/test-zlib-unzip-one-byte-chunks.js', + 'test/parallel/test-zlib-write-after-close.js', + 'test/parallel/test-zlib-write-after-flush.js', + 'test/parallel/test-zlib-zero-byte.js' +]); diff --git a/test/workers/testcfg.py b/test/workers/testcfg.py new file mode 100644 index 0000000000..9b0ca8a043 --- /dev/null +++ b/test/workers/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, 'workers')