Skip to content

Commit e5630e8

Browse files
authored
Feat: Add public API for workers (#2115)
* Feat: Add public API for workers * Add boostrab and teardown hooks * Refract worker and Add tests * Add tests and Refract worker * Remove node 8 support * Add share API * Add share API review changes
1 parent 5464ae0 commit e5630e8

File tree

13 files changed

+693
-3
lines changed

13 files changed

+693
-3
lines changed

lib/codecept.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ class Codecept {
7676
global.DataTable = require('./data/table');
7777
global.locate = locator => require('./locator').build(locator);
7878
global.inject = container.support;
79+
global.share = container.share;
7980
global.secret = require('./secret').secret;
8081
global.codeceptjs = require('./index'); // load all objects
8182

lib/command/run-workers.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const { tryOrDefault, fileExists } = require('../utils');
1111
const output = require('../output');
1212
const event = require('../event');
1313
const runHook = require('../hooks');
14+
const WorkerStorage = require('../workerStorage');
1415

1516
const stats = {
1617
suites: 0,
@@ -76,14 +77,16 @@ module.exports = function (workers, options) {
7677
function createWorkers(groups, options, testRoot) {
7778
const workers = groups.map((tests, workerIndex) => {
7879
workerIndex++;
79-
return new Worker(pathToWorker, {
80+
const worker = new Worker(pathToWorker, {
8081
workerData: {
8182
options: simplifyObject(options),
8283
tests,
8384
testRoot,
8485
workerIndex,
8586
},
8687
});
88+
WorkerStorage.addWorker(worker);
89+
return worker;
8790
});
8891

8992
return workers;

lib/command/workers/runTests.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const event = require('../../event');
1414
const output = require('../../output');
1515
const container = require('../../container');
1616
const { getConfig, getTestRoot } = require('../utils');
17+
const { tryOrDefault } = require('../../utils');
1718

1819
let stdout = '';
1920
const stderr = '';
@@ -29,7 +30,13 @@ const {
2930
// hide worker output
3031
if (!options.debug && !options.verbose) process.stdout.write = (string, encoding, fd) => { stdout += string; return true; };
3132

32-
const config = getConfig(options.config || testRoot);
33+
34+
const overrideConfigs = tryOrDefault(() => JSON.parse(options.override), {});
35+
36+
const config = {
37+
...getConfig(options.config || testRoot),
38+
...overrideConfigs,
39+
};
3340

3441
// Load test and run
3542
const codecept = new Codecept(config, options);
@@ -40,6 +47,7 @@ filterTests();
4047
if (mocha.suite.total()) {
4148
codecept.runBootstrap((err) => {
4249
if (err) throw new Error(`Error while running bootstrap file :${err}`);
50+
listenToParentThread();
4351
initializeListeners();
4452
disablePause();
4553
codecept.run();
@@ -139,3 +147,9 @@ function collectStats() {
139147
function sendToParentThread(data) {
140148
parentPort.postMessage(data);
141149
}
150+
151+
function listenToParentThread() {
152+
parentPort.on('message', (eventData) => {
153+
container.append({ support: eventData.data });
154+
});
155+
}

lib/container.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
const glob = require('glob');
22
const path = require('path');
3-
43
const fileExists = require('./utils').fileExists;
54
const Translation = require('./translation');
65
const MochaFactory = require('./mochaFactory');
76
const recorder = require('./recorder');
87
const event = require('./event');
8+
const WorkerStorage = require('./workerStorage');
9+
910

1011
let container = {
1112
helpers: {},
@@ -129,6 +130,19 @@ class Container {
129130
container.plugins = newPlugins || {};
130131
container.translation = loadTranslation();
131132
}
133+
134+
/**
135+
* Share data across worker threads
136+
*
137+
* @param {Object} data
138+
* @param {Object} options - set {local: true} to not share among workers
139+
*/
140+
static share(data, options = {}) {
141+
Container.append({ support: data });
142+
if (!options.local) {
143+
WorkerStorage.share(data);
144+
}
145+
}
132146
}
133147

134148
module.exports = Container;

lib/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,6 @@ module.exports = {
3636
store: require('./store'),
3737
/** @type {typeof CodeceptJS.Locator} */
3838
locator: require('./locator'),
39+
40+
Workers: require('./workers'),
3941
};

lib/workerStorage.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
const { isMainThread, parentPort } = require('worker_threads');
2+
3+
const workerObjects = {};
4+
const shareEvent = 'share';
5+
6+
const invokeWorkerListeners = (workerObj) => {
7+
const { threadId } = workerObj;
8+
workerObj.on('message', (messageData) => {
9+
if (messageData.event === shareEvent) {
10+
share(messageData.data);
11+
}
12+
});
13+
workerObj.on('exit', () => {
14+
delete workerObjects[threadId];
15+
});
16+
};
17+
18+
class WorkerStorage {
19+
/**
20+
* Add worker object
21+
*
22+
* @api
23+
* @param {Worker} workerObj
24+
*/
25+
static addWorker(workerObj) {
26+
workerObjects[workerObj.threadId] = workerObj;
27+
invokeWorkerListeners(workerObj);
28+
}
29+
30+
/**
31+
* Share data across workers
32+
*
33+
* @param {*} data
34+
*/
35+
static share(data) {
36+
if (isMainThread) {
37+
for (const workerObj of Object.values(workerObjects)) {
38+
workerObj.postMessage({ data });
39+
}
40+
} else {
41+
parentPort.postMessage({ data, event: shareEvent });
42+
}
43+
}
44+
}
45+
46+
module.exports = WorkerStorage;

0 commit comments

Comments
 (0)