Skip to content

Commit

Permalink
[WIP]Restart browser if it became unresponsive (closes DevExpress#1815)
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexKamaev committed Aug 20, 2018
1 parent 19fd15d commit 844c09a
Show file tree
Hide file tree
Showing 7 changed files with 140 additions and 2 deletions.
2 changes: 1 addition & 1 deletion Gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -625,7 +625,7 @@ function testFunctional (fixturesDir, testingEnvironmentName, browserProviderNam
.pipe(mocha({
ui: 'bdd',
reporter: 'spec',
timeout: typeof v8debug === 'undefined' ? 30000 : Infinity // NOTE: disable timeouts in debug
timeout: typeof v8debug === 'undefined' ? 180000 : Infinity // NOTE: disable timeouts in debug
}));
}

Expand Down
32 changes: 31 additions & 1 deletion src/browser/connection/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import COMMAND from './command';
import STATUS from './status';
import { GeneralError } from '../../errors/runtime';
import MESSAGE from '../../errors/runtime/message';
import testRunTracker from '../../api/test-run-tracker';

const IDLE_PAGE_TEMPLATE = read('../../client/browser/idle-page/index.html.mustache');

Expand Down Expand Up @@ -98,6 +99,8 @@ export default class BrowserConnection extends EventEmitter {

try {
await this.provider.closeBrowser(this.id);

this.opened = false;
}
catch (err) {
// NOTE: A warning would be really nice here, but it can't be done while log is stored in a task.
Expand All @@ -112,9 +115,30 @@ export default class BrowserConnection extends EventEmitter {
}
}

_restartBrowser () {
this.ready = false;

this._forceIdle();

this._closeBrowser()
.then(() => {
const testRun = this._getActiveTestRun();

testRun.stop(new GeneralError(MESSAGE.browserDisconnected, this.userAgent));

this._runBrowser();
});
}

_waitForHeartbeat () {
this.heartbeatTimeout = setTimeout(() => {
this.emit('error', new GeneralError(MESSAGE.browserDisconnected, this.userAgent));
const needRestartBrowser = true; // option

if (needRestartBrowser)
this._restartBrowser();
else
this.emit('error', new GeneralError(MESSAGE.browserDisconnected, this.userAgent));

}, this.HEARTBEAT_TIMEOUT);
}

Expand All @@ -125,6 +149,12 @@ export default class BrowserConnection extends EventEmitter {
return this.pendingTestRunUrl;
}

_getActiveTestRun () {
const testRuns = Object.values(testRunTracker.activeTestRuns);

return testRuns.find(tr => tr.browserConnection.id === this.id);
}

async _popNextTestRunUrl () {
while (this.hasQueuedJobs && !this.currentJob.hasQueuedTestRuns)
this.jobQueue.shift();
Expand Down
5 changes: 5 additions & 0 deletions src/runner/test-run-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ export default class TestRunController extends EventEmitter {
}

_keepInQuarantine () {
this._restart();
}

_restart () {
this.emit('test-run-restart');
}

Expand Down Expand Up @@ -135,6 +139,7 @@ export default class TestRunController extends EventEmitter {

testRun.once('start', () => this.emit('test-run-start'));
testRun.once('done', () => this._testRunDone());
testRun.once('stop', () => this._restart());

testRun.start();

Expand Down
8 changes: 8 additions & 0 deletions src/test-run/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,9 @@ export default class TestRun extends EventEmitter {
}

_rejectCurrentDriverTask (err) {
if (!this.currentDriverTask)
return;

err.callsite = err.callsite || this.driverTaskQueue[0].callsite;
err.isRejectedDriverTask = true;

Expand Down Expand Up @@ -666,6 +669,11 @@ export default class TestRun extends EventEmitter {

return await getLocation();
}

stop (err) {
this._rejectCurrentDriverTask(err);
this.emit('stop');
}
}


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="log"></div>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
const path = require('path');
const Promise = require('pinkie');
const expect = require('chai').expect;
const config = require('../../../config');
const browserProviderPool = require('../../../../../lib/browser/provider/pool');
const BrowserConnection = require('../../../../../lib/browser/connection');

let hasErrors = true;

function customReporter () {
return {
reportTestDone (name, testRunInfo) {
hasErrors = !!testRunInfo.errs.length;
},
reportFixtureStart () {
},
reportTaskStart () {
},
reportTaskDone () {
}
};
}

if (config.useLocalBrowsers) {
describe('Browser reconnect', function () {
async function run (pathToTest) {
const src = path.join(__dirname, pathToTest);
const aliases = config.currentEnvironment.browsers.map(browser => browser.alias);

return Promise.all(aliases.map(alias => browserProviderPool.getBrowserInfo(alias)))
.then(browsers => {
const connections = browsers.map(browser => new BrowserConnection(testCafe.browserConnectionGateway, browser, true));

connections.forEach(connection => {
connection.HEARTBEAT_TIMEOUT = 4000;
});

return connections;
})
.then(connection => {
return testCafe
.createRunner()
.src(src)
.reporter(customReporter)
.browsers(connection)
.run().then(() => {
expect(hasErrors).to.be.false;
});
});
}

it.only('Should restart browser when it does not respond', function () {
return run('./testcafe-fixtures/index-test.js');
});
});
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { ClientFunction } from 'testcafe';

fixture `Browser reconnect`
.page `http://localhost:3000/fixtures/browser-provider/browser-reconnect/pages/index.html`;

const counter = {};
const getUserAgent = ClientFunction(() => navigator.userAgent.toString());

const hang = ClientFunction(() => {
const now = Date.now();

while (Date.now() < now + 5000) {
// hang for 5s
}
});

test('Should restart browser when it does not respond', async t => {
const userAgent = await getUserAgent();

counter[userAgent] = counter[userAgent] || 0;

counter[userAgent]++;

if (counter[userAgent] < 3)
await hang();

await t.expect(counter[userAgent]).eql(3);
});

0 comments on commit 844c09a

Please sign in to comment.