Skip to content

Commit

Permalink
Handle SIGINT via async-exit-hook (closes DevExpress#1378)
Browse files Browse the repository at this point in the history
  • Loading branch information
AndreyBelym committed Sep 11, 2017
1 parent 51ee001 commit 63bc749
Show file tree
Hide file tree
Showing 13 changed files with 112 additions and 14 deletions.
2 changes: 1 addition & 1 deletion bin/testcafe-with-v8-flag-filter.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
var path = require('path');
var v8FlagsFilter = require('bin-v8-flags-filter');

v8FlagsFilter(path.join(__dirname, '../lib/cli'));
v8FlagsFilter(path.join(__dirname, '../lib/cli'), { useShutdownMessage: true });
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,15 @@
"prepublish": "publish-please guard"
},
"dependencies": {
"async-exit-hook": "^1.1.2",
"babel-core": "^6.22.1",
"babel-plugin-transform-class-properties": "^6.24.1",
"babel-plugin-transform-runtime": "^6.22.0",
"babel-preset-env": "^1.1.8",
"babel-preset-flow": "^6.23.0",
"babel-preset-stage-2": "^6.22.0",
"babel-runtime": "^6.22.0",
"bin-v8-flags-filter": "^1.0.0",
"bin-v8-flags-filter": "^1.1.1",
"callsite": "^1.0.0",
"callsite-record": "^4.0.0",
"chai": "^3.0.0",
Expand All @@ -78,7 +79,7 @@
"is-ci": "^1.0.10",
"is-glob": "^2.0.1",
"lodash": "^4.13.1",
"log-update": "^1.0.2",
"log-update-async-hook": "^2.0.2",
"map-reverse": "^1.0.1",
"mkdirp": "^0.5.1",
"moment": "^2.10.3",
Expand Down
5 changes: 3 additions & 2 deletions src/browser/connection/gateway.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,9 @@ export default class BrowserConnectionGateway {

static onHeartbeat (req, res, connection) {
if (BrowserConnectionGateway.ensureConnectionReady(res, connection)) {
connection.heartbeat();
res.end();
var status = connection.heartbeat();

respondWithJSON(res, status);
}
}

Expand Down
11 changes: 10 additions & 1 deletion src/browser/connection/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { readSync as read } from 'read-file-relative';
import promisifyEvent from 'promisify-event';
import shortId from 'shortid';
import COMMAND from './command';
import STATUS from './status';
import { GeneralError } from '../../errors/runtime';
import MESSAGE from '../../errors/runtime/message';

Expand Down Expand Up @@ -36,6 +37,7 @@ export default class BrowserConnection extends EventEmitter {
this.provider = browserInfo.provider;

this.permanent = permanent;
this.closing = false;
this.closed = false;
this.ready = false;
this.opened = false;
Expand Down Expand Up @@ -164,9 +166,11 @@ export default class BrowserConnection extends EventEmitter {
}

close () {
if (this.closed)
if (this.closed || this.closing)
return;

this.closing = true;

this._closeBrowser()
.then(() => {
this.browserConnectionGateway.stopServingConnection(this);
Expand All @@ -193,6 +197,11 @@ export default class BrowserConnection extends EventEmitter {
heartbeat () {
clearTimeout(this.heartbeatTimeout);
this._waitForHeartbeat();

return {
code: this.closing ? STATUS.closing : STATUS.ok,
url: this.closing ? this.idleUrl : ''
};
}

renderIdlePage () {
Expand Down
4 changes: 4 additions & 0 deletions src/browser/connection/status.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export default {
ok: 'ok',
closing: 'closing'
};
8 changes: 8 additions & 0 deletions src/browser/provider/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,14 @@ export default class BrowserProvider {
}

async closeBrowser (browserId) {
var isLocalBrowser = await this.plugin.isLocalBrowser(browserId);
var supportedFeatures = await this.plugin.hasCustomActionForBrowser(browserId);

if (isLocalBrowser && !supportedFeatures.hasCloseBrowser) {
await this.plugin.closeBrowser(this.windowDescriptors[browserId]);
return;
}

await this.plugin.closeBrowser(browserId);
}

Expand Down
1 change: 1 addition & 0 deletions src/browser/provider/plugin-host.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ export default class BrowserProviderPluginHost {

async hasCustomActionForBrowser (/* browserId */) {
return {
hasCloseBrowser: this.hasOwnProperty('closeBrowser'),
hasResizeWindow: this.hasOwnProperty('resizeWindow'),
hasTakeScreenshot: this.hasOwnProperty('takeScreenshot'),
hasCanResizeWindowToDimensions: this.hasOwnProperty('canResizeWindowToDimensions'),
Expand Down
50 changes: 49 additions & 1 deletion src/cli/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import chalk from 'chalk';
import resolveCwd from 'resolve-cwd';
import setupExitHook from 'async-exit-hook';
import browserProviderPool from '../browser/provider/pool';
import { GeneralError, APIError } from '../errors/runtime';
import MESSAGE from '../errors/runtime/message';
Expand All @@ -8,8 +9,50 @@ import log from './log';
import remotesWizard from './remotes-wizard';
import createTestCafe from '../';

function exit (code) {

const TERMINATION_TYPES = {
sigint: 'sigint',
shutdown: 'shutdown'
};

var showMessageOnExit = true;
var exiting = false;

var handledSignalsCount = {
[TERMINATION_TYPES.sigint]: 0,
[TERMINATION_TYPES.shutdown]: 0
};

function exitHandler () {
if (!showMessageOnExit)
return;

log.hideSpinner();
log.write('Stopping TestCafe...');
log.showSpinner();

process.on('exit', () => log.hideSpinner(true));
}

function forcedExitHandler (terminationType) {
handledSignalsCount[terminationType]++;

if (exiting || handledSignalsCount[terminationType] < 2)
return;

exiting = true;

exit(0);
}

function setupForcedExitHandler () {
process.on('SIGINT', () => forcedExitHandler(TERMINATION_TYPES.sigint));

process.on('message', message => message === 'shutdown' && forcedExitHandler(TERMINATION_TYPES.shutdown));
}

function exit (code) {
log.hideSpinner(true);

// NOTE: give a process time to flush the output.
// It's necessary in some environments.
Expand Down Expand Up @@ -70,6 +113,7 @@ async function runTests (argParser) {
}

finally {
showMessageOnExit = false;
await testCafe.close();
}

Expand Down Expand Up @@ -115,6 +159,9 @@ function useLocalInstallation () {
if (useLocalInstallation())
return;

setupExitHook(exitHandler);
setupForcedExitHandler(forcedExitHandler);

try {
var argParser = new CliArgumentParser();

Expand All @@ -126,6 +173,7 @@ function useLocalInstallation () {
await runTests(argParser);
}
catch (err) {
showMessageOnExit = false;
error(err);
}
})();
Expand Down
7 changes: 5 additions & 2 deletions src/cli/log.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import tty from 'tty';
import elegantSpinner from 'elegant-spinner';
import logUpdate from 'log-update';
import logUpdate from 'log-update-async-hook';
import chalk from 'chalk';
import isCI from 'is-ci';

Expand All @@ -24,11 +24,14 @@ export default {
}
},

hideSpinner () {
hideSpinner (isExit) {
if (this.animation) {
clearInterval(this.animation);
logUpdate.stderr.clear();

if (isExit)
logUpdate.stderr.done();

this.animation = null;
}
},
Expand Down
18 changes: 15 additions & 3 deletions src/client/browser/index.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
// TODO: once we'll have client commons load it from there instead of node modules (currently it's leads to two copies of this packages on client)
import Promise from 'pinkie';
import COMMAND from '../../browser/connection/command';
import STATUS from '../../browser/connection/status';

const HEARTBEAT_INTERVAL = 30 * 1000;
const HEARTBEAT_INTERVAL = 2 * 1000;

var allowInitScriptExecution = false;

Expand Down Expand Up @@ -37,8 +38,19 @@ function isCurrentLocation (url) {

//API
export function startHeartbeat (heartbeatUrl, createXHR) {
sendXHR(heartbeatUrl, createXHR);
window.setInterval(() => sendXHR(heartbeatUrl, createXHR), HEARTBEAT_INTERVAL);
function heartbeat () {
sendXHR(heartbeatUrl, createXHR)
.then(status => {
if (status.code === STATUS.closing && !isCurrentLocation(status.url)) {
stopInitScriptExecution();
document.location = status.url;
}
});
}

window.setInterval(heartbeat, HEARTBEAT_INTERVAL);

heartbeat();
}

function executeInitScript (initScriptUrl, createXHR) {
Expand Down
7 changes: 6 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Promise from 'pinkie';
import TestCafe from './testcafe';
import * as endpointUtils from 'endpoint-utils';
import setupExitHook from 'async-exit-hook';
import { GeneralError } from './errors/runtime';
import MESSAGE from './errors/runtime/message';
import embeddingUtils from './embedding-utils';
Expand Down Expand Up @@ -42,7 +43,11 @@ async function createTestCafe (hostname, port1, port2) {
getValidPort(port2)
]);

return new TestCafe(hostname, port1, port2);
var testcafe = new TestCafe(hostname, port1, port2);

setupExitHook(cb => testcafe.close().then(cb));

return testcafe;
}

// Embedding utils
Expand Down
2 changes: 1 addition & 1 deletion src/notifications/debug-logger.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import chalk from 'chalk';
import { findIndex } from 'lodash';
import logUpdate from 'log-update';
import logUpdate from 'log-update-async-hook';
import createStackFilter from '../errors/create-stack-filter';

export default {
Expand Down
6 changes: 6 additions & 0 deletions src/testcafe.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const FAVICON = read('./client/ui/favicon.ico', true);

export default class TestCafe {
constructor (hostname, port1, port2) {
this.closed = false;
this.proxy = new Proxy(hostname, port1, port2);
this.browserConnectionGateway = new BrowserConnectionGateway(this.proxy);
this.runners = [];
Expand Down Expand Up @@ -62,6 +63,11 @@ export default class TestCafe {
}

async close () {
if (this.closed)
return;

this.closed = true;

await Promise.all(this.runners.map(runner => runner.stop()));

await browserProviderPool.dispose();
Expand Down

0 comments on commit 63bc749

Please sign in to comment.