Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
novemberborn committed May 8, 2020
1 parent c07ae45 commit 5a01bf5
Show file tree
Hide file tree
Showing 23 changed files with 885 additions and 35 deletions.
2 changes: 2 additions & 0 deletions lib/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const RunStatus = require('./run-status');
const fork = require('./fork');
const serializeError = require('./serialize-error');
const {getApplicableLineNumbers} = require('./line-numbers');
const sharedWorkers = require('./shared-workers');

function resolveModules(modules) {
return arrify(modules).map(name => {
Expand Down Expand Up @@ -231,6 +232,7 @@ class Api extends Emittery {

const worker = fork(file, options, apiOptions.nodeArguments);
runStatus.observeWorker(worker, file, {selectingLines: lineNumbers.length > 0});
sharedWorkers.observeWorkerProcess(worker, runStatus);

pendingWorkers.add(worker);
worker.promise.then(() => {
Expand Down
98 changes: 81 additions & 17 deletions lib/fork.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,57 @@ if (fs.realpathSync(__filename) !== __filename) {
// In case the test file imports a different AVA install,
// the presence of this variable allows it to require this one instead
const AVA_PATH = path.resolve(__dirname, '..');
const WORKER_PATH = require.resolve('./worker/subprocess');

class SharedWorkerChannel extends Emittery {
constructor({channelId, filename, initialData}, sendToFork) {
super();

this.id = channelId;
this.filename = filename;
this.initialData = initialData;
this.sendToFork = sendToFork;
}

signalReady() {
this.sendToFork({
type: 'shared-worker-ready',
channelId: this.id
});
}

signalError() {
this.sendToFork({
type: 'shared-worker-error',
channelId: this.id
});
}

const workerPath = require.resolve('./worker/subprocess');
emitMessage({messageId, replyTo, data}) {
this.emit('message', {
messageId,
replyTo,
data
});
}

forwardMessageToFork({messageId, replyTo, data}) {
this.sendToFork({
type: 'shared-worker-message',
channelId: this.id,
messageId,
replyTo,
data
});
}
}

let forkCounter = 0;

module.exports = (file, options, execArgv = process.execArgv) => {
const forkId = `fork/${++forkCounter}`;
const sharedWorkerChannels = new Map();

let finished = false;

const emitter = new Emittery();
Expand All @@ -25,16 +72,18 @@ module.exports = (file, options, execArgv = process.execArgv) => {
};

options = {
file,
baseDir: process.cwd(),
file,
forkId,
...options
};

const subprocess = childProcess.fork(workerPath, options.workerArgv, {
const subprocess = childProcess.fork(WORKER_PATH, options.workerArgv, {
cwd: options.projectDir,
silent: true,
env: {NODE_ENV: 'test', ...process.env, ...options.environmentVariables, AVA_PATH},
execArgv
execArgv,
serialization: process.versions.node >= '12.16.0' ? 'advanced' : 'json'
});

subprocess.stdout.on('data', chunk => {
Expand Down Expand Up @@ -65,15 +114,25 @@ module.exports = (file, options, execArgv = process.execArgv) => {
return;
}

if (message.ava.type === 'ready-for-options') {
send({type: 'options', options});
return;
}

if (message.ava.type === 'ping') {
send({type: 'pong'});
} else {
emitStateChange(message.ava);
switch (message.ava.type) {
case 'ready-for-options':
send({type: 'options', options});
break;
case 'shared-worker-connect': {
const channel = new SharedWorkerChannel(message.ava, send);
sharedWorkerChannels.set(channel.id, channel);
emitter.emit('connectSharedWorker', channel);
break;
}

case 'shared-worker-message':
sharedWorkerChannels.get(message.ava.channelId).emitMessage(message.ava);
break;
case 'ping':
send({type: 'pong'});
break;
default:
emitStateChange(message.ava);
}
});

Expand All @@ -98,6 +157,10 @@ module.exports = (file, options, execArgv = process.execArgv) => {
});

return {
file,
forkId,
promise,

exit() {
forcedExit = true;
subprocess.kill();
Expand All @@ -107,11 +170,12 @@ module.exports = (file, options, execArgv = process.execArgv) => {
send({type: 'peer-failed'});
},

onStateChange(listener) {
return emitter.on('stateChange', listener);
onConnectSharedWorker(listener) {
return emitter.on('connectSharedWorker', listener);
},

file,
promise
onStateChange(listener) {
return emitter.on('stateChange', listener);
}
};
};
34 changes: 30 additions & 4 deletions lib/reporters/mini.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ class MiniReporter {
this.prefixTitle = (testFile, title) => title;
this.previousFailures = 0;
this.removePreviousListener = null;
this.sharedWorkerErrors = [];
this.stats = null;
this.uncaughtExceptions = [];
this.unhandledRejections = [];
Expand Down Expand Up @@ -180,6 +181,9 @@ class MiniReporter {
case 'selected-test':
// Ignore
break;
case 'shared-worker-error':
this.sharedWorkerErrors.push(evt);
break;
case 'stats':
this.stats = evt.stats;
break;
Expand Down Expand Up @@ -511,7 +515,7 @@ class MiniReporter {
const shouldWriteFailFastDisclaimer = this.failFastEnabled && (this.stats.remainingTests > 0 || this.stats.files > this.stats.finishedWorkers);

if (this.failures.length > 0) {
const writeTrailingLines = shouldWriteFailFastDisclaimer || this.internalErrors.length > 0 || this.uncaughtExceptions.length > 0 || this.unhandledRejections.length > 0;
const writeTrailingLines = shouldWriteFailFastDisclaimer || this.internalErrors.length > 0 || this.sharedWorkerErrors.length > 0 || this.uncaughtExceptions.length > 0 || this.unhandledRejections.length > 0;
this.lineWriter.writeLine();

const last = this.failures[this.failures.length - 1];
Expand All @@ -527,7 +531,7 @@ class MiniReporter {

if (this.internalErrors.length > 0) {
const writeLeadingLine = this.failures.length === 0;
const writeTrailingLines = shouldWriteFailFastDisclaimer || this.uncaughtExceptions.length > 0 || this.unhandledRejections.length > 0;
const writeTrailingLines = shouldWriteFailFastDisclaimer || this.sharedWorkerErrors.length > 0 || this.uncaughtExceptions.length > 0 || this.unhandledRejections.length > 0;

if (writeLeadingLine) {
this.lineWriter.writeLine();
Expand All @@ -551,8 +555,30 @@ class MiniReporter {
}
}

if (this.uncaughtExceptions.length > 0) {
if (this.sharedWorkerErrors.length > 0) {
const writeLeadingLine = this.failures.length === 0 && this.internalErrors.length === 0;
const writeTrailingLines = shouldWriteFailFastDisclaimer || this.uncaughtExceptions.length > 0 || this.unhandledRejections.length > 0;

if (writeLeadingLine) {
this.lineWriter.writeLine();
}

const last = this.sharedWorkerErrors[this.sharedWorkerErrors.length - 1];
for (const evt of this.sharedWorkerErrors) {
this.lineWriter.writeLine(colors.error(`${figures.cross} Error in shared worker`));

this.lineWriter.writeLine(colors.stack(evt.err.summary));
this.lineWriter.writeLine(colors.errorStack(evt.err.stack));
if (evt !== last || writeTrailingLines) {
this.lineWriter.writeLine();
this.lineWriter.writeLine();
this.lineWriter.writeLine();
}
}
}

if (this.uncaughtExceptions.length > 0) {
const writeLeadingLine = this.failures.length === 0 && this.internalErrors.length === 0 && this.sharedWorkerErrors.length === 0;
const writeTrailingLines = shouldWriteFailFastDisclaimer || this.unhandledRejections.length > 0;

if (writeLeadingLine) {
Expand All @@ -573,7 +599,7 @@ class MiniReporter {
}

if (this.unhandledRejections.length > 0) {
const writeLeadingLine = this.failures.length === 0 && this.internalErrors.length === 0 && this.uncaughtExceptions.length === 0;
const writeLeadingLine = this.failures.length === 0 && this.internalErrors.length === 0 && this.sharedWorkerErrors.length === 0 && this.uncaughtExceptions.length === 0;
const writeTrailingLines = shouldWriteFailFastDisclaimer;

if (writeLeadingLine) {
Expand Down
8 changes: 8 additions & 0 deletions lib/reporters/verbose.js
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,14 @@ class VerboseReporter {
this.lineWriter.writeLine(colors.todo(`- ${this.prefixTitle(evt.testFile, evt.title)}`));
}

break;
case 'shared-worker-error':
this.lineWriter.writeLine(colors.error(`${figures.cross} Error in shared worker`));

this.lineWriter.writeLine(colors.stack(evt.err.summary));
this.lineWriter.writeLine(colors.errorStack(evt.err.stack));
this.lineWriter.writeLine();
this.lineWriter.writeLine();
break;
case 'stats':
this.stats = evt.stats;
Expand Down
3 changes: 3 additions & 0 deletions lib/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class Runner extends Emittery {
serial: [],
todo: []
};
this.waitForReady = [];

const uniqueTestTitles = new Set();
this.registerUniqueTitle = title => {
Expand Down Expand Up @@ -435,6 +436,8 @@ class Runner extends Emittery {
});
}

await Promise.all(this.waitForReady);

if (concurrentTests.length === 0 && serialTests.length === 0) {
this.emit('finish');
// Don't run any hooks if there are no tests to run.
Expand Down
Loading

0 comments on commit 5a01bf5

Please sign in to comment.