UNPKG

testcafe

Version:

Automated browser testing for the modern web development stack.

232 lines 36.5 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; 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 testcafe_hammerhead_1 = require("testcafe-hammerhead"); const quarantine_1 = require("../utils/get-options/quarantine"); const clientScriptsRouting = __importStar(require("../custom-client-scripts/routing")); const types_1 = require("../errors/types"); const runtime_1 = require("../errors/runtime"); const debug_loggers_1 = require("../utils/debug-loggers"); const DISCONNECT_THRESHOLD = 3; class TestRunController extends async_event_emitter_1.default { constructor({ test, index, proxy, screenshots, warningLog, fixtureHookController, opts, testRunHook, messageBus, }) { super(); this.clientScriptRoutes = []; this.isNativeAutomation = false; this.test = test; this.index = index; this._opts = opts; this.id = (0, testcafe_hammerhead_1.generateUniqueId)(); 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._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, messageBus: this._messageBus, nativeAutomation: this.isNativeAutomation, screenshotCapturer, startRunExecutionTime, }); this.clientScriptRoutes = clientScriptsRouting.register({ proxy: this._proxy, test: this.test, nativeAutomation: this.isNativeAutomation, folderName: this.testRun.id, }); if (this.isNativeAutomation) connection.resetActiveWindowId(); 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); clientScriptsRouting.unRegister(this._proxy, this.clientScriptRoutes); this.done = true; await this.emit('test-run-done'); (0, debug_loggers_1.testRunControllerLogger)('done %s', this.id); } 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 disconnectionThresholdExceeded = this._disconnectionCount >= DISCONNECT_THRESHOLD; return connection .processDisconnection(disconnectionThresholdExceeded) .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 _handleNativeAutomationMode(connection) { this.isNativeAutomation = !this._opts.disableNativeAutomation; const supportNativeAutomation = connection.supportNativeAutomation(); if (!this.isNativeAutomation || supportNativeAutomation) return; await this._messageBus.emit('before-test-run-created-error'); throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.setNativeAutomationForUnsupportedBrowsers, connection.browserInfo.providerName); } async start(connection, startRunExecutionTime) { (0, debug_loggers_1.testRunControllerLogger)('start %s %O %O', this.id, { test: { name: this.test.name, id: this.test.id, }, connection: { userAgent: connection.userAgent, id: connection.id, }, }); await this._handleNativeAutomationMode(connection); this._fixtureHookController.blockTestIfNecessary(this.test); const testRun = await this._createTestRun(connection, startRunExecutionTime); const hookOk = await this._testRunHook.runTestRunBeforeHookIfNecessary(testRun) && await this._fixtureHookController.runFixtureBeforeHookIfNecessary(testRun); this._fixtureHookController.unblockTest(this.test); 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdC1ydW4tY29udHJvbGxlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9ydW5uZXIvdGVzdC1ydW4tY29udHJvbGxlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsdUZBQTZEO0FBQzdELFlBQVk7QUFDWiw2REFBK0Q7QUFDL0QsMkRBQWtDO0FBQ2xDLHdGQUErRDtBQUUvRCw2REFBOEQ7QUFPOUQsZ0VBQTZEO0FBRzdELHVGQUF5RTtBQUN6RSwyQ0FBaUQ7QUFDakQsK0NBQWlEO0FBQ2pELDBEQUFpRTtBQUVqRSxNQUFNLG9CQUFvQixHQUFHLENBQUMsQ0FBQztBQUUvQixNQUFxQixpQkFBa0IsU0FBUSw2QkFBaUI7SUFtQjVELFlBQW9CLEVBQ2hCLElBQUksRUFDSixLQUFLLEVBQ0wsS0FBSyxFQUNMLFdBQVcsRUFDWCxVQUFVLEVBQ1YscUJBQXFCLEVBQ3JCLElBQUksRUFDSixXQUFXLEVBQ1gsVUFBVSxHQUNVO1FBQ3BCLEtBQUssRUFBRSxDQUFDO1FBZkosdUJBQWtCLEdBQWEsRUFBRSxDQUFDO1FBQ2xDLHVCQUFrQixHQUFHLEtBQUssQ0FBQztRQWdCL0IsSUFBSSxDQUFDLElBQUksR0FBSSxJQUFJLENBQUM7UUFDbEIsSUFBSSxDQUFDLEtBQUssR0FBRyxLQUFLLENBQUM7UUFDbkIsSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUM7UUFDbEIsSUFBSSxDQUFDLEVBQUUsR0FBTSxJQUFBLHNDQUFnQixHQUFFLENBQUM7UUFFaEMsSUFBSSxDQUFDLE1BQU0sR0FBbUIsS0FBSyxDQUFDO1FBQ3BDLElBQUksQ0FBQyxZQUFZLEdBQWEsV0FBVyxDQUFDO1FBQzFDLElBQUksQ0FBQyxXQUFXLEdBQWMsVUFBVSxDQUFDO1FBQ3pDLElBQUksQ0FBQyxzQkFBc0IsR0FBRyxxQkFBcUIsQ0FBQztRQUNwRCxJQUFJLENBQUMsWUFBWSxHQUFhLFdBQVcsQ0FBQztR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QUU1RCxNQUFNLE9BQU8sR0FBRyxNQUFNLElBQUksQ0FBQyxjQUFjLENBQUMsVUFBVSxFQUFFLHFCQUFxQixDQUFDLENBQUM7UUFFN0UsTUFBTSxNQUFNLEdBQUcsTUFBTSxJQUFJLENBQUMsWUFBWSxDQUFDLCtCQUErQixDQUFDLE9BQU8sQ0FBQztlQUM3RCxNQUFNLElBQUksQ0FBQyxzQkFBc0IsQ0FBQywrQkFBK0IsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUU3RixJQUFJLENBQUMsc0JBQXNCLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUVuRCxJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxJQUFJLENBQUMsTUFBTSxFQUFFO1lBQzNCLE1BQU0sSUFBSSxDQUFDLGlCQUFpQixFQUFFLENBQUM7WUFDL0IsTUFBTSxJQUFJLENBQUMsSUFBSSxDQUFDLHNCQUFzQixDQUFDLENBQUM7WUFDeEMsTUFBTSxJQUFJLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztZQUU5QixPQUFPLElBQUksQ0FBQztTQUNmO1FBRUQsSUFBSSxDQUFDLG9CQUFvQixDQUFDLE9BQU8sRUFBRSxVQUFVLENBQUMsQ0FBQztRQUUvQyxPQUFPLENBQUMsS0FBSyxFQUFFLENBQUM7UUFFaEIsT0FBTyw0QkFBaUIsQ0FBQyxhQUFhLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUNqRSxDQUFDO0NBQ0o7QUFuUkQsb0NBbVJDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IEFzeW5jRXZlbnRFbWl0dGVyIGZyb20gJy4uL3V0aWxzL2FzeW5jLWV2ZW50LWVtaXR0ZXInO1xuLy9AdHMtaWdub3JlXG5pbXBvcnQgeyBUZXN0UnVuIGFzIExlZ2FjeVRlc3RSdW4gfSBmcm9tICd0ZXN0Y2FmZS1sZWdhY3ktYXBpJztcbmltcG9ydCBUZXN0UnVuIGZyb20gJy4uL3Rlc3QtcnVuJztcbmltcG9ydCBTZXNzaW9uQ29udHJvbGxlciBmcm9tICcuLi90ZXN0LXJ1bi9zZXNzaW9uLWNvbnRyb2xsZXInO1xuaW1wb3J0IEJyb3dzZXJDb25uZWN0aW9uIGZyb20gJy4uL2Jyb3dzZXIvY29ubmVjdGlvbic7XG5pbXBvcnQgeyBQcm94eSwgZ2VuZXJhdGVVbmlxdWVJZCB9IGZyb20gJ3Rlc3RjYWZlLWhhbW1lcmhlYWQnO1xuaW1wb3J0IFRlc3QgZnJvbSAnLi4vYXBpL3N0cnVjdHVyZS90ZXN0JztcbmltcG9ydCBTY3JlZW5zaG90cyBmcm9tICcuLi9zY3JlZW5zaG90cyc7XG5pbXBvcnQgV2FybmluZ0xvZyBmcm9tICcuLi9ub3RpZmljYXRpb25zL3dhcm5pbmctbG9nJztcbmltcG9ydCBGaXh0dXJlSG9va0NvbnRyb2xsZXIgZnJvbSAnLi9maXh0dXJlLWhvb2stY29udHJvbGxlcic7XG5pbXBvcnQgeyBEaWN0aW9uYXJ5IH0gZnJvbSAnLi4vY29uZmlndXJhdGlvbi9pbnRlcmZhY2VzJztcbmltcG9ydCB7IEFjdGlvbkV2ZW50QXJnLCBUZXN0UnVuQ29udHJvbGxlckluaXQgfSBmcm9tICcuL2ludGVyZmFjZXMnO1xuaW1wb3J0IHsgUXVhcmFudGluZSB9IGZyb20gJy4uL3V0aWxzL2dldC1vcHRpb25zL3F1YXJhbnRpbmUnO1xuaW1wb3J0IE1lc3NhZ2VCdXMgZnJvbSAnLi4vdXRpbHMvbWVzc2FnZS1idXMnO1xuaW1wb3J0IFRlc3RSdW5Ib29rQ29udHJvbGxlciBmcm9tICcuL3Rlc3QtcnVuLWhvb2stY29udHJvbGxlcic7XG5pbXBvcnQgKiBhcyBjbGllbnRTY3JpcHRzUm91dGluZyBmcm9tICcuLi9jdXN0b20tY2xpZW50LXNjcmlwdHMvcm91dGluZyc7XG5pbXBvcnQgeyBSVU5USU1FX0VSUk9SUyB9IGZyb20gJy4uL2Vycm9ycy90eXBlcyc7XG5pbXBvcnQgeyBHZW5lcmFsRXJyb3IgfSBmcm9tICcuLi9lcnJvcnMvcnVudGltZSc7XG5pbXBvcnQgeyB0ZXN0UnVuQ29udHJvbGxlckxvZ2dlciB9IGZyb20gJy4uL3V0aWxzL2RlYnVnLWxvZ2dlcnMnO1xuXG5jb25zdCBESVNDT05ORUNUX1RIUkVTSE9MRCA9IDM7XG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFRlc3RSdW5Db250cm9sbGVyIGV4dGVuZHMgQXN5bmNFdmVudEVtaXR0ZXIge1xuICAgIHByaXZhdGUgcmVhZG9ubHkgX3F1YXJhbnRpbmU6IG51bGwgfCBRdWFyYW50aW5lO1xuICAgIHByaXZhdGUgX2Rpc2Nvbm5lY3Rpb25Db3VudDogbnVtYmVyO1xuICAgIHByaXZhdGUgcmVhZG9ubHkgX3Byb3h5OiBQcm94eTtcbiAgICBwdWJsaWMgcmVhZG9ubHkgaW5kZXg6IG51bWJlcjtcbiAgICBwdWJsaWMgdGVzdDogVGVzdDtcbiAgICBwcml2YXRlIHJlYWRvbmx5IF9vcHRzOiBEaWN0aW9uYXJ5PE9wdGlvblZhbHVlPjtcbiAgICBwcml2YXRlIF9zY3JlZW5zaG90czogU2NyZWVuc2hvdHM7XG4gICAgcHJpdmF0ZSByZWFkb25seSBfd2FybmluZ0xvZzogV2FybmluZ0xvZztcbiAgICBwcml2YXRlIHJlYWRvbmx5IF9maXh0dXJlSG9va0NvbnRyb2xsZXI6IEZpeHR1cmVIb29rQ29udHJvbGxlcjtcbiAgICBwcml2YXRlIHJlYWRvbmx5IF90ZXN0UnVuQ3RvcjogTGVnYWN5VGVzdFJ1blsnY29uc3RydWN0b3InXSB8IFRlc3RSdW5bJ2NvbnN0cnVjdG9yJ107XG4gICAgcHVibGljIHRlc3RSdW46IG51bGwgfCBMZWdhY3lUZXN0UnVuIHwgVGVzdFJ1bjtcbiAgICBwdWJsaWMgZG9uZTogYm9vbGVhbjtcbiAgICBwcml2YXRlIHJlYWRvbmx5IF9tZXNzYWdlQnVzOiBNZXNzYWdlQnVzO1xuICAgIHByaXZhdGUgcmVhZG9ubHkgX3Rlc3RSdW5Ib29rOiBUZXN0UnVuSG9va0NvbnRyb2xsZXI7XG4gICAgcHJpdmF0ZSBjbGllbnRTY3JpcHRSb3V0ZXM6IHN0cmluZ1tdID0gW107XG4gICAgcHJpdmF0ZSBpc05hdGl2ZUF1dG9tYXRpb24gPSBmYWxzZTtcbiAgICBwdWJsaWMgcmVhZG9ubHkgaWQ6IHN0cmluZztcblxuICAgIHB1YmxpYyBjb25zdHJ1Y3RvciAoe1xuICAgICAgICB0ZXN0LFxuICAgICAgICBpbmRleCxcbiAgICAgICAgcHJveHksXG4gICAgICAgIHNjcmVlbnNob3RzLFxuICAgICAgICB3YXJuaW5nTG9nLFxuICAgICAgICBmaXh0dXJlSG9va0NvbnRyb2xsZXIsXG4gICAgICAgIG9wdHMsXG4gICAgICAgIHRlc3RSdW5Ib29rLFxuICAgICAgICBtZXNzYWdlQnVzLFxuICAgIH06IFRlc3RSdW5Db250cm9sbGVySW5pdCkge1xuICAgICAgICBzdXBlcigpO1xuXG4gICAgICAgIHRoaXMudGVzdCAgPSB0ZXN0O1xuICAgICAgICB0aGlzLmluZGV4ID0gaW5kZXg7XG4gICAgICAgIHRoaXMuX29wdHMgPSBvcHRzO1xuICAgICAgICB0aGlzLmlkICAgID0gZ2VuZXJhdGVVbmlxdWVJZCgpO1xuXG4gICAgICAgIHRoaXMuX3Byb3h5ICAgICAgICAgICAgICAgICA9IHByb3h5O1xuICAgICAgICB0aGlzLl9zY3JlZW5zaG90cyAgICAgICAgICAgPSBzY3JlZW5zaG90cztcbiAgICAgICAgdGhpcy5fd2FybmluZ0xvZyAgICAgICAgICAgID0gd2FybmluZ0xvZztcbiAgICAgICAgdGhpcy5fZml4dHVyZUhvb2tDb250cm9sbGVyID0gZml4dHVyZUhvb2tDb250cm9sbGVyO1xuICAgICAgICB0aGlzLl90ZXN0UnVuSG9vayAgICAgICAgICAgPSB0ZXN0UnVuSG9vaztcblxuICAgICAgICB0aGlzLl90ZXN0UnVuQ3RvciA9IFRlc3RSdW5Db250cm9sbGVyLl9nZXRUZXN0UnVuQ3Rvcih0ZXN0LCBvcHRzKTtcblxuICAgICAgICB0aGlzLnRlc3RSdW4gICAgICAgICAgICAgPSBudWxsO1xuICAgICAgICB0aGlzLmRvbmUgICAgICAgICAgICAgICAgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5fcXVhcmFudGluZSAgICAgICAgID0gdGhpcy5fb3B0cy5xdWFyYW50aW5lTW9kZSA/IG5ldyBRdWFyYW50aW5lKCkgOiBudWxsO1xuICAgICAgICB0aGlzLl9kaXNjb25uZWN0aW9uQ291bnQgPSAwO1xuICAgICAgICB0aGlzLl9tZXNzYWdlQnVzICAgICAgICAgPSBtZXNzYWdlQnVzO1xuICAgIH1cblxuICAgIHByaXZhdGUgc3RhdGljIF9nZXRUZXN0UnVuQ3RvciAodGVzdDogVGVzdCwgb3B0czogRGljdGlvbmFyeTxPcHRpb25WYWx1ZT4pOiBMZWdhY3lUZXN0UnVuIHwgVGVzdFJ1biB7XG4gICAgICAgIGlmIChvcHRzLlRlc3RSdW5DdG9yKVxuICAgICAgICAgICAgcmV0dXJuIG9wdHMuVGVzdFJ1bkN0b3I7XG5cbiAgICAgICAgcmV0dXJuICh0ZXN0IGFzIExlZ2FjeVRlc3RSdW4pLmlzTGVnYWN5ID8gTGVnYWN5VGVzdFJ1biA6IFRlc3RSdW47XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBfY3JlYXRlVGVzdFJ1biAoY29ubmVjdGlvbjogQnJvd3NlckNvbm5lY3Rpb24sIHN0YXJ0UnVuRXhlY3V0aW9uVGltZT86IERhdGUpOiBQcm9taXNlPFRlc3RSdW4gfCBMZWdhY3lUZXN0UnVuPiB7XG4gICAgICAgIGNvbnN0IHNjcmVlbnNob3RDYXB0dXJlciA9IHRoaXMuX3NjcmVlbnNob3RzLmNyZWF0ZUNhcHR1cmVyRm9yKHRoaXMudGVzdCwgdGhpcy5pbmRleCwgdGhpcy5fcXVhcmFudGluZSwgY29ubmVjdGlvbiwgdGhpcy5fd2FybmluZ0xvZyk7XG4gICAgICAgIGNvbnN0IFRlc3RSdW5DdG9yICAgICAgICA9IHRoaXMuX3Rlc3RSdW5DdG9yO1xuXG4gICAgICAgIHRoaXMudGVzdFJ1biA9IG5ldyBUZXN0UnVuQ3Rvcih7XG4gICAgICAgICAgICB0ZXN0OiAgICAgICAgICAgICAgdGhpcy50ZXN0LFxuICAgICAgICAgICAgYnJvd3NlckNvbm5lY3Rpb246IGNvbm5lY3Rpb24sXG4gICAgICAgICAgICBnbG9iYWxXYXJuaW5nTG9nOiAgdGhpcy5fd2FybmluZ0xvZyxcbiAgICAgICAgICAgIG9wdHM6ICAgICAgICAgICAgICB0aGlzLl9vcHRzLFxuICAgICAgICAgICAgbWVzc2FnZUJ1czogICAgICAgIHRoaXMuX21lc3NhZ2VCdXMsXG4gICAgICAgICAgICBuYXRpdmVBdXRvbWF0aW9uOiAgdGhpcy5pc05hdGl2ZUF1dG9tYXRpb24sXG4gICAgICAgICAgICBzY3JlZW5zaG90Q2FwdHVyZXIsXG4gICAgICAgICAgICBzdGFydFJ1bkV4ZWN1dGlvblRpbWUsXG4gICAgICAgIH0pO1xuXG4gICAgICAgIHRoaXMuY2xpZW50U2NyaXB0Um91dGVzID0gY2xpZW50U2NyaXB0c1JvdXRpbmcucmVnaXN0ZXIoe1xuICAgICAgICAgICAgcHJveHk6ICAgICAgICAgICAgdGhpcy5fcHJveHksXG4gICAgICAgICAgICB0ZXN0OiAgICAgICAgICAgICB0aGlzLnRlc3QsXG4gICAgICAgICAgICBuYXRpdmVBdXRvbWF0aW9uOiB0aGlzLmlzTmF0aXZlQXV0b21hdGlvbixcbiAgICAgICAgICAgIGZvbGRlck5hbWU6ICAgICAgIHRoaXMudGVzdFJ1bi5pZCxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaWYgKHRoaXMuaXNOYXRpdmVBdXRvbWF0aW9uKVxuICAgICAgICAgICAgY29ubmVjdGlvbi5yZXNldEFjdGl2ZVdpbmRvd0lkKCk7XG5cbiAgICAgICAgYXdhaXQgdGhpcy50ZXN0UnVuLmluaXRpYWxpemUoKTtcblxuICAgICAgICB0aGlzLl9zY3JlZW5zaG90cy5hZGRUZXN0UnVuKHRoaXMudGVzdCwgdGhpcy50ZXN0UnVuKTtcblxuICAgICAgICBpZiAodGhpcy50ZXN0UnVuLmFkZFF1YXJhbnRpbmVJbmZvKVxuICAgICAgICAgICAgdGhpcy50ZXN0UnVuLmFkZFF1YXJhbnRpbmVJbmZvKHRoaXMuX3F1YXJhbnRpbmUpO1xuXG4gICAgICAgIGlmICh0aGlzLl9xdWFyYW50aW5lKSB7XG4gICAgICAgICAgICBjb25zdCB7IHN1Y2Nlc3NUaHJlc2hvbGQsIGF0dGVtcHRMaW1pdCB9ID0gdGhpcy5fb3B0cy5xdWFyYW50aW5lTW9kZSBhcyBRdWFyYW50aW5lT3B0aW9uVmFsdWU7XG5cbiAgICAgICAgICAgIHRoaXMuX3F1YXJhbnRpbmUuc2V0Q3VzdG9tUGFyYW1ldGVycyhhdHRlbXB0TGltaXQsIHN1Y2Nlc3NUaHJlc2hvbGQpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCF0aGlzLl9xdWFyYW50aW5lIHx8IHRoaXMuX2lzRmlyc3RRdWFyYW50aW5lQXR0ZW1wdCgpKSB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLmVtaXQoJ3Rlc3QtcnVuLWNyZWF0ZScsIHtcbiAgICAgICAgICAgICAgICB0ZXN0UnVuOiAgICB0aGlzLnRlc3RSdW4sXG4gICAgICAgICAgICAgICAgbGVnYWN5OiAgICAgVGVzdFJ1bkN0b3IgPT09IExlZ2FjeVRlc3RSdW4sXG4gICAgICAgICAgICAgICAgdGVzdDogICAgICAgdGhpcy50ZXN0LFxuICAgICAgICAgICAgICAgIGluZGV4OiAgICAgIHRoaXMuaW5kZXgsXG4gICAgICAgICAgICAgICAgcXVhcmFudGluZTogdGhpcy5fcXVhcmFudGluZSxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHRoaXMudGVzdFJ1bjtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIF9lbmRRdWFyYW50aW5lICgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgaWYgKCh0aGlzLl9xdWFyYW50aW5lIGFzIFF1YXJhbnRpbmUpLmF0dGVtcHRzLmxlbmd0aCA+IDEpXG4gICAgICAgICAgICB0aGlzLnRlc3RSdW4udW5zdGFibGUgPSAodGhpcy5fcXVhcmFudGluZSBhcyBRdWFyYW50aW5lKS5nZXRQYXNzZWRBdHRlbXB0cygpLmxlbmd0aCA+IDA7XG5cbiAgICAgICAgYXdhaXQgdGhpcy5fZW1pdFRlc3RSdW5Eb25lKCk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBfc2hvdWxkS2VlcEluUXVhcmFudGluZSAoKTogYm9vbGVhbiB7XG4gICAgICAgIGNvbnN0IGVycm9ycyAgICAgICAgID0gdGhpcy50ZXN0UnVuLmVycnM7XG4gICAgICAgIGNvbnN0IGhhc0Vycm9ycyAgICAgID0gISFlcnJvcnMubGVuZ3RoO1xuICAgICAgICBjb25zdCBhdHRlbXB0cyAgICAgICA9ICh0aGlzLl9xdWFyYW50aW5lIGFzIFF1YXJhbnRpbmUpLmF0dGVtcHRzO1xuICAgICAgICBjb25zdCBpc0ZpcnN0QXR0ZW1wdCA9IHRoaXMuX2lzRmlyc3RRdWFyYW50aW5lQXR0ZW1wdCgpO1xuXG4gICAgICAgIGF0dGVtcHRzLnB1c2goeyB0ZXN0UnVuSWQ6IHRoaXMudGVzdFJ1bi5pZCwgZXJyb3JzIH0pO1xuXG4gICAgICAgIHJldHVybiBpc0ZpcnN0QXR0ZW1wdCA/IGhhc0Vycm9ycyA6ICEodGhpcy5fcXVhcmFudGluZSBhcyBRdWFyYW50aW5lKS5pc1RocmVzaG9sZFJlYWNoZWQoKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIF9pc0ZpcnN0UXVhcmFudGluZUF0dGVtcHQgKCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gISF0aGlzLl9xdWFyYW50aW5lICYmICF0aGlzLl9xdWFyYW50aW5lLmF0dGVtcHRzLmxlbmd0aDtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIF9rZWVwSW5RdWFyYW50aW5lICgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgYXdhaXQgdGhpcy5fcmVzdGFydFRlc3QoKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIF9yZXN0YXJ0VGVzdCAoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGF3YWl0IHRoaXMuZW1pdCgndGVzdC1ydW4tcmVzdGFydCcpO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgX3Rlc3RSdW5Eb25lSW5RdWFyYW50aW5lTW9kZSAoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGlmICh0aGlzLl9zaG91bGRLZWVwSW5RdWFyYW50aW5lKCkpXG4gICAgICAgICAgICBhd2FpdCB0aGlzLl9rZWVwSW5RdWFyYW50aW5lKCk7XG4gICAgICAgIGVsc2VcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuX2VuZFF1YXJhbnRpbmUoKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIF90ZXN0UnVuRG9uZSAoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGlmICh0aGlzLl9xdWFyYW50aW5lKVxuICAgICAgICAgICAgYXdhaXQgdGhpcy5fdGVzdFJ1bkRvbmVJblF1YXJhbnRpbmVNb2RlKCk7XG4gICAgICAgIGVsc2VcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuX2VtaXRUZXN0UnVuRG9uZSgpO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgX2VtaXRBY3Rpb25TdGFydCAoYXJnczogQWN0aW9uRXZlbnRBcmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgYXdhaXQgdGhpcy5fbWVzc2FnZUJ1cy5lbWl0KCd0ZXN0LWFjdGlvbi1zdGFydCcsIGFyZ3MpO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgX2VtaXRBY3Rpb25Eb25lIChhcmdzOiBBY3Rpb25FdmVudEFyZyk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBhd2FpdCB0aGlzLmVtaXQoJ3Rlc3QtYWN0aW9uLWRvbmUnLCBhcmdzKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIF9lbWl0VGVzdFJ1bkRvbmUgKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICAvLyBOT1RFOiB3ZSBzaG91bGQgcmVwb3J0IHRlc3QgcnVuIGNvbXBsZXRpb24gaW4gb3JkZXIgdGhleSB3ZXJlIGNvbXBsZXRlZCBpbiBicm93c2VyLlxuICAgICAgICAvLyBUbyBrZWVwIGEgc2VxdWVuY2UgYWZ0ZXIgZml4dHVyZSBob29rIGV4ZWN1dGlvbiB3ZSB1c2UgY29tcGxldGlvbiBxdWV1ZS5cbiAgICAgICAgYXdhaXQgdGhpcy5fZml4dHVyZUhvb2tDb250cm9sbGVyLnJ1bkZpeHR1cmVBZnRlckhvb2tJZk5lY2Vzc2FyeSh0aGlzLnRlc3RSdW4pO1xuICAgICAgICBhd2FpdCB0aGlzLl90ZXN0UnVuSG9vay5ydW5UZXN0UnVuQWZ0ZXJIb29rSWZOZWNlc3NhcnkodGhpcy50ZXN0UnVuKTtcblxuICAgICAgICBjbGllbnRTY3JpcHRzUm91dGluZy51blJlZ2lzdGVyKHRoaXMuX3Byb3h5LCB0aGlzLmNsaWVudFNjcmlwdFJvdXRlcyk7XG5cbiAgICAgICAgdGhpcy5kb25lID0gdHJ1ZTtcblxuICAgICAgICBhd2FpdCB0aGlzLmVtaXQoJ3Rlc3QtcnVuLWRvbmUnKTtcblxuICAgICAgICB0ZXN0UnVuQ29udHJvbGxlckxvZ2dlcignZG9uZSAlcycsIHRoaXMuaWQpO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgX2VtaXRUZXN0UnVuU3RhcnQgKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBhd2FpdCB0aGlzLl9tZXNzYWdlQnVzLmVtaXQoJ3Rlc3QtcnVuLXN0YXJ0JywgdGhpcy50ZXN0UnVuKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIF90ZXN0UnVuQmVmb3JlRG9uZSAoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGxldCByYWlzZUV2ZW50ID0gIXRoaXMuX3F1YXJhbnRpbmU7XG5cbiAgICAgICAgaWYgKCFyYWlzZUV2ZW50KSB7XG4gICAgICAgICAgICBjb25zdCBpc1N1Y2Nlc3NmdWxRdWFyYW50aW5lRmlyc3RBdHRlbXB0ID0gdGhpcy5faXNGaXJzdFF1YXJhbnRpbmVBdHRlbXB0KCkgJiYgIXRoaXMudGVzdFJ1bi5lcnJzLmxlbmd0aDtcbiAgICAgICAgICAgIGNvbnN0IGlzQXR0ZW1wdHNUaHJlc2hvbGRSZWFjaGVkICAgICAgICAgPSAodGhpcy5fcXVhcmFudGluZSBhcyBRdWFyYW50aW5lKS5pc1RocmVzaG9sZFJlYWNoZWQodGhpcy50ZXN0UnVuLmVycnMpO1xuXG4gICAgICAgICAgICByYWlzZUV2ZW50ID0gaXNTdWNjZXNzZnVsUXVhcmFudGluZUZpcnN0QXR0ZW1wdCB8fCBpc0F0dGVtcHRzVGhyZXNob2xkUmVhY2hlZDtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChyYWlzZUV2ZW50KVxuICAgICAgICAgICAgYXdhaXQgdGhpcy5lbWl0KCd0ZXN0LXJ1bi1iZWZvcmUtZG9uZScpO1xuICAgIH1cblxuICAgIHByaXZhdGUgX3Rlc3RSdW5EaXNjb25uZWN0ZWQgKGNvbm5lY3Rpb246IEJyb3dzZXJDb25uZWN0aW9uKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIHRoaXMuX2Rpc2Nvbm5lY3Rpb25Db3VudCsrO1xuXG4gICAgICAgIGNvbnN0IGRpc2Nvbm5lY3Rpb25UaHJlc2hvbGRFeGNlZWRlZCA9IHRoaXMuX2Rpc2Nvbm5lY3Rpb25Db3VudCA+PSBESVNDT05ORUNUX1RIUkVTSE9MRDtcblxuICAgICAgICByZXR1cm4gY29ubmVjdGlvblxuICAgICAgICAgICAgLnByb2Nlc3NEaXNjb25uZWN0aW9uKGRpc2Nvbm5lY3Rpb25UaHJlc2hvbGRFeGNlZWRlZClcbiAgICAgICAgICAgIC50aGVuKCgpID0+IHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5fcmVzdGFydFRlc3QoKTtcbiAgICAgICAgICAgIH0pO1xuICAgIH1cblxuICAgIHByaXZhdGUgX2Fzc2lnblRlc3RSdW5FdmVudHMgKHRlc3RSdW46IFRlc3RSdW4gfCBMZWdhY3lUZXN0UnVuLCBjb25uZWN0aW9uOiBCcm93c2VyQ29ubmVjdGlvbik6IHZvaWQge1xuICAgICAgICB0ZXN0UnVuLm9uKCdhY3Rpb24tc3RhcnQnLCBhc3luYyAoYXJnczogQWN0aW9uRXZlbnRBcmcpID0+IHRoaXMuX2VtaXRBY3Rpb25TdGFydChPYmplY3QuYXNzaWduKGFyZ3MsIHsgdGVzdFJ1biB9KSkpO1xuICAgICAgICB0ZXN0UnVuLm9uKCdhY3Rpb24tZG9uZScsIGFzeW5jIChhcmdzOiBBY3Rpb25FdmVudEFyZykgPT4gdGhpcy5fZW1pdEFjdGlvbkRvbmUoT2JqZWN0LmFzc2lnbihhcmdzLCB7IHRlc3RSdW4gfSkpKTtcblxuICAgICAgICB0ZXN0UnVuLm9uY2UoJ3N0YXJ0JywgYXN5bmMgKCkgPT4gdGhpcy5fZW1pdFRlc3RSdW5TdGFydCgpKTtcbiAgICAgICAgdGVzdFJ1bi5vbmNlKCdyZWFkeScsIGFzeW5jICgpID0+IHtcbiAgICAgICAgICAgIGlmICghdGhpcy5fcXVhcmFudGluZSB8fCB0aGlzLl9pc0ZpcnN0UXVhcmFudGluZUF0dGVtcHQoKSlcbiAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLmVtaXQoJ3Rlc3QtcnVuLXJlYWR5Jyk7XG4gICAgICAgIH0pO1xuICAgICAgICB0ZXN0UnVuLm9uY2UoJ2JlZm9yZS1kb25lJywgKCkgPT4gdGhpcy5fdGVzdFJ1bkJlZm9yZURvbmUoKSk7XG4gICAgICAgIHRlc3RSdW4ub25jZSgnZG9uZScsICgpID0+IHRoaXMuX3Rlc3RSdW5Eb25lKCkpO1xuICAgICAgICB0ZXN0UnVuLm9uY2UoJ2Rpc2Nvbm5lY3RlZCcsICgpID0+IHRoaXMuX3Rlc3RSdW5EaXNjb25uZWN0ZWQoY29ubmVjdGlvbikpO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXQgYmxvY2tlZCAoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0aGlzLl9maXh0dXJlSG9va0NvbnRyb2xsZXIuaXNUZXN0QmxvY2tlZCh0aGlzLnRlc3QpO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgX2hhbmRsZU5hdGl2ZUF1dG9tYXRpb25Nb2RlIChjb25uZWN0aW9uOiBCcm93c2VyQ29ubmVjdGlvbik6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICB0aGlzLmlzTmF0aXZlQXV0b21hdGlvbiA9ICF0aGlzLl9vcHRzLmRpc2FibGVOYXRpdmVBdXRvbWF0aW9uO1xuXG4gICAgICAgIGNvbnN0IHN1cHBvcnROYXRpdmVBdXRvbWF0aW9uID0gY29ubmVjdGlvbi5zdXBwb3J0TmF0aXZlQXV0b21hdGlvbigpO1xuXG4gICAgICAgIGlmICghdGhpcy5pc05hdGl2ZUF1dG9tYXRpb24gfHwgc3VwcG9ydE5hdGl2ZUF1dG9tYXRpb24pXG4gICAgICAgICAgICByZXR1cm47XG5cbiAgICAgICAgYXdhaXQgdGhpcy5fbWVzc2FnZUJ1cy5lbWl0KCdiZWZvcmUtdGVzdC1ydW4tY3JlYXRlZC1lcnJvcicpO1xuXG4gICAgICAgIHRocm93IG5ldyBHZW5lcmFsRXJyb3IoUlVOVElNRV9FUlJPUlMuc2V0TmF0aXZlQXV0b21hdGlvbkZvclVuc3VwcG9ydGVkQnJvd3NlcnMsIGNvbm5lY3Rpb24uYnJvd3NlckluZm8ucHJvdmlkZXJOYW1lKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgc3RhcnQgKGNvbm5lY3Rpb246IEJyb3dzZXJDb25uZWN0aW9uLCBzdGFydFJ1bkV4ZWN1dGlvblRpbWU/OiBEYXRlKTogUHJvbWlzZTxzdHJpbmcgfCBudWxsPiB7XG4gICAgICAgIHRlc3RSdW5Db250cm9sbGVyTG9nZ2VyKCdzdGFydCAlcyAlTyAlTycsIHRoaXMuaWQsIHtcbiAgICAgICAgICAgIHRlc3Q6IHtcbiAgICAgICAgICAgICAgICBuYW1lOiB0aGlzLnRlc3QubmFtZSxcbiAgICAgICAgICAgICAgICBpZDogICB0aGlzLnRlc3QuaWQsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgY29ubmVjdGlvbjoge1xuICAgICAgICAgICAgICAgIHVzZXJBZ2VudDogY29ubmVjdGlvbi51c2VyQWdlbnQsXG4gICAgICAgICAgICAgICAgaWQ6ICAgICAgICBjb25uZWN0aW9uLmlkLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgYXdhaXQgdGhpcy5faGFuZGxlTmF0aXZlQXV0b21hdGlvbk1vZGUoY29ubmVjdGlvbik7XG5cbiAgICAgICAgdGhpcy5fZml4dHVyZUhvb2tDb250cm9sbGVyLmJsb2NrVGVzdElmTmVjZXNzYXJ5KHRoaXMudGVzdCk7XG5cbiAgICAgICAgY29uc3QgdGVzdFJ1biA9IGF3YWl0IHRoaXMuX2NyZWF0ZVRlc3RSdW4oY29ubmVjdGlvbiwgc3RhcnRSdW5FeGVjdXRpb25UaW1lKTtcblxuICAgICAgICBjb25zdCBob29rT2sgPSBhd2FpdCB0aGlzLl90ZXN0UnVuSG9vay5ydW5UZXN0UnVuQmVmb3JlSG9va0lmTmVjZXNzYXJ5KHRlc3RSdW4pXG4gICAgICAgICAgICAgICAgICAgICAgICYmIGF3YWl0IHRoaXMuX2ZpeHR1cmVIb29rQ29udHJvbGxlci5ydW5GaXh0dXJlQmVmb3JlSG9va0lmTmVjZXNzYXJ5KHRlc3RSdW4pO1xuXG4gICAgICAgIHRoaXMuX2ZpeHR1cmVIb29rQ29udHJvbGxlci51bmJsb2NrVGVzdCh0aGlzLnRlc3QpO1xuXG4gICAgICAgIGlmICh0aGlzLnRlc3Quc2tpcCB8fCAhaG9va09rKSB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLl9lbWl0VGVzdFJ1blN0YXJ0KCk7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLmVtaXQoJ3Rlc3QtcnVuLWJlZm9yZS1kb25lJyk7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLl9lbWl0VGVzdFJ1bkRvbmUoKTtcblxuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLl9hc3NpZ25UZXN0UnVuRXZlbnRzKHRlc3RSdW4sIGNvbm5lY3Rpb24pO1xuXG4gICAgICAgIHRlc3RSdW4uc3RhcnQoKTtcblxuICAgICAgICByZXR1cm4gU2Vzc2lvbkNvbnRyb2xsZXIuZ2V0U2Vzc2lvblVybCh0ZXN0UnVuLCB0aGlzLl9wcm94eSk7XG4gICAgfVxufVxuIl19