UNPKG

testcafe

Version:

Automated browser testing for the modern web development stack.

272 lines 36.5 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const events_1 = require("events"); const pinkie_1 = __importDefault(require("pinkie")); const mustache_1 = __importDefault(require("mustache")); const lodash_1 = require("lodash"); const useragent_1 = require("useragent"); const read_file_relative_1 = require("read-file-relative"); const promisify_event_1 = __importDefault(require("promisify-event")); const nanoid_1 = __importDefault(require("nanoid")); const command_1 = __importDefault(require("./command")); const status_1 = __importDefault(require("./status")); const runtime_1 = require("../../errors/runtime"); const types_1 = require("../../errors/types"); const IDLE_PAGE_TEMPLATE = read_file_relative_1.readSync('../../client/browser/idle-page/index.html.mustache'); const connections = {}; class BrowserConnection extends events_1.EventEmitter { constructor(gateway, browserInfo, permanent) { super(); this.HEARTBEAT_TIMEOUT = 2 * 60 * 1000; this.BROWSER_RESTART_TIMEOUT = 60 * 1000; this.id = BrowserConnection._generateId(); this.jobQueue = []; this.initScriptsQueue = []; this.browserConnectionGateway = gateway; this.disconnectionPromise = null; this.testRunAborted = false; this.browserInfo = browserInfo; this.browserInfo.userAgent = ''; this.browserInfo.userAgentProviderMetaInfo = ''; this.provider = browserInfo.provider; this.permanent = permanent; this.closing = false; this.closed = false; this.ready = false; this.opened = false; this.idle = true; this.heartbeatTimeout = null; this.pendingTestRunUrl = null; this.url = `${gateway.domain}/browser/connect/${this.id}`; this.idleUrl = `${gateway.domain}/browser/idle/${this.id}`; this.forcedIdleUrl = `${gateway.domain}/browser/idle-forced/${this.id}`; this.initScriptUrl = `${gateway.domain}/browser/init-script/${this.id}`; this.heartbeatRelativeUrl = `/browser/heartbeat/${this.id}`; this.statusRelativeUrl = `/browser/status/${this.id}`; this.statusDoneRelativeUrl = `/browser/status-done/${this.id}`; this.heartbeatUrl = `${gateway.domain}${this.heartbeatRelativeUrl}`; this.statusUrl = `${gateway.domain}${this.statusRelativeUrl}`; this.statusDoneUrl = `${gateway.domain}${this.statusDoneRelativeUrl}`; this.on('error', () => { this._forceIdle(); this.close(); }); connections[this.id] = this; this.browserConnectionGateway.startServingConnection(this); process.nextTick(() => this._runBrowser()); } static _generateId() { return nanoid_1.default(7); } async _runBrowser() { try { await this.provider.openBrowser(this.id, this.url, this.browserInfo.browserName); if (!this.ready) await promisify_event_1.default(this, 'ready'); this.opened = true; this.emit('opened'); } catch (err) { this.emit('error', new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.unableToOpenBrowser, this.browserInfo.providerName + ':' + this.browserInfo.browserName, err.stack)); } } async _closeBrowser() { if (!this.idle) await promisify_event_1.default(this, 'idle'); try { await this.provider.closeBrowser(this.id); } catch (err) { // NOTE: A warning would be really nice here, but it can't be done while log is stored in a task. } } _forceIdle() { if (!this.idle) { this.switchingToIdle = false; this.idle = true; this.emit('idle'); } } _createBrowserDisconnectedError() { return new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.browserDisconnected, this.userAgent); } _waitForHeartbeat() { this.heartbeatTimeout = setTimeout(() => { const err = this._createBrowserDisconnectedError(); this.opened = false; this.testRunAborted = true; this.emit('disconnected', err); this._restartBrowserOnDisconnect(err); }, this.HEARTBEAT_TIMEOUT); } async _getTestRunUrl(needPopNext) { if (needPopNext || !this.pendingTestRunUrl) this.pendingTestRunUrl = await this._popNextTestRunUrl(); return this.pendingTestRunUrl; } async _popNextTestRunUrl() { while (this.hasQueuedJobs && !this.currentJob.hasQueuedTestRuns) this.jobQueue.shift(); return this.hasQueuedJobs ? await this.currentJob.popNextTestRunUrl(this) : null; } static getById(id) { return connections[id] || null; } async _restartBrowser() { this.ready = false; this._forceIdle(); let resolveTimeout = null; let isTimeoutExpired = false; let timeout = null; const restartPromise = this._closeBrowser() .then(() => this._runBrowser()); const timeoutPromise = new pinkie_1.default(resolve => { resolveTimeout = resolve; timeout = setTimeout(() => { isTimeoutExpired = true; resolve(); }, this.BROWSER_RESTART_TIMEOUT); }); pinkie_1.default.race([restartPromise, timeoutPromise]) .then(() => { clearTimeout(timeout); if (isTimeoutExpired) this.emit('error', this._createBrowserDisconnectedError()); else resolveTimeout(); }); } _restartBrowserOnDisconnect(err) { let resolveFn = null; let rejectFn = null; this.disconnectionPromise = new pinkie_1.default((resolve, reject) => { resolveFn = resolve; rejectFn = () => { reject(err); }; setTimeout(() => { rejectFn(); }); }) .then(() => { return this._restartBrowser(); }) .catch(e => { this.emit('error', e); }); this.disconnectionPromise.resolve = resolveFn; this.disconnectionPromise.reject = rejectFn; } async processDisconnection(disconnectionThresholdExceedeed) { const { resolve, reject } = this.disconnectionPromise; if (disconnectionThresholdExceedeed) reject(); else resolve(); } addWarning(...args) { if (this.currentJob) this.currentJob.warningLog.addWarning(...args); } setProviderMetaInfo(str) { this.browserInfo.userAgentProviderMetaInfo = str; } get userAgent() { let userAgent = this.browserInfo.userAgent; if (this.browserInfo.userAgentProviderMetaInfo) userAgent += ` (${this.browserInfo.userAgentProviderMetaInfo})`; return userAgent; } get hasQueuedJobs() { return !!this.jobQueue.length; } get currentJob() { return this.jobQueue[0]; } // API runInitScript(code) { return new pinkie_1.default(resolve => this.initScriptsQueue.push({ code, resolve })); } addJob(job) { this.jobQueue.push(job); } removeJob(job) { lodash_1.pull(this.jobQueue, job); } close() { if (this.closed || this.closing) return; this.closing = true; this._closeBrowser() .then(() => { this.browserConnectionGateway.stopServingConnection(this); clearTimeout(this.heartbeatTimeout); delete connections[this.id]; this.ready = false; this.closed = true; this.emit('closed'); }); } establish(userAgent) { this.ready = true; const parsedUserAgent = useragent_1.parse(userAgent); this.browserInfo.userAgent = parsedUserAgent.toString(); this.browserInfo.fullUserAgent = userAgent; this.browserInfo.parsedUserAgent = parsedUserAgent; this._waitForHeartbeat(); this.emit('ready'); } heartbeat() { clearTimeout(this.heartbeatTimeout); this._waitForHeartbeat(); return { code: this.closing ? status_1.default.closing : status_1.default.ok, url: this.closing ? this.idleUrl : '' }; } renderIdlePage() { return mustache_1.default.render(IDLE_PAGE_TEMPLATE, { userAgent: this.userAgent, statusUrl: this.statusUrl, heartbeatUrl: this.heartbeatUrl, initScriptUrl: this.initScriptUrl, retryTestPages: !!this.browserConnectionGateway.retryTestPages }); } getInitScript() { const initScriptPromise = this.initScriptsQueue[0]; return { code: initScriptPromise ? initScriptPromise.code : null }; } handleInitScriptResult(data) { const initScriptPromise = this.initScriptsQueue.shift(); if (initScriptPromise) initScriptPromise.resolve(JSON.parse(data)); } isHeadlessBrowser() { return this.provider.isHeadlessBrowser(this.id); } async reportJobResult(status, data) { await this.provider.reportJobResult(this.id, status, data); } async getStatus(isTestDone) { if (!this.idle && !isTestDone) { this.idle = true; this.emit('idle'); } if (this.opened) { const testRunUrl = await this._getTestRunUrl(isTestDone || this.testRunAborted); this.testRunAborted = false; if (testRunUrl) { this.idle = false; return { cmd: command_1.default.run, url: testRunUrl }; } } return { cmd: command_1.default.idle, url: this.idleUrl }; } } exports.default = BrowserConnection; module.exports = exports.default; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvYnJvd3Nlci9jb25uZWN0aW9uL2luZGV4LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsbUNBQXNDO0FBQ3RDLG9EQUE2QjtBQUM3Qix3REFBZ0M7QUFDaEMsbUNBQXdDO0FBQ3hDLHlDQUFvRDtBQUNwRCwyREFBc0Q7QUFDdEQsc0VBQTZDO0FBQzdDLG9EQUE0QjtBQUM1Qix3REFBZ0M7QUFDaEMsc0RBQThCO0FBQzlCLGtEQUFvRDtBQUNwRCw4Q0FBb0Q7QUFFcEQsTUFBTSxrQkFBa0IsR0FBRyw2QkFBSSxDQUFDLG9EQUFvRCxDQUFDLENBQUM7QUFDdEYsTUFBTSxXQUFXLEdBQVUsRUFBRSxDQUFDO0FBRzlCLE1BQXFCLGlCQUFrQixTQUFRLHFCQUFZO0lBQ3ZELFlBQWEsT0FBTyxFQUFFLFdBQVcsRUFBRSxTQUFTO1FBQ3hDLEtBQUssRUFBRSxDQUFDO1FBRVIsSUFBSSxDQUFDLGlCQUFpQixHQUFTLENBQUMsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDO1FBQzdDLElBQUksQ0FBQyx1QkFBdUIsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDO1FBRXpDLElBQUksQ0FBQyxFQUFFLEdBQXlCLGlCQUFpQixDQUFDLFdBQVcsRUFBRSxDQUFDO1FBQ2hFLElBQUksQ0FBQyxRQUFRLEdBQW1CLEVBQUUsQ0FBQztRQUNuQyxJQUFJLENBQUMsZ0JBQWdCLEdBQVcsRUFBRSxDQUFDO1FBQ25DLElBQUksQ0FBQyx3QkFBd0IsR0FBRyxPQUFPLENBQUM7UUFDeEMsSUFBSSxDQUFDLG9CQUFvQixHQUFPLElBQUksQ0FBQztRQUNyQyxJQUFJLENBQUMsY0FBYyxHQUFhLEtBQUssQ0FBQztRQUV0QyxJQUFJLENBQUMsV0FBVyxHQUE2QixXQUFXLENBQUM7UUFDekQsSUFBSSxDQUFDLFdBQVcsQ0FBQyxTQUFTLEdBQW1CLEVBQUUsQ0FBQztRQUNoRCxJQUFJLENBQUMs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QUFDO2FBQ2hEO1NBQ0o7UUFFRCxPQUFPLEVBQUUsR0FBRyxFQUFFLGlCQUFPLENBQUMsSUFBSSxFQUFFLEdBQUcsRUFBRSxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7SUFDcEQsQ0FBQztDQUNKO0FBNVVELG9DQTRVQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEV2ZW50RW1pdHRlciB9IGZyb20gJ2V2ZW50cyc7XG5pbXBvcnQgUHJvbWlzZSBmcm9tICdwaW5raWUnO1xuaW1wb3J0IE11c3RhY2hlIGZyb20gJ211c3RhY2hlJztcbmltcG9ydCB7IHB1bGwgYXMgcmVtb3ZlIH0gZnJvbSAnbG9kYXNoJztcbmltcG9ydCB7IHBhcnNlIGFzIHBhcnNlVXNlckFnZW50IH0gZnJvbSAndXNlcmFnZW50JztcbmltcG9ydCB7IHJlYWRTeW5jIGFzIHJlYWQgfSBmcm9tICdyZWFkLWZpbGUtcmVsYXRpdmUnO1xuaW1wb3J0IHByb21pc2lmeUV2ZW50IGZyb20gJ3Byb21pc2lmeS1ldmVudCc7XG5pbXBvcnQgbmFub2lkIGZyb20gJ25hbm9pZCc7XG5pbXBvcnQgQ09NTUFORCBmcm9tICcuL2NvbW1hbmQnO1xuaW1wb3J0IFNUQVRVUyBmcm9tICcuL3N0YXR1cyc7XG5pbXBvcnQgeyBHZW5lcmFsRXJyb3IgfSBmcm9tICcuLi8uLi9lcnJvcnMvcnVudGltZSc7XG5pbXBvcnQgeyBSVU5USU1FX0VSUk9SUyB9IGZyb20gJy4uLy4uL2Vycm9ycy90eXBlcyc7XG5cbmNvbnN0IElETEVfUEFHRV9URU1QTEFURSA9IHJlYWQoJy4uLy4uL2NsaWVudC9icm93c2VyL2lkbGUtcGFnZS9pbmRleC5odG1sLm11c3RhY2hlJyk7XG5jb25zdCBjb25uZWN0aW9ucyAgICAgICAgPSB7fTtcblxuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBCcm93c2VyQ29ubmVjdGlvbiBleHRlbmRzIEV2ZW50RW1pdHRlciB7XG4gICAgY29uc3RydWN0b3IgKGdhdGV3YXksIGJyb3dzZXJJbmZvLCBwZXJtYW5lbnQpIHtcbiAgICAgICAgc3VwZXIoKTtcblxuICAgICAgICB0aGlzLkhFQVJUQkVBVF9USU1FT1VUICAgICAgID0gMiAqIDYwICogMTAwMDtcbiAgICAgICAgdGhpcy5CUk9XU0VSX1JFU1RBUlRfVElNRU9VVCA9IDYwICogMTAwMDtcblxuICAgICAgICB0aGlzLmlkICAgICAgICAgICAgICAgICAgICAgICA9IEJyb3dzZXJDb25uZWN0aW9uLl9nZW5lcmF0ZUlkKCk7XG4gICAgICAgIHRoaXMuam9iUXVldWUgICAgICAgICAgICAgICAgID0gW107XG4gICAgICAgIHRoaXMuaW5pdFNjcmlwdHNRdWV1ZSAgICAgICAgID0gW107XG4gICAgICAgIHRoaXMuYnJvd3NlckNvbm5lY3Rpb25HYXRld2F5ID0gZ2F0ZXdheTtcbiAgICAgICAgdGhpcy5kaXNjb25uZWN0aW9uUHJvbWlzZSAgICAgPSBudWxsO1xuICAgICAgICB0aGlzLnRlc3RSdW5BYm9ydGVkICAgICAgICAgICA9IGZhbHNlO1xuXG4gICAgICAgIHRoaXMuYnJvd3NlckluZm8gICAgICAgICAgICAgICAgICAgICAgICAgICA9IGJyb3dzZXJJbmZvO1xuICAgICAgICB0aGlzLmJyb3dzZXJJbmZvLnVzZXJBZ2VudCAgICAgICAgICAgICAgICAgPSAnJztcbiAgICAgICAgdGhpcy5icm93c2VySW5mby51c2VyQWdlbnRQcm92aWRlck1ldGFJbmZvID0gJyc7XG5cbiAgICAgICAgdGhpcy5wcm92aWRlciA9IGJyb3dzZXJJbmZvLnByb3ZpZGVyO1xuXG4gICAgICAgIHRoaXMucGVybWFuZW50ICAgICAgICAgPSBwZXJtYW5lbnQ7XG4gICAgICAgIHRoaXMuY2xvc2luZyAgICAgICAgICAgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5jbG9zZWQgICAgICAgICAgICA9IGZhbHNlO1xuICAgICAgICB0aGlzLnJlYWR5ICAgICAgICAgICAgID0gZmFsc2U7XG4gICAgICAgIHRoaXMub3BlbmVkICAgICAgICAgICAgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5pZGxlICAgICAgICAgICAgICA9IHRydWU7XG4gICAgICAgIHRoaXMuaGVhcnRiZWF0VGltZW91dCAgPSBudWxsO1xuICAgICAgICB0aGlzLnBlbmRpbmdUZXN0UnVuVXJsID0gbnVsbDtcblxuICAgICAgICB0aGlzLnVybCAgICAgICAgICAgPSBgJHtnYXRld2F5LmRvbWFpbn0vYnJvd3Nlci9jb25uZWN0LyR7dGhpcy5pZH1gO1xuICAgICAgICB0aGlzLmlkbGVVcmwgICAgICAgPSBgJHtnYXRld2F5LmRvbWFpbn0vYnJvd3Nlci9pZGxlLyR7dGhpcy5pZH1gO1xuICAgICAgICB0aGlzLmZvcmNlZElkbGVVcmwgPSBgJHtnYXRld2F5LmRvbWFpbn0vYnJvd3Nlci9pZGxlLWZvcmNlZC8ke3RoaXMuaWR9YDtcbiAgICAgICAgdGhpcy5pbml0U2NyaXB0VXJsID0gYCR7Z2F0ZXdheS5kb21haW59L2Jyb3dzZXIvaW5pdC1zY3JpcHQvJHt0aGlzLmlkfWA7XG5cbiAgICAgICAgdGhpcy5oZWFydGJlYXRSZWxhdGl2ZVVybCAgPSBgL2Jyb3dzZXIvaGVhcnRiZWF0LyR7dGhpcy5pZH1gO1xuICAgICAgICB0aGlzLnN0YXR1c1JlbGF0aXZlVXJsICAgICA9IGAvYnJvd3Nlci9zdGF0dXMvJHt0aGlzLmlkfWA7XG4gICAgICAgIHRoaXMuc3RhdHVzRG9uZVJlbGF0aXZlVXJsID0gYC9icm93c2VyL3N0YXR1cy1kb25lLyR7dGhpcy5pZH1gO1xuXG4gICAgICAgIHRoaXMuaGVhcnRiZWF0VXJsICA9IGAke2dhdGV3YXkuZG9tYWlufSR7dGhpcy5oZWFydGJlYXRSZWxhdGl2ZVVybH1gO1xuICAgICAgICB0aGlzLnN0YXR1c1VybCAgICAgPSBgJHtnYXRld2F5LmRvbWFpbn0ke3RoaXMuc3RhdHVzUmVsYXRpdmVVcmx9YDtcbiAgICAgICAgdGhpcy5zdGF0dXNEb25lVXJsID0gYCR7Z2F0ZXdheS5kb21haW59JHt0aGlzLnN0YXR1c0RvbmVSZWxhdGl2ZVVybH1gO1xuXG4gICAgICAgIHRoaXMub24oJ2Vycm9yJywgKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5fZm9yY2VJZGxlKCk7XG4gICAgICAgICAgICB0aGlzLmNsb3NlKCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGNvbm5lY3Rpb25zW3RoaXMuaWRdID0gdGhpcztcblxuICAgICAgICB0aGlzLmJyb3dzZXJDb25uZWN0aW9uR2F0ZXdheS5zdGFydFNlcnZpbmdDb25uZWN0aW9uKHRoaXMpO1xuXG4gICAgICAgIHByb2Nlc3MubmV4dFRpY2soKCkgPT4gdGhpcy5fcnVuQnJvd3NlcigpKTtcbiAgICB9XG5cbiAgICBzdGF0aWMgX2dlbmVyYXRlSWQgKCkge1xuICAgICAgICByZXR1cm4gbmFub2lkKDcpO1xuICAgIH1cblxuICAgIGFzeW5jIF9ydW5Ccm93c2VyICgpIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMucHJvdmlkZXIub3BlbkJyb3dzZXIodGhpcy5pZCwgdGhpcy51cmwsIHRoaXMuYnJvd3NlckluZm8uYnJvd3Nlck5hbWUpO1xuXG4gICAgICAgICAgICBpZiAoIXRoaXMucmVhZHkpXG4gICAgICAgICAgICAgICAgYXdhaXQgcHJvbWlzaWZ5RXZlbnQodGhpcywgJ3JlYWR5Jyk7XG5cbiAgICAgICAgICAgIHRoaXMub3BlbmVkID0gdHJ1ZTtcbiAgICAgICAgICAgIHRoaXMuZW1pdCgnb3BlbmVkJyk7XG4gICAgICAgIH1cbiAgICAgICAgY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgdGhpcy5lbWl0KCdlcnJvcicsIG5ldyBHZW5lcmFsRXJyb3IoXG4gICAgICAgICAgICAgICAgUlVOVElNRV9FUlJPUlMudW5hYmxlVG9PcGVuQnJvd3NlcixcbiAgICAgICAgICAgICAgICB0aGlzLmJyb3dzZXJJbmZvLnByb3ZpZGVyTmFtZSArICc6JyArIHRoaXMuYnJvd3NlckluZm8uYnJvd3Nlck5hbWUsXG4gICAgICAgICAgICAgICAgZXJyLnN0YWNrXG4gICAgICAgICAgICApKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGFzeW5jIF9jbG9zZUJyb3dzZXIgKCkge1xuICAgICAgICBpZiAoIXRoaXMuaWRsZSlcbiAgICAgICAgICAgIGF3YWl0IHByb21pc2lmeUV2ZW50KHRoaXMsICdpZGxlJyk7XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMucHJvdmlkZXIuY2xvc2VCcm93c2VyKHRoaXMuaWQpO1xuICAgICAgICB9XG4gICAgICAgIGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAgIC8vIE5PVEU6IEEgd2FybmluZyB3b3VsZCBiZSByZWFsbHkgbmljZSBoZXJlLCBidXQgaXQgY2FuJ3QgYmUgZG9uZSB3aGlsZSBsb2cgaXMgc3RvcmVkIGluIGEgdGFzay5cbiAgICAgICAgfVxuICAgIH1cblxuICAgIF9mb3JjZUlkbGUgKCkge1xuICAgICAgICBpZiAoIXRoaXMuaWRsZSkge1xuICAgICAgICAgICAgdGhpcy5zd2l0Y2hpbmdUb0lkbGUgPSBmYWxzZTtcbiAgICAgICAgICAgIHRoaXMuaWRsZSAgICAgICAgICAgID0gdHJ1ZTtcbiAgICAgICAgICAgIHRoaXMuZW1pdCgnaWRsZScpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgX2NyZWF0ZUJyb3dzZXJEaXNjb25uZWN0ZWRFcnJvciAoKSB7XG4gICAgICAgIHJldHVybiBuZXcgR2VuZXJhbEVycm9yKFJVTlRJTUVfRVJST1JTLmJyb3dzZXJEaXNjb25uZWN0ZWQsIHRoaXMudXNlckFnZW50KTtcbiAgICB9XG5cbiAgICBfd2FpdEZvckhlYXJ0YmVhdCAoKSB7XG4gICAgICAgIHRoaXMuaGVhcnRiZWF0VGltZW91dCA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgY29uc3QgZXJyID0gdGhpcy5fY3JlYXRlQnJvd3NlckRpc2Nvbm5lY3RlZEVycm9yKCk7XG5cbiAgICAgICAgICAgIHRoaXMub3BlbmVkICAgICAgICAgPSBmYWxzZTtcbiAgICAgICAgICAgIHRoaXMudGVzdFJ1bkFib3J0ZWQgPSB0cnVlO1xuXG4gICAgICAgICAgICB0aGlzLmVtaXQoJ2Rpc2Nvbm5lY3RlZCcsIGVycik7XG5cbiAgICAgICAgICAgIHRoaXMuX3Jlc3RhcnRCcm93c2VyT25EaXNjb25uZWN0KGVycik7XG4gICAgICAgIH0sIHRoaXMuSEVBUlRCRUFUX1RJTUVPVVQpO1xuICAgIH1cblxuICAgIGFzeW5jIF9nZXRUZXN0UnVuVXJsIChuZWVkUG9wTmV4dCkge1xuICAgICAgICBpZiAobmVlZFBvcE5leHQgfHwgIXRoaXMucGVuZGluZ1Rlc3RSdW5VcmwpXG4gICAgICAgICAgICB0aGlzLnBlbmRpbmdUZXN0UnVuVXJsID0gYXdhaXQgdGhpcy5fcG9wTmV4dFRlc3RSdW5VcmwoKTtcblxuICAgICAgICByZXR1cm4gdGhpcy5wZW5kaW5nVGVzdFJ1blVybDtcbiAgICB9XG5cbiAgICBhc3luYyBfcG9wTmV4dFRlc3RSdW5VcmwgKCkge1xuICAgICAgICB3aGlsZSAodGhpcy5oYXNRdWV1ZWRKb2JzICYmICF0aGlzLmN1cnJlbnRKb2IuaGFzUXVldWVkVGVzdFJ1bnMpXG4gICAgICAgICAgICB0aGlzLmpvYlF1ZXVlLnNoaWZ0KCk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMuaGFzUXVldWVkSm9icyA/IGF3YWl0IHRoaXMuY3VycmVudEpvYi5wb3BOZXh0VGVzdFJ1blVybCh0aGlzKSA6IG51bGw7XG4gICAgfVxuXG4gICAgc3RhdGljIGdldEJ5SWQgKGlkKSB7XG4gICAgICAgIHJldHVybiBjb25uZWN0aW9uc1tpZF0gfHwgbnVsbDtcbiAgICB9XG5cbiAgICBhc3luYyBfcmVzdGFydEJyb3dzZXIgKCkge1xuICAgICAgICB0aGlzLnJlYWR5ID0gZmFsc2U7XG5cbiAgICAgICAgdGhpcy5fZm9yY2VJZGxlKCk7XG5cbiAgICAgICAgbGV0IHJlc29sdmVUaW1lb3V0ICAgPSBudWxsO1xuICAgICAgICBsZXQgaXNUaW1lb3V0RXhwaXJlZCA9IGZhbHNlO1xuICAgICAgICBsZXQgdGltZW91dCAgICAgICAgICA9IG51bGw7XG5cbiAgICAgICAgY29uc3QgcmVzdGFydFByb21pc2UgPSB0aGlzLl9jbG9zZUJyb3dzZXIoKVxuICAgICAgICAgICAgLnRoZW4oKCkgPT4gdGhpcy5fcnVuQnJvd3NlcigpKTtcblxuICAgICAgICBjb25zdCB0aW1lb3V0UHJvbWlzZSA9IG5ldyBQcm9taXNlKHJlc29sdmUgPT4ge1xuICAgICAgICAgICAgcmVzb2x2ZVRpbWVvdXQgPSByZXNvbHZlO1xuXG4gICAgICAgICAgICB0aW1lb3V0ID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICAgICAgaXNUaW1lb3V0RXhwaXJlZCA9IHRydWU7XG5cbiAgICAgICAgICAgICAgICByZXNvbHZlKCk7XG4gICAgICAgICAgICB9LCB0aGlzLkJST1dTRVJfUkVTVEFSVF9USU1FT1VUKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgUHJvbWlzZS5yYWNlKFsgcmVzdGFydFByb21pc2UsIHRpbWVvdXRQcm9taXNlIF0pXG4gICAgICAgICAgICAudGhlbigoKSA9PiB7XG4gICAgICAgICAgICAgICAgY2xlYXJUaW1lb3V0KHRpbWVvdXQpO1xuXG4gICAgICAgICAgICAgICAgaWYgKGlzVGltZW91dEV4cGlyZWQpXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZW1pdCgnZXJyb3InLCB0aGlzLl9jcmVhdGVCcm93c2VyRGlzY29ubmVjdGVkRXJyb3IoKSk7XG4gICAgICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgICAgICByZXNvbHZlVGltZW91dCgpO1xuICAgICAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgX3Jlc3RhcnRCcm93c2VyT25EaXNjb25uZWN0IChlcnIpIHtcbiAgICAgICAgbGV0IHJlc29sdmVGbiA9IG51bGw7XG4gICAgICAgIGxldCByZWplY3RGbiAgPSBudWxsO1xuXG4gICAgICAgIHRoaXMuZGlzY29ubmVjdGlvblByb21pc2UgPSBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgICAgICByZXNvbHZlRm4gPSByZXNvbHZlO1xuXG4gICAgICAgICAgICByZWplY3RGbiA9ICgpID0+IHtcbiAgICAgICAgICAgICAgICByZWplY3QoZXJyKTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgICAgIHJlamVjdEZuKCk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSlcbiAgICAgICAgICAgIC50aGVuKCgpID0+IHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5fcmVzdGFydEJyb3dzZXIoKTtcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAuY2F0Y2goZSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5lbWl0KCdlcnJvcicsIGUpO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgdGhpcy5kaXNjb25uZWN0aW9uUHJvbWlzZS5yZXNvbHZlID0gcmVzb2x2ZUZuO1xuICAgICAgICB0aGlzLmRpc2Nvbm5lY3Rpb25Qcm9taXNlLnJlamVjdCAgPSByZWplY3RGbjtcbiAgICB9XG5cbiAgICBhc3luYyBwcm9jZXNzRGlzY29ubmVjdGlvbiAoZGlzY29ubmVjdGlvblRocmVzaG9sZEV4Y2VlZGVlZCkge1xuICAgICAgICBjb25zdCB7IHJlc29sdmUsIHJlamVjdCB9ID0gdGhpcy5kaXNjb25uZWN0aW9uUHJvbWlzZTtcblxuICAgICAgICBpZiAoZGlzY29ubmVjdGlvblRocmVzaG9sZEV4Y2VlZGVlZClcbiAgICAgICAgICAgIHJlamVjdCgpO1xuICAgICAgICBlbHNlXG4gICAgICAgICAgICByZXNvbHZlKCk7XG4gICAgfVxuXG4gICAgYWRkV2FybmluZyAoLi4uYXJncykge1xuICAgICAgICBpZiAodGhpcy5jdXJyZW50Sm9iKVxuICAgICAgICAgICAgdGhpcy5jdXJyZW50Sm9iLndhcm5pbmdMb2cuYWRkV2FybmluZyguLi5hcmdzKTtcbiAgICB9XG5cbiAgICBzZXRQcm92aWRlck1ldGFJbmZvIChzdHIpIHtcbiAgICAgICAgdGhpcy5icm93c2VySW5mby51c2VyQWdlbnRQcm92aWRlck1ldGFJbmZvID0gc3RyO1xuICAgIH1cblxuICAgIGdldCB1c2VyQWdlbnQgKCkge1xuICAgICAgICBsZXQgdXNlckFnZW50ID0gdGhpcy5icm93c2VySW5mby51c2VyQWdlbnQ7XG5cbiAgICAgICAgaWYgKHRoaXMuYnJvd3NlckluZm8udXNlckFnZW50UHJvdmlkZXJNZXRhSW5mbylcbiAgICAgICAgICAgIHVzZXJBZ2VudCArPSBgICgke3RoaXMuYnJvd3NlckluZm8udXNlckFnZW50UHJvdmlkZXJNZXRhSW5mb30pYDtcblxuICAgICAgICByZXR1cm4gdXNlckFnZW50O1xuICAgIH1cblxuICAgIGdldCBoYXNRdWV1ZWRKb2JzICgpIHtcbiAgICAgICAgcmV0dXJuICEhdGhpcy5qb2JRdWV1ZS5sZW5ndGg7XG4gICAgfVxuXG4gICAgZ2V0IGN1cnJlbnRKb2IgKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5qb2JRdWV1ZVswXTtcbiAgICB9XG5cbiAgICAvLyBBUElcbiAgICBydW5Jbml0U2NyaXB0IChjb2RlKSB7XG4gICAgICAgIHJldHVybiBuZXcgUHJvbWlzZShyZXNvbHZlID0+IHRoaXMuaW5pdFNjcmlwdHNRdWV1ZS5wdXNoKHsgY29kZSwgcmVzb2x2ZSB9KSk7XG4gICAgfVxuXG4gICAgYWRkSm9iIChqb2IpIHtcbiAgICAgICAgdGhpcy5qb2JRdWV1ZS5wdXNoKGpvYik7XG4gICAgfVxuXG4gICAgcmVtb3ZlSm9iIChqb2IpIHtcbiAgICAgICAgcmVtb3ZlKHRoaXMuam9iUXVldWUsIGpvYik7XG4gICAgfVxuXG4gICAgY2xvc2UgKCkge1xuICAgICAgICBpZiAodGhpcy5jbG9zZWQgfHwgdGhpcy5jbG9zaW5nKVxuICAgICAgICAgICAgcmV0dXJuO1xuXG4gICAgICAgIHRoaXMuY2xvc2luZyA9IHRydWU7XG5cbiAgICAgICAgdGhpcy5fY2xvc2VCcm93c2VyKClcbiAgICAgICAgICAgIC50aGVuKCgpID0+IHtcbiAgICAgICAgICAgICAgICB0aGlzLmJyb3dzZXJDb25uZWN0aW9uR2F0ZXdheS5zdG9wU2VydmluZ0Nvbm5lY3Rpb24odGhpcyk7XG4gICAgICAgICAgICAgICAgY2xlYXJUaW1lb3V0KHRoaXMuaGVhcnRiZWF0VGltZW91dCk7XG5cbiAgICAgICAgICAgICAgICBkZWxldGUgY29ubmVjdGlvbnNbdGhpcy5pZF07XG5cbiAgICAgICAgICAgICAgICB0aGlzLnJlYWR5ICA9IGZhbHNlO1xuICAgICAgICAgICAgICAgIHRoaXMuY2xvc2VkID0gdHJ1ZTtcblxuICAgICAgICAgICAgICAgIHRoaXMuZW1pdCgnY2xvc2VkJyk7XG4gICAgICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBlc3RhYmxpc2ggKHVzZXJBZ2VudCkge1xuICAgICAgICB0aGlzLnJlYWR5ID0gdHJ1ZTtcblxuICAgICAgICBjb25zdCBwYXJzZWRVc2VyQWdlbnQgPSBwYXJzZVVzZXJBZ2VudCh1c2VyQWdlbnQpO1xuXG4gICAgICAgIHRoaXMuYnJvd3NlckluZm8udXNlckFnZW50ICAgICAgID0gcGFyc2VkVXNlckFnZW50LnRvU3RyaW5nKCk7XG4gICAgICAgIHRoaXMuYnJvd3NlckluZm8uZnVsbFVzZXJBZ2VudCAgID0gdXNlckFnZW50O1xuICAgICAgICB0aGlzLmJyb3dzZXJJbmZvLnBhcnNlZFVzZXJBZ2VudCA9IHBhcnNlZFVzZXJBZ2VudDtcblxuICAgICAgICB0aGlzLl93YWl0Rm9ySGVhcnRiZWF0KCk7XG4gICAgICAgIHRoaXMuZW1pdCgncmVhZHknKTtcbiAgICB9XG5cbiAgICBoZWFydGJlYXQgKCkge1xuICAgICAgICBjbGVhclRpbWVvdXQodGhpcy5oZWFydGJlYXRUaW1lb3V0KTtcbiAgICAgICAgdGhpcy5fd2FpdEZvckhlYXJ0YmVhdCgpO1xuXG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBjb2RlOiB0aGlzLmNsb3NpbmcgPyBTVEFUVVMuY2xvc2luZyA6IFNUQVRVUy5vayxcbiAgICAgICAgICAgIHVybDogIHRoaXMuY2xvc2luZyA/IHRoaXMuaWRsZVVybCA6ICcnXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgcmVuZGVySWRsZVBhZ2UgKCkge1xuICAgICAgICByZXR1cm4gTXVzdGFjaGUucmVuZGVyKElETEVfUEFHRV9URU1QTEFURSwge1xuICAgICAgICAgICAgdXNlckFnZW50OiAgICAgIHRoaXMudXNlckFnZW50LFxuICAgICAgICAgICAgc3RhdHVzVXJsOiAgICAgIHRoaXMuc3RhdHVzVXJsLFxuICAgICAgICAgICAgaGVhcnRiZWF0VXJsOiAgIHRoaXMuaGVhcnRiZWF0VXJsLFxuICAgICAgICAgICAgaW5pdFNjcmlwdFVybDogIHRoaXMuaW5pdFNjcmlwdFVybCxcbiAgICAgICAgICAgIHJldHJ5VGVzdFBhZ2VzOiAhIXRoaXMuYnJvd3NlckNvbm5lY3Rpb25HYXRld2F5LnJldHJ5VGVzdFBhZ2VzXG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIGdldEluaXRTY3JpcHQgKCkge1xuICAgICAgICBjb25zdCBpbml0U2NyaXB0UHJvbWlzZSA9IHRoaXMuaW5pdFNjcmlwdHNRdWV1ZVswXTtcblxuICAgICAgICByZXR1cm4geyBjb2RlOiBpbml0U2NyaXB0UHJvbWlzZSA/IGluaXRTY3JpcHRQcm9taXNlLmNvZGUgOiBudWxsIH07XG4gICAgfVxuXG4gICAgaGFuZGxlSW5pdFNjcmlwdFJlc3VsdCAoZGF0YSkge1xuICAgICAgICBjb25zdCBpbml0U2NyaXB0UHJvbWlzZSA9IHRoaXMuaW5pdFNjcmlwdHNRdWV1ZS5zaGlmdCgpO1xuXG4gICAgICAgIGlmIChpbml0U2NyaXB0UHJvbWlzZSlcbiAgICAgICAgICAgIGluaXRTY3JpcHRQcm9taXNlLnJlc29sdmUoSlNPTi5wYXJzZShkYXRhKSk7XG4gICAgfVxuXG4gICAgaXNIZWFkbGVzc0Jyb3dzZXIgKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5wcm92aWRlci5pc0hlYWRsZXNzQnJvd3Nlcih0aGlzLmlkKTtcbiAgICB9XG5cbiAgICBhc3luYyByZXBvcnRKb2JSZXN1bHQgKHN0YXR1cywgZGF0YSkge1xuICAgICAgICBhd2FpdCB0aGlzLnByb3ZpZGVyLnJlcG9ydEpvYlJlc3VsdCh0aGlzLmlkLCBzdGF0dXMsIGRhdGEpO1xuICAgIH1cblxuICAgIGFzeW5jIGdldFN0YXR1cyAoaXNUZXN0RG9uZSkge1xuICAgICAgICBpZiAoIXRoaXMuaWRsZSAmJiAhaXNUZXN0RG9uZSkge1xuICAgICAgICAgICAgdGhpcy5pZGxlID0gdHJ1ZTtcbiAgICAgICAgICAgIHRoaXMuZW1pdCgnaWRsZScpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRoaXMub3BlbmVkKSB7XG4gICAgICAgICAgICBjb25zdCB0ZXN0UnVuVXJsID0gYXdhaXQgdGhpcy5fZ2V0VGVzdFJ1blVybChpc1Rlc3REb25lIHx8IHRoaXMudGVzdFJ1bkFib3J0ZWQpO1xuXG4gICAgICAgICAgICB0aGlzLnRlc3RSdW5BYm9ydGVkID0gZmFsc2U7XG5cbiAgICAgICAgICAgIGlmICh0ZXN0UnVuVXJsKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5pZGxlID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHsgY21kOiBDT01NQU5ELnJ1biwgdXJsOiB0ZXN0UnVuVXJsIH07XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4geyBjbWQ6IENPTU1BTkQuaWRsZSwgdXJsOiB0aGlzLmlkbGVVcmwgfTtcbiAgICB9XG59XG4iXX0=