Innovenergy_trunk/frontend/node_modules/testcafe/lib/runner/test-run-controller.js

171 lines
29 KiB
JavaScript

"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const async_event_emitter_1 = __importDefault(require("../utils/async-event-emitter"));
//@ts-ignore
const testcafe_legacy_api_1 = require("testcafe-legacy-api");
const test_run_1 = __importDefault(require("../test-run"));
const session_controller_1 = __importDefault(require("../test-run/session-controller"));
const quarantine_1 = require("../utils/get-options/quarantine");
const DISCONNECT_THRESHOLD = 3;
class TestRunController extends async_event_emitter_1.default {
constructor({ test, index, proxy, screenshots, warningLog, fixtureHookController, opts, testRunHook, compilerService, messageBus, }) {
super();
this.test = test;
this.index = index;
this._opts = opts;
this._proxy = proxy;
this._screenshots = screenshots;
this._warningLog = warningLog;
this._fixtureHookController = fixtureHookController;
this._testRunHook = testRunHook;
this._testRunCtor = TestRunController._getTestRunCtor(test, opts);
this.testRun = null;
this.done = false;
this._quarantine = this._opts.quarantineMode ? new quarantine_1.Quarantine() : null;
this._disconnectionCount = 0;
this.compilerService = compilerService;
this._messageBus = messageBus;
}
static _getTestRunCtor(test, opts) {
if (opts.TestRunCtor)
return opts.TestRunCtor;
return test.isLegacy ? testcafe_legacy_api_1.TestRun : test_run_1.default;
}
async _createTestRun(connection, startRunExecutionTime) {
const screenshotCapturer = this._screenshots.createCapturerFor(this.test, this.index, this._quarantine, connection, this._warningLog);
const TestRunCtor = this._testRunCtor;
this.testRun = new TestRunCtor({
test: this.test,
browserConnection: connection,
globalWarningLog: this._warningLog,
opts: this._opts,
compilerService: this.compilerService,
messageBus: this._messageBus,
screenshotCapturer,
startRunExecutionTime,
});
await this.testRun.initialize();
this._screenshots.addTestRun(this.test, this.testRun);
if (this.testRun.addQuarantineInfo)
this.testRun.addQuarantineInfo(this._quarantine);
if (this._quarantine) {
const { successThreshold, attemptLimit } = this._opts.quarantineMode;
this._quarantine.setCustomParameters(attemptLimit, successThreshold);
}
if (!this._quarantine || this._isFirstQuarantineAttempt()) {
await this.emit('test-run-create', {
testRun: this.testRun,
legacy: TestRunCtor === testcafe_legacy_api_1.TestRun,
test: this.test,
index: this.index,
quarantine: this._quarantine,
});
}
return this.testRun;
}
async _endQuarantine() {
if (this._quarantine.attempts.length > 1)
this.testRun.unstable = this._quarantine.getPassedAttempts().length > 0;
await this._emitTestRunDone();
}
_shouldKeepInQuarantine() {
const errors = this.testRun.errs;
const hasErrors = !!errors.length;
const attempts = this._quarantine.attempts;
const isFirstAttempt = this._isFirstQuarantineAttempt();
attempts.push({ testRunId: this.testRun.id, errors });
return isFirstAttempt ? hasErrors : !this._quarantine.isThresholdReached();
}
_isFirstQuarantineAttempt() {
return !!this._quarantine && !this._quarantine.attempts.length;
}
async _keepInQuarantine() {
await this._restartTest();
}
async _restartTest() {
await this.emit('test-run-restart');
}
async _testRunDoneInQuarantineMode() {
if (this._shouldKeepInQuarantine())
await this._keepInQuarantine();
else
await this._endQuarantine();
}
async _testRunDone() {
if (this._quarantine)
await this._testRunDoneInQuarantineMode();
else
await this._emitTestRunDone();
}
async _emitActionStart(args) {
await this._messageBus.emit('test-action-start', args);
}
async _emitActionDone(args) {
await this.emit('test-action-done', args);
}
async _emitTestRunDone() {
// NOTE: we should report test run completion in order they were completed in browser.
// To keep a sequence after fixture hook execution we use completion queue.
await this._fixtureHookController.runFixtureAfterHookIfNecessary(this.testRun);
await this._testRunHook.runTestRunAfterHookIfNecessary(this.testRun);
this.done = true;
await this.emit('test-run-done');
}
async _emitTestRunStart() {
await this._messageBus.emit('test-run-start', this.testRun);
}
async _testRunBeforeDone() {
let raiseEvent = !this._quarantine;
if (!raiseEvent) {
const isSuccessfulQuarantineFirstAttempt = this._isFirstQuarantineAttempt() && !this.testRun.errs.length;
const isAttemptsThresholdReached = this._quarantine.isThresholdReached(this.testRun.errs);
raiseEvent = isSuccessfulQuarantineFirstAttempt || isAttemptsThresholdReached;
}
if (raiseEvent)
await this.emit('test-run-before-done');
}
_testRunDisconnected(connection) {
this._disconnectionCount++;
const disconnectionThresholdExceedeed = this._disconnectionCount >= DISCONNECT_THRESHOLD;
return connection
.processDisconnection(disconnectionThresholdExceedeed)
.then(() => {
return this._restartTest();
});
}
_assignTestRunEvents(testRun, connection) {
testRun.on('action-start', async (args) => this._emitActionStart(Object.assign(args, { testRun })));
testRun.on('action-done', async (args) => this._emitActionDone(Object.assign(args, { testRun })));
testRun.once('start', async () => this._emitTestRunStart());
testRun.once('ready', async () => {
if (!this._quarantine || this._isFirstQuarantineAttempt())
await this.emit('test-run-ready');
});
testRun.once('before-done', () => this._testRunBeforeDone());
testRun.once('done', () => this._testRunDone());
testRun.once('disconnected', () => this._testRunDisconnected(connection));
}
get blocked() {
return this._fixtureHookController.isTestBlocked(this.test);
}
async start(connection, startRunExecutionTime) {
const testRun = await this._createTestRun(connection, startRunExecutionTime);
const hookOk = await this._testRunHook.runTestRunBeforeHookIfNecessary(testRun)
&& await this._fixtureHookController.runFixtureBeforeHookIfNecessary(testRun);
if (this.test.skip || !hookOk) {
await this._emitTestRunStart();
await this.emit('test-run-before-done');
await this._emitTestRunDone();
return null;
}
this._assignTestRunEvents(testRun, connection);
testRun.start();
return session_controller_1.default.getSessionUrl(testRun, this._proxy);
}
}
exports.default = TestRunController;
module.exports = exports.default;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdC1ydW4tY29udHJvbGxlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9ydW5uZXIvdGVzdC1ydW4tY29udHJvbGxlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLHVGQUE2RDtBQUM3RCxZQUFZO0FBQ1osNkRBQStEO0FBQy9ELDJEQUFrQztBQUNsQyx3RkFBK0Q7QUFVL0QsZ0VBQTZEO0FBSTdELE1BQU0sb0JBQW9CLEdBQUcsQ0FBQyxDQUFDO0FBRy9CLE1BQXFCLGlCQUFrQixTQUFRLDZCQUFpQjtJQWlCNUQsWUFBb0IsRUFDaEIsSUFBSSxFQUNKLEtBQUssRUFDTCxLQUFLLEVBQ0wsV0FBVyxFQUNYLFVBQVUsRUFDVixxQkFBcUIsRUFDckIsSUFBSSxFQUNKLFdBQVcsRUFDWCxlQUFlLEVBQ2YsVUFBVSxHQUNVO1FBQ3BCLEtBQUssRUFBRSxDQUFDO1FBRVIsSUFBSSxDQUFDLElBQUksR0FBSSxJQUFJLENBQUM7UUFDbEIsSUFBSSxDQUFDLEtBQUssR0FBRyxLQUFLLENBQUM7UUFDbkIsSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUM7UUFFbEIsSUFBSSxDQUFDLE1BQU0sR0FBbUIsS0FBSyxDQUFDO1FBQ3BDLElBQUksQ0FBQyxZQUFZLEdBQWEsV0FBVyxDQUFDO1FBQzFDLElBQUksQ0FBQyxXQUFXLEdBQWMsVUFBVSxDQUFDO1FBQ3pDLElBQUksQ0FBQyxzQkFBc0IsR0FBRyxxQkFBcUIsQ0FBQztRQUNwRCxJQUFJLENBQUMsWUFBWSxHQUFhLFdBQVcsQ0FBQztRQUUxQyxJQUFJLENBQUMsWUFBWSxHQUFHLGlCQUFpQixDQUFDLGVBQWUsQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFFbEUsSUFBSSxDQUFDLE9BQU8sR0FBZSxJQUFJLENBQUM7UUFDaEMsSUFBSSxDQUFDLElBQUksR0FBa0IsS0FBSyxDQUFDO1FBQ2pDLElBQUksQ0FBQyxXQUFXLEdBQVcsSUFBSSxDQUFDLEtB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QUFDO1lBRTlCLE9BQU8sSUFBSSxDQUFDO1NBQ2Y7UUFFRCxJQUFJLENBQUMsb0JBQW9CLENBQUMsT0FBTyxFQUFFLFVBQVUsQ0FBQyxDQUFDO1FBRS9DLE9BQU8sQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUVoQixPQUFPLDRCQUFpQixDQUFDLGFBQWEsQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ2pFLENBQUM7Q0FDSjtBQXRPRCxvQ0FzT0MiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgQXN5bmNFdmVudEVtaXR0ZXIgZnJvbSAnLi4vdXRpbHMvYXN5bmMtZXZlbnQtZW1pdHRlcic7XG4vL0B0cy1pZ25vcmVcbmltcG9ydCB7IFRlc3RSdW4gYXMgTGVnYWN5VGVzdFJ1biB9IGZyb20gJ3Rlc3RjYWZlLWxlZ2FjeS1hcGknO1xuaW1wb3J0IFRlc3RSdW4gZnJvbSAnLi4vdGVzdC1ydW4nO1xuaW1wb3J0IFNlc3Npb25Db250cm9sbGVyIGZyb20gJy4uL3Rlc3QtcnVuL3Nlc3Npb24tY29udHJvbGxlcic7XG5pbXBvcnQgQnJvd3NlckNvbm5lY3Rpb24gZnJvbSAnLi4vYnJvd3Nlci9jb25uZWN0aW9uJztcbmltcG9ydCB7IFByb3h5IH0gZnJvbSAndGVzdGNhZmUtaGFtbWVyaGVhZCc7XG5pbXBvcnQgVGVzdCBmcm9tICcuLi9hcGkvc3RydWN0dXJlL3Rlc3QnO1xuaW1wb3J0IFNjcmVlbnNob3RzIGZyb20gJy4uL3NjcmVlbnNob3RzJztcbmltcG9ydCBXYXJuaW5nTG9nIGZyb20gJy4uL25vdGlmaWNhdGlvbnMvd2FybmluZy1sb2cnO1xuaW1wb3J0IEZpeHR1cmVIb29rQ29udHJvbGxlciBmcm9tICcuL2ZpeHR1cmUtaG9vay1jb250cm9sbGVyJztcbmltcG9ydCB7IERpY3Rpb25hcnkgfSBmcm9tICcuLi9jb25maWd1cmF0aW9uL2ludGVyZmFjZXMnO1xuaW1wb3J0IHsgQWN0aW9uRXZlbnRBcmcsIFRlc3RSdW5Db250cm9sbGVySW5pdCB9IGZyb20gJy4vaW50ZXJmYWNlcyc7XG5pbXBvcnQgQ29tcGlsZXJTZXJ2aWNlIGZyb20gJy4uL3NlcnZpY2VzL2NvbXBpbGVyL2hvc3QnO1xuaW1wb3J0IHsgUXVhcmFudGluZSB9IGZyb20gJy4uL3V0aWxzL2dldC1vcHRpb25zL3F1YXJhbnRpbmUnO1xuaW1wb3J0IE1lc3NhZ2VCdXMgZnJvbSAnLi4vdXRpbHMvbWVzc2FnZS1idXMnO1xuaW1wb3J0IFRlc3RSdW5Ib29rQ29udHJvbGxlciBmcm9tICcuL3Rlc3QtcnVuLWhvb2stY29udHJvbGxlcic7XG5cbmNvbnN0IERJU0NPTk5FQ1RfVEhSRVNIT0xEID0gMztcblxuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBUZXN0UnVuQ29udHJvbGxlciBleHRlbmRzIEFzeW5jRXZlbnRFbWl0dGVyIHtcbiAgICBwcml2YXRlIHJlYWRvbmx5IF9xdWFyYW50aW5lOiBudWxsIHwgUXVhcmFudGluZTtcbiAgICBwcml2YXRlIF9kaXNjb25uZWN0aW9uQ291bnQ6IG51bWJlcjtcbiAgICBwcml2YXRlIHJlYWRvbmx5IF9wcm94eTogUHJveHk7XG4gICAgcHVibGljIHJlYWRvbmx5IGluZGV4OiBudW1iZXI7XG4gICAgcHVibGljIHRlc3Q6IFRlc3Q7XG4gICAgcHJpdmF0ZSByZWFkb25seSBfb3B0czogRGljdGlvbmFyeTxPcHRpb25WYWx1ZT47XG4gICAgcHJpdmF0ZSBfc2NyZWVuc2hvdHM6IFNjcmVlbnNob3RzO1xuICAgIHByaXZhdGUgcmVhZG9ubHkgX3dhcm5pbmdMb2c6IFdhcm5pbmdMb2c7XG4gICAgcHJpdmF0ZSByZWFkb25seSBfZml4dHVyZUhvb2tDb250cm9sbGVyOiBGaXh0dXJlSG9va0NvbnRyb2xsZXI7XG4gICAgcHJpdmF0ZSByZWFkb25seSBfdGVzdFJ1bkN0b3I6IExlZ2FjeVRlc3RSdW5bJ2NvbnN0cnVjdG9yJ10gfCBUZXN0UnVuWydjb25zdHJ1Y3RvciddO1xuICAgIHB1YmxpYyB0ZXN0UnVuOiBudWxsIHwgTGVnYWN5VGVzdFJ1biB8IFRlc3RSdW47XG4gICAgcHVibGljIGRvbmU6IGJvb2xlYW47XG4gICAgcHJpdmF0ZSByZWFkb25seSBjb21waWxlclNlcnZpY2U/OiBDb21waWxlclNlcnZpY2U7XG4gICAgcHJpdmF0ZSByZWFkb25seSBfbWVzc2FnZUJ1czogTWVzc2FnZUJ1cztcbiAgICBwcml2YXRlIHJlYWRvbmx5IF90ZXN0UnVuSG9vazogVGVzdFJ1bkhvb2tDb250cm9sbGVyO1xuXG4gICAgcHVibGljIGNvbnN0cnVjdG9yICh7XG4gICAgICAgIHRlc3QsXG4gICAgICAgIGluZGV4LFxuICAgICAgICBwcm94eSxcbiAgICAgICAgc2NyZWVuc2hvdHMsXG4gICAgICAgIHdhcm5pbmdMb2csXG4gICAgICAgIGZpeHR1cmVIb29rQ29udHJvbGxlcixcbiAgICAgICAgb3B0cyxcbiAgICAgICAgdGVzdFJ1bkhvb2ssXG4gICAgICAgIGNvbXBpbGVyU2VydmljZSxcbiAgICAgICAgbWVzc2FnZUJ1cyxcbiAgICB9OiBUZXN0UnVuQ29udHJvbGxlckluaXQpIHtcbiAgICAgICAgc3VwZXIoKTtcblxuICAgICAgICB0aGlzLnRlc3QgID0gdGVzdDtcbiAgICAgICAgdGhpcy5pbmRleCA9IGluZGV4O1xuICAgICAgICB0aGlzLl9vcHRzID0gb3B0cztcblxuICAgICAgICB0aGlzLl9wcm94eSAgICAgICAgICAgICAgICAgPSBwcm94eTtcbiAgICAgICAgdGhpcy5fc2NyZWVuc2hvdHMgICAgICAgICAgID0gc2NyZWVuc2hvdHM7XG4gICAgICAgIHRoaXMuX3dhcm5pbmdMb2cgICAgICAgICAgICA9IHdhcm5pbmdMb2c7XG4gICAgICAgIHRoaXMuX2ZpeHR1cmVIb29rQ29udHJvbGxlciA9IGZpeHR1cmVIb29rQ29udHJvbGxlcjtcbiAgICAgICAgdGhpcy5fdGVzdFJ1bkhvb2sgICAgICAgICAgID0gdGVzdFJ1bkhvb2s7XG5cbiAgICAgICAgdGhpcy5fdGVzdFJ1bkN0b3IgPSBUZXN0UnVuQ29udHJvbGxlci5fZ2V0VGVzdFJ1bkN0b3IodGVzdCwgb3B0cyk7XG5cbiAgICAgICAgdGhpcy50ZXN0UnVuICAgICAgICAgICAgID0gbnVsbDtcbiAgICAgICAgdGhpcy5kb25lICAgICAgICAgICAgICAgID0gZmFsc2U7XG4gICAgICAgIHRoaXMuX3F1YXJhbnRpbmUgICAgICAgICA9IHRoaXMuX29wdHMucXVhcmFudGluZU1vZGUgPyBuZXcgUXVhcmFudGluZSgpIDogbnVsbDtcbiAgICAgICAgdGhpcy5fZGlzY29ubmVjdGlvbkNvdW50ID0gMDtcbiAgICAgICAgdGhpcy5jb21waWxlclNlcnZpY2UgICAgID0gY29tcGlsZXJTZXJ2aWNlO1xuICAgICAgICB0aGlzLl9tZXNzYWdlQnVzICAgICAgICAgPSBtZXNzYWdlQnVzO1xuICAgIH1cblxuICAgIHByaXZhdGUgc3RhdGljIF9nZXRUZXN0UnVuQ3RvciAodGVzdDogVGVzdCwgb3B0czogRGljdGlvbmFyeTxPcHRpb25WYWx1ZT4pOiBMZWdhY3lUZXN0UnVuIHwgVGVzdFJ1biB7XG4gICAgICAgIGlmIChvcHRzLlRlc3RSdW5DdG9yKVxuICAgICAgICAgICAgcmV0dXJuIG9wdHMuVGVzdFJ1bkN0b3I7XG5cbiAgICAgICAgcmV0dXJuICh0ZXN0IGFzIExlZ2FjeVRlc3RSdW4pLmlzTGVnYWN5ID8gTGVnYWN5VGVzdFJ1biA6IFRlc3RSdW47XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBfY3JlYXRlVGVzdFJ1biAoY29ubmVjdGlvbjogQnJvd3NlckNvbm5lY3Rpb24sIHN0YXJ0UnVuRXhlY3V0aW9uVGltZT86IERhdGUpOiBQcm9taXNlPFRlc3RSdW4gfCBMZWdhY3lUZXN0UnVuPiB7XG4gICAgICAgIGNvbnN0IHNjcmVlbnNob3RDYXB0dXJlciA9IHRoaXMuX3NjcmVlbnNob3RzLmNyZWF0ZUNhcHR1cmVyRm9yKHRoaXMudGVzdCwgdGhpcy5pbmRleCwgdGhpcy5fcXVhcmFudGluZSwgY29ubmVjdGlvbiwgdGhpcy5fd2FybmluZ0xvZyk7XG4gICAgICAgIGNvbnN0IFRlc3RSdW5DdG9yICAgICAgICA9IHRoaXMuX3Rlc3RSdW5DdG9yO1xuXG4gICAgICAgIHRoaXMudGVzdFJ1biA9IG5ldyBUZXN0UnVuQ3Rvcih7XG4gICAgICAgICAgICB0ZXN0OiAgICAgICAgICAgICAgdGhpcy50ZXN0LFxuICAgICAgICAgICAgYnJvd3NlckNvbm5lY3Rpb246IGNvbm5lY3Rpb24sXG4gICAgICAgICAgICBnbG9iYWxXYXJuaW5nTG9nOiAgdGhpcy5fd2FybmluZ0xvZyxcbiAgICAgICAgICAgIG9wdHM6ICAgICAgICAgICAgICB0aGlzLl9vcHRzLFxuICAgICAgICAgICAgY29tcGlsZXJTZXJ2aWNlOiAgIHRoaXMuY29tcGlsZXJTZXJ2aWNlLFxuICAgICAgICAgICAgbWVzc2FnZUJ1czogICAgICAgIHRoaXMuX21lc3NhZ2VCdXMsXG4gICAgICAgICAgICBzY3JlZW5zaG90Q2FwdHVyZXIsXG4gICAgICAgICAgICBzdGFydFJ1bkV4ZWN1dGlvblRpbWUsXG4gICAgICAgIH0pO1xuXG4gICAgICAgIGF3YWl0IHRoaXMudGVzdFJ1bi5pbml0aWFsaXplKCk7XG5cbiAgICAgICAgdGhpcy5fc2NyZWVuc2hvdHMuYWRkVGVzdFJ1bih0aGlzLnRlc3QsIHRoaXMudGVzdFJ1bik7XG5cbiAgICAgICAgaWYgKHRoaXMudGVzdFJ1bi5hZGRRdWFyYW50aW5lSW5mbylcbiAgICAgICAgICAgIHRoaXMudGVzdFJ1bi5hZGRRdWFyYW50aW5lSW5mbyh0aGlzLl9xdWFyYW50aW5lKTtcblxuICAgICAgICBpZiAodGhpcy5fcXVhcmFudGluZSkge1xuICAgICAgICAgICAgY29uc3QgeyBzdWNjZXNzVGhyZXNob2xkLCBhdHRlbXB0TGltaXQgfSA9IHRoaXMuX29wdHMucXVhcmFudGluZU1vZGUgYXMgUXVhcmFudGluZU9wdGlvblZhbHVlO1xuXG4gICAgICAgICAgICB0aGlzLl9xdWFyYW50aW5lLnNldEN1c3RvbVBhcmFtZXRlcnMoYXR0ZW1wdExpbWl0LCBzdWNjZXNzVGhyZXNob2xkKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghdGhpcy5fcXVhcmFudGluZSB8fCB0aGlzLl9pc0ZpcnN0UXVhcmFudGluZUF0dGVtcHQoKSkge1xuICAgICAgICAgICAgYXdhaXQgdGhpcy5lbWl0KCd0ZXN0LXJ1bi1jcmVhdGUnLCB7XG4gICAgICAgICAgICAgICAgdGVzdFJ1bjogICAgdGhpcy50ZXN0UnVuLFxuICAgICAgICAgICAgICAgIGxlZ2FjeTogICAgIFRlc3RSdW5DdG9yID09PSBMZWdhY3lUZXN0UnVuLFxuICAgICAgICAgICAgICAgIHRlc3Q6ICAgICAgIHRoaXMudGVzdCxcbiAgICAgICAgICAgICAgICBpbmRleDogICAgICB0aGlzLmluZGV4LFxuICAgICAgICAgICAgICAgIHF1YXJhbnRpbmU6IHRoaXMuX3F1YXJhbnRpbmUsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0aGlzLnRlc3RSdW47XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBfZW5kUXVhcmFudGluZSAoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGlmICgodGhpcy5fcXVhcmFudGluZSBhcyBRdWFyYW50aW5lKS5hdHRlbXB0cy5sZW5ndGggPiAxKVxuICAgICAgICAgICAgdGhpcy50ZXN0UnVuLnVuc3RhYmxlID0gKHRoaXMuX3F1YXJhbnRpbmUgYXMgUXVhcmFudGluZSkuZ2V0UGFzc2VkQXR0ZW1wdHMoKS5sZW5ndGggPiAwO1xuXG4gICAgICAgIGF3YWl0IHRoaXMuX2VtaXRUZXN0UnVuRG9uZSgpO1xuICAgIH1cblxuICAgIHByaXZhdGUgX3Nob3VsZEtlZXBJblF1YXJhbnRpbmUgKCk6IGJvb2xlYW4ge1xuICAgICAgICBjb25zdCBlcnJvcnMgICAgICAgICA9IHRoaXMudGVzdFJ1bi5lcnJzO1xuICAgICAgICBjb25zdCBoYXNFcnJvcnMgICAgICA9ICEhZXJyb3JzLmxlbmd0aDtcbiAgICAgICAgY29uc3QgYXR0ZW1wdHMgICAgICAgPSAodGhpcy5fcXVhcmFudGluZSBhcyBRdWFyYW50aW5lKS5hdHRlbXB0cztcbiAgICAgICAgY29uc3QgaXNGaXJzdEF0dGVtcHQgPSB0aGlzLl9pc0ZpcnN0UXVhcmFudGluZUF0dGVtcHQoKTtcblxuICAgICAgICBhdHRlbXB0cy5wdXNoKHsgdGVzdFJ1bklkOiB0aGlzLnRlc3RSdW4uaWQsIGVycm9ycyB9KTtcblxuICAgICAgICByZXR1cm4gaXNGaXJzdEF0dGVtcHQgPyBoYXNFcnJvcnMgOiAhKHRoaXMuX3F1YXJhbnRpbmUgYXMgUXVhcmFudGluZSkuaXNUaHJlc2hvbGRSZWFjaGVkKCk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBfaXNGaXJzdFF1YXJhbnRpbmVBdHRlbXB0ICgpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuICEhdGhpcy5fcXVhcmFudGluZSAmJiAhdGhpcy5fcXVhcmFudGluZS5hdHRlbXB0cy5sZW5ndGg7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBfa2VlcEluUXVhcmFudGluZSAoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGF3YWl0IHRoaXMuX3Jlc3RhcnRUZXN0KCk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBfcmVzdGFydFRlc3QgKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBhd2FpdCB0aGlzLmVtaXQoJ3Rlc3QtcnVuLXJlc3RhcnQnKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIF90ZXN0UnVuRG9uZUluUXVhcmFudGluZU1vZGUgKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBpZiAodGhpcy5fc2hvdWxkS2VlcEluUXVhcmFudGluZSgpKVxuICAgICAgICAgICAgYXdhaXQgdGhpcy5fa2VlcEluUXVhcmFudGluZSgpO1xuICAgICAgICBlbHNlXG4gICAgICAgICAgICBhd2FpdCB0aGlzLl9lbmRRdWFyYW50aW5lKCk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBfdGVzdFJ1bkRvbmUgKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBpZiAodGhpcy5fcXVhcmFudGluZSlcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuX3Rlc3RSdW5Eb25lSW5RdWFyYW50aW5lTW9kZSgpO1xuICAgICAgICBlbHNlXG4gICAgICAgICAgICBhd2FpdCB0aGlzLl9lbWl0VGVzdFJ1bkRvbmUoKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIF9lbWl0QWN0aW9uU3RhcnQgKGFyZ3M6IEFjdGlvbkV2ZW50QXJnKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGF3YWl0IHRoaXMuX21lc3NhZ2VCdXMuZW1pdCgndGVzdC1hY3Rpb24tc3RhcnQnLCBhcmdzKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIF9lbWl0QWN0aW9uRG9uZSAoYXJnczogQWN0aW9uRXZlbnRBcmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgYXdhaXQgdGhpcy5lbWl0KCd0ZXN0LWFjdGlvbi1kb25lJywgYXJncyk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBfZW1pdFRlc3RSdW5Eb25lICgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgLy8gTk9URTogd2Ugc2hvdWxkIHJlcG9ydCB0ZXN0IHJ1biBjb21wbGV0aW9uIGluIG9yZGVyIHRoZXkgd2VyZSBjb21wbGV0ZWQgaW4gYnJvd3Nlci5cbiAgICAgICAgLy8gVG8ga2VlcCBhIHNlcXVlbmNlIGFmdGVyIGZpeHR1cmUgaG9vayBleGVjdXRpb24gd2UgdXNlIGNvbXBsZXRpb24gcXVldWUuXG4gICAgICAgIGF3YWl0IHRoaXMuX2ZpeHR1cmVIb29rQ29udHJvbGxlci5ydW5GaXh0dXJlQWZ0ZXJIb29rSWZOZWNlc3NhcnkodGhpcy50ZXN0UnVuKTtcbiAgICAgICAgYXdhaXQgdGhpcy5fdGVzdFJ1bkhvb2sucnVuVGVzdFJ1bkFmdGVySG9va0lmTmVjZXNzYXJ5KHRoaXMudGVzdFJ1bik7XG5cbiAgICAgICAgdGhpcy5kb25lID0gdHJ1ZTtcblxuICAgICAgICBhd2FpdCB0aGlzLmVtaXQoJ3Rlc3QtcnVuLWRvbmUnKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIF9lbWl0VGVzdFJ1blN0YXJ0ICgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgYXdhaXQgdGhpcy5fbWVzc2FnZUJ1cy5lbWl0KCd0ZXN0LXJ1bi1zdGFydCcsIHRoaXMudGVzdFJ1bik7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBfdGVzdFJ1bkJlZm9yZURvbmUgKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBsZXQgcmFpc2VFdmVudCA9ICF0aGlzLl9xdWFyYW50aW5lO1xuXG4gICAgICAgIGlmICghcmFpc2VFdmVudCkge1xuICAgICAgICAgICAgY29uc3QgaXNTdWNjZXNzZnVsUXVhcmFudGluZUZpcnN0QXR0ZW1wdCA9IHRoaXMuX2lzRmlyc3RRdWFyYW50aW5lQXR0ZW1wdCgpICYmICF0aGlzLnRlc3RSdW4uZXJycy5sZW5ndGg7XG4gICAgICAgICAgICBjb25zdCBpc0F0dGVtcHRzVGhyZXNob2xkUmVhY2hlZCAgICAgICAgID0gKHRoaXMuX3F1YXJhbnRpbmUgYXMgUXVhcmFudGluZSkuaXNUaHJlc2hvbGRSZWFjaGVkKHRoaXMudGVzdFJ1bi5lcnJzKTtcblxuICAgICAgICAgICAgcmFpc2VFdmVudCA9IGlzU3VjY2Vzc2Z1bFF1YXJhbnRpbmVGaXJzdEF0dGVtcHQgfHwgaXNBdHRlbXB0c1RocmVzaG9sZFJlYWNoZWQ7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAocmFpc2VFdmVudClcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuZW1pdCgndGVzdC1ydW4tYmVmb3JlLWRvbmUnKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIF90ZXN0UnVuRGlzY29ubmVjdGVkIChjb25uZWN0aW9uOiBCcm93c2VyQ29ubmVjdGlvbik6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICB0aGlzLl9kaXNjb25uZWN0aW9uQ291bnQrKztcblxuICAgICAgICBjb25zdCBkaXNjb25uZWN0aW9uVGhyZXNob2xkRXhjZWVkZWVkID0gdGhpcy5fZGlzY29ubmVjdGlvbkNvdW50ID49IERJU0NPTk5FQ1RfVEhSRVNIT0xEO1xuXG4gICAgICAgIHJldHVybiBjb25uZWN0aW9uXG4gICAgICAgICAgICAucHJvY2Vzc0Rpc2Nvbm5lY3Rpb24oZGlzY29ubmVjdGlvblRocmVzaG9sZEV4Y2VlZGVlZClcbiAgICAgICAgICAgIC50aGVuKCgpID0+IHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5fcmVzdGFydFRlc3QoKTtcbiAgICAgICAgICAgIH0pO1xuICAgIH1cblxuICAgIHByaXZhdGUgX2Fzc2lnblRlc3RSdW5FdmVudHMgKHRlc3RSdW46IFRlc3RSdW4gfCBMZWdhY3lUZXN0UnVuLCBjb25uZWN0aW9uOiBCcm93c2VyQ29ubmVjdGlvbik6IHZvaWQge1xuICAgICAgICB0ZXN0UnVuLm9uKCdhY3Rpb24tc3RhcnQnLCBhc3luYyAoYXJnczogQWN0aW9uRXZlbnRBcmcpID0+IHRoaXMuX2VtaXRBY3Rpb25TdGFydChPYmplY3QuYXNzaWduKGFyZ3MsIHsgdGVzdFJ1biB9KSkpO1xuICAgICAgICB0ZXN0UnVuLm9uKCdhY3Rpb24tZG9uZScsIGFzeW5jIChhcmdzOiBBY3Rpb25FdmVudEFyZykgPT4gdGhpcy5fZW1pdEFjdGlvbkRvbmUoT2JqZWN0LmFzc2lnbihhcmdzLCB7IHRlc3RSdW4gfSkpKTtcblxuICAgICAgICB0ZXN0UnVuLm9uY2UoJ3N0YXJ0JywgYXN5bmMgKCkgPT4gdGhpcy5fZW1pdFRlc3RSdW5TdGFydCgpKTtcbiAgICAgICAgdGVzdFJ1bi5vbmNlKCdyZWFkeScsIGFzeW5jICgpID0+IHtcbiAgICAgICAgICAgIGlmICghdGhpcy5fcXVhcmFudGluZSB8fCB0aGlzLl9pc0ZpcnN0UXVhcmFudGluZUF0dGVtcHQoKSlcbiAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLmVtaXQoJ3Rlc3QtcnVuLXJlYWR5Jyk7XG4gICAgICAgIH0pO1xuICAgICAgICB0ZXN0UnVuLm9uY2UoJ2JlZm9yZS1kb25lJywgKCkgPT4gdGhpcy5fdGVzdFJ1bkJlZm9yZURvbmUoKSk7XG4gICAgICAgIHRlc3RSdW4ub25jZSgnZG9uZScsICgpID0+IHRoaXMuX3Rlc3RSdW5Eb25lKCkpO1xuICAgICAgICB0ZXN0UnVuLm9uY2UoJ2Rpc2Nvbm5lY3RlZCcsICgpID0+IHRoaXMuX3Rlc3RSdW5EaXNjb25uZWN0ZWQoY29ubmVjdGlvbikpO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXQgYmxvY2tlZCAoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0aGlzLl9maXh0dXJlSG9va0NvbnRyb2xsZXIuaXNUZXN0QmxvY2tlZCh0aGlzLnRlc3QpO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBzdGFydCAoY29ubmVjdGlvbjogQnJvd3NlckNvbm5lY3Rpb24sIHN0YXJ0UnVuRXhlY3V0aW9uVGltZT86IERhdGUpOiBQcm9taXNlPHN0cmluZyB8IG51bGw+IHtcbiAgICAgICAgY29uc3QgdGVzdFJ1biA9IGF3YWl0IHRoaXMuX2NyZWF0ZVRlc3RSdW4oY29ubmVjdGlvbiwgc3RhcnRSdW5FeGVjdXRpb25UaW1lKTtcblxuICAgICAgICBjb25zdCBob29rT2sgPSBhd2FpdCB0aGlzLl90ZXN0UnVuSG9vay5ydW5UZXN0UnVuQmVmb3JlSG9va0lmTmVjZXNzYXJ5KHRlc3RSdW4pXG4gICAgICAgICAgICAgICAgICAgICAgICYmIGF3YWl0IHRoaXMuX2ZpeHR1cmVIb29rQ29udHJvbGxlci5ydW5GaXh0dXJlQmVmb3JlSG9va0lmTmVjZXNzYXJ5KHRlc3RSdW4pO1xuXG4gICAgICAgIGlmICh0aGlzLnRlc3Quc2tpcCB8fCAhaG9va09rKSB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLl9lbWl0VGVzdFJ1blN0YXJ0KCk7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLmVtaXQoJ3Rlc3QtcnVuLWJlZm9yZS1kb25lJyk7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLl9lbWl0VGVzdFJ1bkRvbmUoKTtcblxuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLl9hc3NpZ25UZXN0UnVuRXZlbnRzKHRlc3RSdW4sIGNvbm5lY3Rpb24pO1xuXG4gICAgICAgIHRlc3RSdW4uc3RhcnQoKTtcblxuICAgICAgICByZXR1cm4gU2Vzc2lvbkNvbnRyb2xsZXIuZ2V0U2Vzc2lvblVybCh0ZXN0UnVuLCB0aGlzLl9wcm94eSk7XG4gICAgfVxufVxuIl19