Skip to content
This repository has been archived by the owner on Aug 31, 2018. It is now read-only.

Commit

Permalink
test: add more tests for workers
Browse files Browse the repository at this point in the history
Taken from petkaantonov/io.js@ea143f7
and modified to fit current linter rules and coding style.
  • Loading branch information
petkaantonov authored and addaleax committed Sep 5, 2017
1 parent eb3cbac commit 155c764
Show file tree
Hide file tree
Showing 21 changed files with 673 additions and 4 deletions.
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ test-all-valgrind: test-build
$(PYTHON) tools/test.py --mode=debug,release --valgrind

CI_NATIVE_SUITES := addons addons-napi
CI_JS_SUITES := abort async-hooks doctool inspector known_issues message parallel pseudo-tty sequential
CI_JS_SUITES := abort async-hooks doctool inspector known_issues message parallel pseudo-tty sequential workers

# Build and test addons without building anything else
test-ci-native: LOGLEVEL := silent
Expand Down Expand Up @@ -439,6 +439,9 @@ test-timers-clean:
test-async-hooks:
$(PYTHON) tools/test.py --mode=release async-hooks

test-worker:
$(PYTHON) tools/test.py --mode=release workers


ifneq ("","$(wildcard deps/v8/tools/run-tests.py)")
test-v8: v8
Expand Down
10 changes: 7 additions & 3 deletions test/common/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,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}`;
if ((process.workerData && process.workerData.testThreadId) ||
process.env.TEST_THREAD_ID) {
const id = +((process.workerData && process.workerData.testThreadId) ||
process.env.TEST_THREAD_ID);

exports.PORT += id * 100;
exports.tmpDirName += `.${id}`;
}
exports.tmpDir = path.join(testRoot, exports.tmpDirName);

Expand Down
13 changes: 13 additions & 0 deletions test/parallel/test-worker-termination-2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
'use strict';

const common = require('../common');
const { Worker } = require('worker');

if (process.isMainThread) {
const aWorker = new Worker(__filename);
aWorker.terminate(common.mustCall());
aWorker.on('message', common.mustNotCall());
} else {
while (true)
process.postMessage({ hello: 'world' });
}
22 changes: 22 additions & 0 deletions test/parallel/test-worker-termination-3.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
'use strict';

const common = require('../common');
const { Worker } = require('worker');

if (process.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 {
process.on('workerMessage', function() {
while (true)
process.postMessage({ hello: 'world' });
});

process.postMessage();
}
30 changes: 30 additions & 0 deletions test/parallel/test-worker-termination-exit-2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
'use strict';

const common = require('../common');
const assert = require('assert');
const { Worker } = require('worker');

if (process.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() {
process.postMessage({ hello: 'world' });
}, 5000);
setImmediate(function f() {
process.postMessage({ hello: 'world' });
setImmediate(f);
});
process.exit(1337);
});
let emits = 0;
process.on('exit', function() {
process.postMessage(emits++);
});
}
26 changes: 26 additions & 0 deletions test/parallel/test-worker-termination-exit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
'use strict';

const common = require('../common');
const assert = require('assert');
const { Worker } = require('worker');

if (process.isMainThread) {
const aWorker = new Worker(__filename);
aWorker.on('exit', common.mustCall((code) => {
assert.strictEqual(1337, code);
}));
aWorker.on('message', common.mustNotCall());
} else {
setInterval(function() {
process.postMessage({ hello: 'world' });
}, 5000);
setImmediate(function f() {
process.postMessage({ hello: 'world' });
setImmediate(f);
});
(function() {
[1337, 2, 3].map(function(value) {
process.exit(value);
});
})();
}
54 changes: 54 additions & 0 deletions test/parallel/test-worker-termination-grand-parent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
'use strict';

require('../common');
const assert = require('assert');
const { Worker } = require('worker');
const ids = [];

if (process.isMainThread) {
const aWorker = new Worker(__filename);
aWorker.postMessage({
init: true,
subWorker: false
});
aWorker.on('message', function(data) {
ids.push(data.id);
if (ids.length === 4) {
// Terminating the main worker should terminate its 4 sub-workers
aWorker.terminate();
}
});
process.on('beforeExit', function() {
assert.deepStrictEqual([0, 1, 2, 3].sort(), ids.sort());
});
} else {
process.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) {
process.postMessage(payload);
});
}
}

function subWorker(id) {
process.postMessage({ id: id });
while (true);
}
31 changes: 31 additions & 0 deletions test/parallel/test-worker-termination-owner.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
'use strict';

const common = require('../common');
const { Worker } = require('worker');

// Test that termination of a worker that is in the middle of processing
// messages from its sub-worker works.

if (process.isMainThread) {
const worker = new Worker(__filename);
worker.postMessage({ main: true });
worker.on('message', common.mustCall(() => {
worker.terminate();
}));
} else {
process.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)
process.postMessage();
});
} else {
while (true) process.postMessage();
}
});
}
114 changes: 114 additions & 0 deletions test/parallel/test-worker-termination-races.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
'use strict';

const common = require('../common');

if (!common.hasCrypto)
common.skip('missing crypto');

const { Worker } = require('worker');
const MESSAGES_PER_GRAND_CHILD_WORKER = 20;

if (process.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 {
process.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 });
}
});
process.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--) {
process.postMessage({
id: data.id
});
}
}
18 changes: 18 additions & 0 deletions test/parallel/test-worker-termination.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
'use strict';

const common = require('../common');
const { Worker } = require('worker');

if (process.isMainThread) {
const aWorker = new Worker(__filename);
aWorker.terminate(common.mustCall());
aWorker.on('message', common.mustNotCall());
} else {
setInterval(function() {
process.postMessage({ hello: 'world' });
}, 5000);
setImmediate(function f() {
process.postMessage({ hello: 'world' });
setImmediate(f);
});
}
35 changes: 35 additions & 0 deletions test/parallel/test-worker-unref-2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
'use strict';

require('../common');
const assert = require('assert');
const { Worker } = require('worker');
let checks = 0;

if (process.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 {
process.on('workerMessage', function() {
setTimeout(function() {
process.postMessage();
}, 1);
});
}
Loading

0 comments on commit 155c764

Please sign in to comment.