Skip to content
This repository was archived by the owner on Jul 29, 2024. It is now read-only.

Commit cca82ca

Browse files
committed
refactor(launcher): make launcher use child process messages instead of messing with the env
1 parent 3879af3 commit cca82ca

File tree

2 files changed

+124
-97
lines changed

2 files changed

+124
-97
lines changed

lib/launcher.js

+97-77
Original file line numberDiff line numberDiff line change
@@ -11,43 +11,42 @@ var util = require('util'),
1111
child = require('child_process'),
1212
ConfigParser = require('./configParser');
1313

14+
var launcherPrefix = '[launcher] '
1415

15-
var reportHeader_ = function(proc, env) {
16-
var capability = JSON.parse(env.capability);
16+
var log_ = function(stuff) {
17+
console.log(launcherPrefix + stuff);
18+
}
19+
20+
var noLineLog_ = function(stuff) {
21+
process.stdout.write(launcherPrefix + stuff);
22+
}
23+
24+
25+
var reportHeader_ = function(childFork) {
26+
var capability = childFork.capability;
1727
var eol = require('os').EOL;
1828

19-
var outputHeader = eol + '------------------------------' + eol;
20-
outputHeader += 'PID: ' + proc.pid + ' (capability: ';
29+
var outputHeader = eol + '------------------------------------' + eol;;
30+
outputHeader += 'PID: ' + childFork.process.pid + ' (capability: ';
2131
outputHeader += (capability.browserName) ?
2232
capability.browserName : '';
2333
outputHeader += (capability.version) ?
2434
capability.version : '';
2535
outputHeader += (capability.platform) ?
2636
capability.platform : '';
27-
outputHeader += (env.runNumber) ?
28-
' #' + env.runNumber : '';
37+
outputHeader += (childFork.runNumber) ?
38+
' #' + childFork.runNumber : '';
2939
outputHeader += ')' + eol;
30-
outputHeader += '------------------------------';
40+
outputHeader += '------------------------------------' + eol;
3141

3242

3343
util.puts(outputHeader);
3444
};
3545

36-
var makeChildEnv_ = function(additional) {
37-
var newEnv = {};
38-
for (var v in process.env) {
39-
newEnv[v] = process.env[v];
40-
}
41-
for (var a in additional) {
42-
newEnv[a] = additional[a];
43-
}
44-
return newEnv;
45-
};
46-
4746
/**
4847
* Initialize and run the tests.
4948
*
50-
* @param {Object} argv - Optimist parsed arguments
49+
* @param {Object} argv Optimist parsed arguments.
5150
*/
5251
var init = function(argv) {
5352

@@ -61,8 +60,20 @@ var init = function(argv) {
6160
addConfig(argv).
6261
getConfig();
6362

63+
var listRemainingForks = function() {
64+
var remaining = 0;
65+
childForks.forEach(function(childFork) {
66+
if (!childFork.done) {
67+
remaining++;
68+
}
69+
});
70+
if (remaining) {
71+
noLineLog_(remaining + ' instance(s) of WebDriver still running');
72+
}
73+
}
74+
6475
if (config.multiCapabilities.length) {
65-
console.log('Running using config.multiCapabilities - ' +
76+
log_('Running using config.multiCapabilities - ' +
6677
'config.capabilities will be ignored');
6778
}
6879

@@ -80,79 +91,88 @@ var init = function(argv) {
8091

8192
// Fork the child runners.
8293
for (var j = 0; j < capabilityRunCount; j++) {
83-
84-
// We use an environment variable to retain the optimist parsed args and
85-
// to tell the runner which capability its responsible for.
86-
// The child environment inherits from the parent environment.
87-
childForks.push(makeChildEnv_({
88-
cliArgs: JSON.stringify(argv),
89-
capability: JSON.stringify(config.multiCapabilities[i]),
94+
childForks.push({
95+
cliArgs: argv,
96+
capability: config.multiCapabilities[i],
9097
runNumber: j + 1
91-
}));
98+
});
9299
}
93100
}
94101

95102
// If we're launching multiple runners, aggregate output until completion.
96-
// Otherwise, there are multiple runners, let's pipe the output straight
103+
// Otherwise, there is a single runner, let's pipe the output straight
97104
// through to maintain realtime reporting.
98105
if (childForks.length === 1) {
99-
var childEnv = childForks.pop(),
100-
childProc = child.fork(__dirname + "/runFromLauncher.js", [],
101-
{env: childEnv,
102-
cwd: process.cwd()});
103-
reportHeader_(childProc, childEnv);
104-
childProc.on('error', function(err) {
105-
util.puts('Runner Process(' + childProc.pid + ') Error: ' + err);
106+
var childFork = childForks[0];
107+
childFork.process = child.fork(
108+
__dirname + "/runFromLauncher.js", [], {cwd: process.cwd()});
109+
reportHeader_(childFork);
110+
111+
childFork.process.send({
112+
command: 'run',
113+
cliArgs: childFork.cliArgs,
114+
capability: childFork.capability
115+
});
116+
117+
childFork.process.on('error', function(err) {
118+
log_('Runner Process(' + childFork.process.pid + ') Error: ' + err);
106119
});
107120

108-
childProc.on('exit', function(code, signal) {
121+
childFork.process.on('exit', function(code, signal) {
109122
if (code) {
110-
util.puts('Runner Process Exited With Error Code: ' + code);
123+
log_('Runner Process Exited With Error Code: ' + code);
111124
launcherExitCode = 1;
112125
}
113126
});
114127
} else {
115-
process.stdout.write('Running ' + childForks.length + ' instances of WebDriver');
128+
noLineLog_('Running ' + childForks.length +
129+
' instances of WebDriver');
116130

117131
// Launch each fork and set up listeners
118-
childForks.forEach(function(childEnv) {
119-
120-
var childProc = child.fork(__dirname + "/runFromLauncher.js", [],
121-
{env: childEnv, silent: true, cwd: process.cwd()});
122-
123-
// Force evaluation to protect from loop changing closure in callbacks
124-
(function(childProc_, childEnv_) {
125-
childProc_.output = '';
126-
127-
// stdin pipe
128-
childProc_.stdout.on('data', function(chunk) {
129-
// Output something so processes know we haven't stalled.
130-
// TODO - consider replacing this with a message system which would
131-
// output a dot per test.
132-
process.stdout.write('.');
133-
childProc_.output += chunk;
134-
});
135-
136-
// stderr pipe
137-
childProc_.stderr.on('data', function(chunk) {
138-
childProc_.output += chunk;
139-
});
140-
141-
// err handler
142-
childProc_.on('error', function(err) {
143-
util.puts('Runner Process(' + childProc_.pid + ') Error: ' + err);
144-
});
145-
146-
// exit handlers
147-
childProc_.on('exit', function(code, signal) {
148-
if (code) {
149-
util.puts('Runner Process Exited With Error Code: ' + code);
150-
launcherExitCode = 1;
151-
}
152-
reportHeader_(childProc_, childEnv_);
153-
util.puts(childProc_.output);
154-
});
155-
})(childProc, childEnv);
132+
childForks.forEach(function(childFork) {
133+
134+
childFork.process = child.fork(
135+
__dirname + "/runFromLauncher.js", [],
136+
{silent: true, cwd: process.cwd()});
137+
138+
childFork.output = '';
139+
140+
// stdin pipe
141+
childFork.process.stdout.on('data', function(chunk) {
142+
// Output something so processes know we haven't stalled.
143+
// TODO - consider replacing this with a message system which would
144+
// output a dot per test.
145+
process.stdout.write('.');
146+
childFork.output += chunk;
147+
});
148+
149+
// stderr pipe
150+
childFork.process.stderr.on('data', function(chunk) {
151+
childFork.output += chunk;
152+
});
153+
154+
// err handler
155+
childFork.process.on('error', function(err) {
156+
log_('Runner Process(' + childFork.process.pid + ') Error: ' + err);
157+
});
158+
159+
// exit handlers
160+
childFork.process.on('exit', function(code, signal) {
161+
if (code) {
162+
log_('Runner Process Exited With Error Code: ' + code);
163+
launcherExitCode = 1;
164+
}
165+
reportHeader_(childFork);
166+
util.puts(childFork.output);
167+
childFork.done = true;
168+
listRemainingForks();
169+
});
170+
171+
childFork.process.send({
172+
command: 'run',
173+
cliArgs: childFork.cliArgs,
174+
capability: childFork.capability
175+
});
156176
});
157177
}
158178

lib/runFromLauncher.js

+27-20
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,39 @@
11
/**
22
* This serves as the main function for starting a test run that has been
3-
* requested by the launcher. It assumes that the process environment has
4-
* been set with the following properties:
5-
* cliArgs - a stringified JSON object representing the CLI args passed
6-
* to this test run.
7-
* capability - a stringified JSON object representing the particular
8-
* capability to be used for this run.
9-
* numNumber - an identifier for this run, in case multiple runs of the same
10-
* capability were requested.
3+
* requested by the launcher.
114
*/
125

136
var ConfigParser = require('./configParser');
147
var Runner = require('./runner');
158

169
var config, argv;
1710

18-
// Merge in config file options.
19-
argv = JSON.parse(process.env.cliArgs);
20-
config = new ConfigParser().
21-
addFileConfig(argv._[0]).
22-
addConfig(argv).
23-
getConfig();
11+
process.on('message', function(m) {
12+
switch (m.command) {
13+
case 'run':
14+
if (!m.capability) {
15+
throw new Error('Run message missing capability');
16+
}
17+
if (!m.cliArgs) {
18+
throw new Error('Run message missing cliArgs');
19+
}
20+
// Merge in config file options.
21+
argv = m.cliArgs;
22+
config = new ConfigParser().
23+
addFileConfig(argv._[0]).
24+
addConfig(argv).
25+
getConfig();
2426

25-
// Grab capability to run from launcher.
26-
config.capabilities = JSON.parse(process.env.capability);
27+
// Grab capability to run from launcher.
28+
config.capabilities = m.capability;
2729

28-
// Launch test run.
29-
var runner = new Runner(config);
30-
runner.run().then(function(exitCode) {
31-
process.exit(exitCode);
30+
// Launch test run.
31+
var runner = new Runner(config);
32+
runner.run().then(function(exitCode) {
33+
process.exit(exitCode);
34+
});
35+
break;
36+
default:
37+
throw new Error('command ' + m.command + ' is invalid');
38+
}
3239
});

0 commit comments

Comments
 (0)