Skip to content
This repository was archived by the owner on Sep 21, 2022. It is now read-only.

Commit 1f0ffbe

Browse files
committed
fix: correct exit on 'SIGHUP', 'SIGINT' or 'SIGTERM'
1 parent 2bf95bb commit 1f0ffbe

File tree

12 files changed

+79
-76
lines changed

12 files changed

+79
-76
lines changed

lib/browser-pool/basic-pool.js

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
var util = require('util'),
33
Browser = require('../browser'),
44
Pool = require('./pool'),
5-
signalHandler = require('../signal-handler'),
65
_ = require('lodash'),
7-
Promise = require('bluebird');
6+
Promise = require('bluebird'),
7+
CancelledError = require('../errors/cancelled-error');
88

99
var activeSessions = {};
1010

@@ -23,15 +23,16 @@ util.inherits(BasicPool, Pool);
2323

2424
Pool.prototype.getBrowser = function(id) {
2525
var _this = this,
26-
browser = Browser.create(this._config.forBrowser(id)),
27-
launchPromise = browser.launch(this._calibrator);
26+
browser = Browser.create(this._config.forBrowser(id));
2827

29-
activeSessions[browser.id] = {
30-
browser: browser,
31-
launchPromise: launchPromise
32-
};
28+
return browser.launch(this._calibrator)
29+
.then(() => {
30+
if (this._cancelled) {
31+
return Promise.reject(new CancelledError());
32+
}
3333

34-
return launchPromise
34+
activeSessions[browser.sessionId] = browser;
35+
})
3536
.then(browser.reset.bind(browser)).thenReturn(browser)
3637
.catch(function(e) {
3738
return _this.freeBrowser(browser)
@@ -42,19 +43,16 @@ Pool.prototype.getBrowser = function(id) {
4243
};
4344

4445
Pool.prototype.freeBrowser = function(browser) {
45-
delete activeSessions[browser.id];
46+
delete activeSessions[browser.sessionId];
4647
return browser.quit();
4748
};
4849

49-
signalHandler.on('exit', function() {
50-
console.log('Killing browsers...');
51-
return _(activeSessions)
52-
.map(function(session) {
53-
var quit_ = session.browser.quit.bind(session.browser);
54-
return session.launchPromise.then(quit_);
55-
})
56-
.thru(Promise.all)
57-
.value();
58-
});
50+
Pool.prototype.cancel = function() {
51+
this._cancelled = true;
52+
53+
_.forEach(activeSessions, (browser) => browser.quit());
54+
55+
activeSessions = {};
56+
};
5957

6058
module.exports = BasicPool;

lib/browser/new-browser.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@ module.exports = class NewBrowser extends Browser {
341341
.then(() => this._wd.quit())
342342
.then(() => this.log('kill browser %o', this))
343343
.then(() => this._setHttpTimeout())
344-
.catch((err) => console.warn(err));
344+
.catch((err) => this.log(err));
345345
}
346346

347347
inspect() {

lib/cli/index.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@ const program = require('commander');
55
const Promise = require('bluebird');
66

77
const Config = require('../config');
8+
const Events = require('../constants/events');
89
const Gemini = require('../gemini');
910
const pkg = require('../../package.json');
1011
const handleErrors = require('./errors').handleErrors;
1112
const checkForDeprecations = require('./deprecations').checkForDeprecations;
1213
const handleUncaughtExceptions = require('./errors').handleUncaughtExceptions;
1314

15+
let exitCode;
16+
1417
exports.run = () => {
1518
program
1619
.version(pkg.version)
@@ -86,7 +89,11 @@ function runGemini(method, paths, options) {
8689

8790
return Promise.try(() => {
8891
checkForDeprecations();
89-
return new Gemini(program.config, {cli: true, env: true});
92+
93+
const gemini = new Gemini(program.config, {cli: true, env: true});
94+
gemini.on(Events.INTERRUPT, (data) => exitCode = data.exitCode);
95+
96+
return gemini;
9097
})
9198
.then((gemini) => {
9299
return gemini[method](paths, {
@@ -109,5 +116,5 @@ function runGemini(method, paths, options) {
109116
}
110117

111118
function exit(code) {
112-
process.on('exit', () => process.exit(code));
119+
process.on('exit', () => process.exit(exitCode || code));
113120
}

lib/constants/events.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,7 @@ module.exports = {
3333
UPDATE_RESULT: 'updateResult',
3434

3535
BEFORE_FILE_READ: 'beforeFileRead',
36-
AFTER_FILE_READ: 'afterFileRead'
36+
AFTER_FILE_READ: 'afterFileRead',
37+
38+
INTERRUPT: 'interrupt'
3739
};

lib/gemini.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,13 @@ module.exports = class Gemini extends PassthroughEmitter {
6565

6666
this._passThroughEvents(runner);
6767

68+
// it is important to require signal handler here in order to guarantee subscribing to "INTERRUPT" event
69+
require('./signal-handler').on(Events.INTERRUPT, (data) => {
70+
this.emit(Events.INTERRUPT, data);
71+
72+
runner.cancel();
73+
});
74+
6875
if (browsers) {
6976
this.checkUnknownBrowsers(browsers);
7077

lib/reporters/html/view-model.js

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,28 +49,36 @@ module.exports = class ViewModel {
4949
* @param {TestStateResult} result
5050
*/
5151
addFail(result) {
52+
this._addFailResult(result);
53+
54+
this._counter.onFailed(result);
55+
}
56+
57+
_addFailResult(result) {
5258
this._addTestResult(result, {
5359
fail: true,
5460
actualPath: lib.currentPath(result),
5561
expectedPath: lib.referencePath(result),
5662
diffPath: lib.diffPath(result)
5763
});
58-
59-
this._counter.onFailed(result);
6064
}
6165

6266
/**
6367
* @param {ErrorStateResult} result
6468
*/
6569
addError(result) {
70+
this._addErrorResult(result);
71+
72+
this._counter.onFailed(result);
73+
}
74+
75+
_addErrorResult(result) {
6676
this._addTestResult(result, {
6777
actualPath: result.state ? lib.currentPath(result) : '',
6878
error: true,
6979
image: !!result.imagePath || !!result.currentPath,
7080
reason: (result.stack || result.message || result || '')
7181
});
72-
73-
this._counter.onFailed(result);
7482
}
7583

7684
/**
@@ -91,9 +99,9 @@ module.exports = class ViewModel {
9199
*/
92100
addRetry(result) {
93101
if (result.hasOwnProperty('equal')) {
94-
this.addFail(result);
102+
this._addFailResult(result);
95103
} else {
96-
this.addError(result);
104+
this._addErrorResult(result);
97105
}
98106

99107
this._counter.onRetry(result);

lib/runner/browser-runner/index.js

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
'use strict';
22

33
const _ = require('lodash');
4-
const Promise = require('bluebird');
54
const promiseUtils = require('q-promise-utils');
65
const BrowserAgent = require('./browser-agent');
76
const Runner = require('../runner');
@@ -35,14 +34,9 @@ module.exports = class BrowserRunner extends Runner {
3534
}
3635

3736
cancel() {
38-
this._runSuite = this._doNothing;
3937
this._suiteRunners.forEach((runner) => runner.cancel());
4038
}
4139

42-
_doNothing() {
43-
return Promise.resolve();
44-
}
45-
4640
_runSuites(suiteCollection, stateProcessor) {
4741
const suites = suiteCollection.clone().allSuites();
4842

lib/runner/index.js

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ module.exports = class TestsRunner extends Runner {
4040
return Promise.resolve(this.emitAndWait(Events.START_RUNNER, this))
4141
.then(() => this.emit(Events.BEGIN, this._formatBeginEventData(suiteCollection)))
4242
.then(() => this._stateProcessor.prepare(this))
43-
.then(() => this._runTests(suiteCollection))
43+
.then(() => !this._cancelled && this._runTests(suiteCollection))
4444
.then(() => this.coverage && this.coverage.processStats())
4545
.finally(() => {
4646
this.emit(Events.END);
@@ -76,8 +76,6 @@ module.exports = class TestsRunner extends Runner {
7676
_runTestsInBrowser(suiteCollection, browserId) {
7777
const runner = BrowserRunner.create(browserId, this.config, this._browserPool);
7878

79-
this._browserRunners.push(runner);
80-
8179
this.passthroughEvent(runner, [
8280
Events.RETRY,
8381
Events.START_BROWSER,
@@ -97,11 +95,8 @@ module.exports = class TestsRunner extends Runner {
9795
runner.on(Events.TEST_RESULT, (result) => this._handleResult(result, [Events.END_TEST, Events.TEST_RESULT]));
9896
runner.on(Events.UPDATE_RESULT, (result) => this._handleResult(result, Events.UPDATE_RESULT));
9997

100-
return runner.run(suiteCollection, this._stateProcessor)
101-
.catch((e) => {
102-
this._cancel();
103-
return Promise.reject(e);
104-
});
98+
this._browserRunners.push(runner);
99+
return runner.run(suiteCollection, this._stateProcessor);
105100
}
106101

107102
_handleResult(result, events) {
@@ -116,8 +111,11 @@ module.exports = class TestsRunner extends Runner {
116111
}
117112
}
118113

119-
_cancel() {
114+
cancel() {
115+
this._cancelled = true;
116+
120117
this._browserRunners.forEach((runner) => runner.cancel());
118+
121119
this._browserPool.cancel();
122120
}
123121
};

lib/runner/suite-runner/insistent-suite-runner.js

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,6 @@ module.exports = class InsistentSuiteRunner extends SuiteRunner {
2020
this._retriesPerformed = 0;
2121
}
2222

23-
cancel() {
24-
this._suiteRunner.cancel();
25-
}
26-
2723
_doRun(stateProcessor) {
2824
this._suiteRunner = this._initSuiteRunner();
2925
this._statesToRetry = [];
@@ -61,7 +57,7 @@ module.exports = class InsistentSuiteRunner extends SuiteRunner {
6157
}
6258

6359
_retry(stateProcessor) {
64-
if (_.isEmpty(this._statesToRetry)) {
60+
if (_.isEmpty(this._statesToRetry) || this._cancelled) {
6561
return;
6662
}
6763

lib/runner/suite-runner/regular-suite-runner.js

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,6 @@ module.exports = class RegularSuiteRunner extends SuiteRunner {
5353
});
5454
}
5555

56-
cancel() {
57-
this._runStateInSession = this._doNothing;
58-
}
59-
60-
_doNothing() {
61-
return Promise.resolve();
62-
}
63-
6456
_processStates(stateProcessor) {
6557
const browser = this._session.browser;
6658

0 commit comments

Comments
 (0)