UNPKG

27.2 kBJavaScriptView Raw
1"use strict";
2var __importDefault = (this && this.__importDefault) || function (mod) {
3 return (mod && mod.__esModule) ? mod : { "default": mod };
4};
5Object.defineProperty(exports, "__esModule", { value: true });
6const async_event_emitter_1 = __importDefault(require("../utils/async-event-emitter"));
7const testcafe_legacy_api_1 = require("testcafe-legacy-api");
8const test_run_1 = __importDefault(require("../test-run"));
9const session_controller_1 = __importDefault(require("../test-run/session-controller"));
10const QUARANTINE_THRESHOLD = 3;
11const DISCONNECT_THRESHOLD = 3;
12class Quarantine {
13 constructor() {
14 this.attempts = [];
15 }
16 getFailedAttempts() {
17 return this.attempts.filter(errors => !!errors.length);
18 }
19 getPassedAttempts() {
20 return this.attempts.filter(errors => errors.length === 0);
21 }
22 getNextAttemptNumber() {
23 return this.attempts.length + 1;
24 }
25 isThresholdReached(extraErrors) {
26 const { failedTimes, passedTimes } = this._getAttemptsResult(extraErrors);
27 const failedThresholdReached = failedTimes >= QUARANTINE_THRESHOLD;
28 const passedThresholdReached = passedTimes >= QUARANTINE_THRESHOLD;
29 return failedThresholdReached || passedThresholdReached;
30 }
31 isFirstAttemptSuccessful(extraErrors) {
32 const { failedTimes, passedTimes } = this._getAttemptsResult(extraErrors);
33 return failedTimes === 0 && passedTimes > 0;
34 }
35 _getAttemptsResult(extraErrors) {
36 let failedTimes = this.getFailedAttempts().length;
37 let passedTimes = this.getPassedAttempts().length;
38 if (extraErrors) {
39 if (extraErrors.length)
40 failedTimes += extraErrors.length;
41 else
42 passedTimes += 1;
43 }
44 return { failedTimes, passedTimes };
45 }
46}
47class TestRunController extends async_event_emitter_1.default {
48 constructor(test, index, proxy, screenshots, warningLog, fixtureHookController, opts) {
49 super();
50 this.test = test;
51 this.index = index;
52 this.opts = opts;
53 this.proxy = proxy;
54 this.screenshots = screenshots;
55 this.warningLog = warningLog;
56 this.fixtureHookController = fixtureHookController;
57 this.TestRunCtor = TestRunController._getTestRunCtor(test, opts);
58 this.testRun = null;
59 this.done = false;
60 this.quarantine = null;
61 this.disconnectionCount = 0;
62 if (this.opts.quarantineMode)
63 this.quarantine = new Quarantine();
64 }
65 static _getTestRunCtor(test, opts) {
66 if (opts.TestRunCtor)
67 return opts.TestRunCtor;
68 return test.isLegacy ? testcafe_legacy_api_1.TestRun : test_run_1.default;
69 }
70 async _createTestRun(connection) {
71 const screenshotCapturer = this.screenshots.createCapturerFor(this.test, this.index, this.quarantine, connection, this.warningLog);
72 const TestRunCtor = this.TestRunCtor;
73 this.testRun = new TestRunCtor(this.test, connection, screenshotCapturer, this.warningLog, this.opts);
74 if (this.testRun.addQuarantineInfo)
75 this.testRun.addQuarantineInfo(this.quarantine);
76 if (!this.quarantine || this._isFirstQuarantineAttempt()) {
77 await this.emit('test-run-create', {
78 testRun: this.testRun,
79 legacy: TestRunCtor === testcafe_legacy_api_1.TestRun,
80 test: this.test,
81 index: this.index,
82 quarantine: this.quarantine,
83 });
84 }
85 return this.testRun;
86 }
87 async _endQuarantine() {
88 if (this.quarantine.attempts.length > 1)
89 this.testRun.unstable = this.quarantine.getPassedAttempts().length > 0;
90 await this._emitTestRunDone();
91 }
92 _shouldKeepInQuarantine() {
93 const errors = this.testRun.errs;
94 const hasErrors = !!errors.length;
95 const attempts = this.quarantine.attempts;
96 const isFirstAttempt = this._isFirstQuarantineAttempt();
97 attempts.push(errors);
98 return isFirstAttempt ? hasErrors : !this.quarantine.isThresholdReached();
99 }
100 _isFirstQuarantineAttempt() {
101 return this.quarantine && !this.quarantine.attempts.length;
102 }
103 async _keepInQuarantine() {
104 await this._restartTest();
105 }
106 async _restartTest() {
107 await this.emit('test-run-restart');
108 }
109 async _testRunDoneInQuarantineMode() {
110 if (this._shouldKeepInQuarantine())
111 await this._keepInQuarantine();
112 else
113 await this._endQuarantine();
114 }
115 async _testRunDone() {
116 if (this.quarantine)
117 await this._testRunDoneInQuarantineMode();
118 else
119 await this._emitTestRunDone();
120 }
121 async _emitActionStart(args) {
122 await this.emit('test-action-start', args);
123 }
124 async _emitActionDone(args) {
125 await this.emit('test-action-done', args);
126 }
127 async _emitTestRunDone() {
128 // NOTE: we should report test run completion in order they were completed in browser.
129 // To keep a sequence after fixture hook execution we use completion queue.
130 await this.fixtureHookController.runFixtureAfterHookIfNecessary(this.testRun);
131 this.done = true;
132 await this.emit('test-run-done');
133 }
134 async _emitTestRunStart() {
135 await this.emit('test-run-start');
136 }
137 async _testRunBeforeDone() {
138 let raiseEvent = !this.quarantine;
139 if (!raiseEvent) {
140 const isSuccessfulQuarantineFirstAttempt = this._isFirstQuarantineAttempt() && !this.testRun.errs.length;
141 const isAttemptsThresholdReached = this.quarantine.isThresholdReached(this.testRun.errs);
142 raiseEvent = isSuccessfulQuarantineFirstAttempt || isAttemptsThresholdReached;
143 }
144 if (raiseEvent)
145 await this.emit('test-run-before-done');
146 }
147 _testRunDisconnected(connection) {
148 this.disconnectionCount++;
149 const disconnectionThresholdExceedeed = this.disconnectionCount >= DISCONNECT_THRESHOLD;
150 return connection
151 .processDisconnection(disconnectionThresholdExceedeed)
152 .then(() => {
153 return this._restartTest();
154 });
155 }
156 _assignTestRunEvents(testRun, connection) {
157 testRun.on('action-start', async (args) => this._emitActionStart(Object.assign(args, { testRun })));
158 testRun.on('action-done', async (args) => this._emitActionDone(Object.assign(args, { testRun })));
159 testRun.once('start', async () => this._emitTestRunStart());
160 testRun.once('ready', async () => {
161 if (!this.quarantine || this._isFirstQuarantineAttempt())
162 await this.emit('test-run-ready');
163 });
164 testRun.once('before-done', () => this._testRunBeforeDone());
165 testRun.once('done', () => this._testRunDone());
166 testRun.once('disconnected', () => this._testRunDisconnected(connection));
167 }
168 get blocked() {
169 return this.fixtureHookController.isTestBlocked(this.test);
170 }
171 async start(connection) {
172 const testRun = await this._createTestRun(connection);
173 const hookOk = await this.fixtureHookController.runFixtureBeforeHookIfNecessary(testRun);
174 if (this.test.skip || !hookOk) {
175 await this.emit('test-run-start');
176 await this._emitTestRunDone();
177 return null;
178 }
179 this._assignTestRunEvents(testRun, connection);
180 testRun.start();
181 return session_controller_1.default.getSessionUrl(testRun, this.proxy);
182 }
183}
184exports.default = TestRunController;
185module.exports = exports.default;
186//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdC1ydW4tY29udHJvbGxlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9ydW5uZXIvdGVzdC1ydW4tY29udHJvbGxlci5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLHVGQUE2RDtBQUM3RCw2REFBK0Q7QUFDL0QsMkRBQWtDO0FBQ2xDLHdGQUErRDtBQUUvRCxNQUFNLG9CQUFvQixHQUFHLENBQUMsQ0FBQztBQUMvQixNQUFNLG9CQUFvQixHQUFHLENBQUMsQ0FBQztBQUUvQixNQUFNLFVBQVU7SUFDWjtRQUNJLElBQUksQ0FBQyxRQUFRLEdBQUcsRUFBRSxDQUFDO0lBQ3ZCLENBQUM7SUFFRCxpQkFBaUI7UUFDYixPQUFPLElBQUksQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUMzRCxDQUFDO0lBRUQsaUJBQWlCO1FBQ2IsT0FBTyxJQUFJLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEtBQUssQ0FBQyxDQUFDLENBQUM7SUFDL0QsQ0FBQztJQUVELG9CQUFvQjtRQUNoQixPQUFPLElBQUksQ0FBQyxRQUFRLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQztJQUNwQyxDQUFDO0lBRUQsa0JBQWtCLENBQUUsV0FBVztRQUMzQixNQUFNLEVBQUUsV0FBVyxFQUFFLFdBQVcsRUFBRSxHQUFHLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUUxRSxNQUFNLHNCQUFzQixHQUFHLFdBQVcsSUFBSSxvQkFBb0IsQ0FBQztRQUNuRSxNQUFNLHNCQUFzQixHQUFHLFdBQVcsSUFBSSxvQkFBb0IsQ0FBQztRQUVuRSxPQUFPLHNCQUFzQixJQUFJLHNCQUFzQixDQUFDO0lBQzVELENBQUM7SUFFRCx3QkFBd0IsQ0FBRSxXQUFXO1FBQ2pD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TSxNQUFNLEdBQUcsTUFBTSxJQUFJLENBQUMscUJBQXFCLENBQUMsK0JBQStCLENBQUMsT0FBTyxDQUFDLENBQUM7UUFFekYsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksSUFBSSxDQUFDLE1BQU0sRUFBRTtZQUMzQixNQUFNLElBQUksQ0FBQyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztZQUNsQyxNQUFNLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1lBQzlCLE9BQU8sSUFBSSxDQUFDO1NBQ2Y7UUFFRCxJQUFJLENBQUMsb0JBQW9CLENBQUMsT0FBTyxFQUFFLFVBQVUsQ0FBQyxDQUFDO1FBRS9DLE9BQU8sQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUVoQixPQUFPLDRCQUFpQixDQUFDLGFBQWEsQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ2hFLENBQUM7Q0FDSjtBQXBMRCxvQ0FvTEMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgQXN5bmNFdmVudEVtaXR0ZXIgZnJvbSAnLi4vdXRpbHMvYXN5bmMtZXZlbnQtZW1pdHRlcic7XG5pbXBvcnQgeyBUZXN0UnVuIGFzIExlZ2FjeVRlc3RSdW4gfSBmcm9tICd0ZXN0Y2FmZS1sZWdhY3ktYXBpJztcbmltcG9ydCBUZXN0UnVuIGZyb20gJy4uL3Rlc3QtcnVuJztcbmltcG9ydCBTZXNzaW9uQ29udHJvbGxlciBmcm9tICcuLi90ZXN0LXJ1bi9zZXNzaW9uLWNvbnRyb2xsZXInO1xuXG5jb25zdCBRVUFSQU5USU5FX1RIUkVTSE9MRCA9IDM7XG5jb25zdCBESVNDT05ORUNUX1RIUkVTSE9MRCA9IDM7XG5cbmNsYXNzIFF1YXJhbnRpbmUge1xuICAgIGNvbnN0cnVjdG9yICgpIHtcbiAgICAgICAgdGhpcy5hdHRlbXB0cyA9IFtdO1xuICAgIH1cblxuICAgIGdldEZhaWxlZEF0dGVtcHRzICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuYXR0ZW1wdHMuZmlsdGVyKGVycm9ycyA9PiAhIWVycm9ycy5sZW5ndGgpO1xuICAgIH1cblxuICAgIGdldFBhc3NlZEF0dGVtcHRzICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuYXR0ZW1wdHMuZmlsdGVyKGVycm9ycyA9PiBlcnJvcnMubGVuZ3RoID09PSAwKTtcbiAgICB9XG5cbiAgICBnZXROZXh0QXR0ZW1wdE51bWJlciAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmF0dGVtcHRzLmxlbmd0aCArIDE7XG4gICAgfVxuXG4gICAgaXNUaHJlc2hvbGRSZWFjaGVkIChleHRyYUVycm9ycykge1xuICAgICAgICBjb25zdCB7IGZhaWxlZFRpbWVzLCBwYXNzZWRUaW1lcyB9ID0gdGhpcy5fZ2V0QXR0ZW1wdHNSZXN1bHQoZXh0cmFFcnJvcnMpO1xuXG4gICAgICAgIGNvbnN0IGZhaWxlZFRocmVzaG9sZFJlYWNoZWQgPSBmYWlsZWRUaW1lcyA+PSBRVUFSQU5USU5FX1RIUkVTSE9MRDtcbiAgICAgICAgY29uc3QgcGFzc2VkVGhyZXNob2xkUmVhY2hlZCA9IHBhc3NlZFRpbWVzID49IFFVQVJBTlRJTkVfVEhSRVNIT0xEO1xuXG4gICAgICAgIHJldHVybiBmYWlsZWRUaHJlc2hvbGRSZWFjaGVkIHx8IHBhc3NlZFRocmVzaG9sZFJlYWNoZWQ7XG4gICAgfVxuXG4gICAgaXNGaXJzdEF0dGVtcHRTdWNjZXNzZnVsIChleHRyYUVycm9ycykge1xuICAgICAgICBjb25zdCB7IGZhaWxlZFRpbWVzLCBwYXNzZWRUaW1lcyB9ID0gdGhpcy5fZ2V0QXR0ZW1wdHNSZXN1bHQoZXh0cmFFcnJvcnMpO1xuXG4gICAgICAgIHJldHVybiBmYWlsZWRUaW1lcyA9PT0gMCAmJiBwYXNzZWRUaW1lcyA+IDA7XG4gICAgfVxuXG4gICAgX2dldEF0dGVtcHRzUmVzdWx0IChleHRyYUVycm9ycykge1xuICAgICAgICBsZXQgZmFpbGVkVGltZXMgPSB0aGlzLmdldEZhaWxlZEF0dGVtcHRzKCkubGVuZ3RoO1xuICAgICAgICBsZXQgcGFzc2VkVGltZXMgPSB0aGlzLmdldFBhc3NlZEF0dGVtcHRzKCkubGVuZ3RoO1xuXG4gICAgICAgIGlmIChleHRyYUVycm9ycykge1xuICAgICAgICAgICAgaWYgKGV4dHJhRXJyb3JzLmxlbmd0aClcbiAgICAgICAgICAgICAgICBmYWlsZWRUaW1lcyArPSBleHRyYUVycm9ycy5sZW5ndGg7XG4gICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgcGFzc2VkVGltZXMgKz0gMTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB7IGZhaWxlZFRpbWVzLCBwYXNzZWRUaW1lcyB9O1xuICAgIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgVGVzdFJ1bkNvbnRyb2xsZXIgZXh0ZW5kcyBBc3luY0V2ZW50RW1pdHRlciB7XG4gICAgY29uc3RydWN0b3IgKHRlc3QsIGluZGV4LCBwcm94eSwgc2NyZWVuc2hvdHMsIHdhcm5pbmdMb2csIGZpeHR1cmVIb29rQ29udHJvbGxlciwgb3B0cykge1xuICAgICAgICBzdXBlcigpO1xuXG4gICAgICAgIHRoaXMudGVzdCAgPSB0ZXN0O1xuICAgICAgICB0aGlzLmluZGV4ID0gaW5kZXg7XG4gICAgICAgIHRoaXMub3B0cyAgPSBvcHRzO1xuXG4gICAgICAgIHRoaXMucHJveHkgICAgICAgICAgICAgICAgID0gcHJveHk7XG4gICAgICAgIHRoaXMuc2NyZWVuc2hvdHMgICAgICAgICAgID0gc2NyZWVuc2hvdHM7XG4gICAgICAgIHRoaXMud2FybmluZ0xvZyAgICAgICAgICAgID0gd2FybmluZ0xvZztcbiAgICAgICAgdGhpcy5maXh0dXJlSG9va0NvbnRyb2xsZXIgPSBmaXh0dXJlSG9va0NvbnRyb2xsZXI7XG5cbiAgICAgICAgdGhpcy5UZXN0UnVuQ3RvciA9IFRlc3RSdW5Db250cm9sbGVyLl9nZXRUZXN0UnVuQ3Rvcih0ZXN0LCBvcHRzKTtcblxuICAgICAgICB0aGlzLnRlc3RSdW4gICAgICAgICAgICA9IG51bGw7XG4gICAgICAgIHRoaXMuZG9uZSAgICAgICAgICAgICAgID0gZmFsc2U7XG4gICAgICAgIHRoaXMucXVhcmFudGluZSAgICAgICAgID0gbnVsbDtcbiAgICAgICAgdGhpcy5kaXNjb25uZWN0aW9uQ291bnQgPSAwO1xuXG4gICAgICAgIGlmICh0aGlzLm9wdHMucXVhcmFudGluZU1vZGUpXG4gICAgICAgICAgICB0aGlzLnF1YXJhbnRpbmUgPSBuZXcgUXVhcmFudGluZSgpO1xuICAgIH1cblxuICAgIHN0YXRpYyBfZ2V0VGVzdFJ1bkN0b3IgKHRlc3QsIG9wdHMpIHtcbiAgICAgICAgaWYgKG9wdHMuVGVzdFJ1bkN0b3IpXG4gICAgICAgICAgICByZXR1cm4gb3B0cy5UZXN0UnVuQ3RvcjtcblxuICAgICAgICByZXR1cm4gdGVzdC5pc0xlZ2FjeSA/IExlZ2FjeVRlc3RSdW4gOiBUZXN0UnVuO1xuICAgIH1cblxuICAgIGFzeW5jIF9jcmVhdGVUZXN0UnVuIChjb25uZWN0aW9uKSB7XG4gICAgICAgIGNvbnN0IHNjcmVlbnNob3RDYXB0dXJlciA9IHRoaXMuc2NyZWVuc2hvdHMuY3JlYXRlQ2FwdHVyZXJGb3IodGhpcy50ZXN0LCB0aGlzLmluZGV4LCB0aGlzLnF1YXJhbnRpbmUsIGNvbm5lY3Rpb24sIHRoaXMud2FybmluZ0xvZyk7XG4gICAgICAgIGNvbnN0IFRlc3RSdW5DdG9yICAgICAgICA9IHRoaXMuVGVzdFJ1bkN0b3I7XG5cbiAgICAgICAgdGhpcy50ZXN0UnVuID0gbmV3IFRlc3RSdW5DdG9yKHRoaXMudGVzdCwgY29ubmVjdGlvbiwgc2NyZWVuc2hvdENhcHR1cmVyLCB0aGlzLndhcm5pbmdMb2csIHRoaXMub3B0cyk7XG5cbiAgICAgICAgaWYgKHRoaXMudGVzdFJ1bi5hZGRRdWFyYW50aW5lSW5mbylcbiAgICAgICAgICAgIHRoaXMudGVzdFJ1bi5hZGRRdWFyYW50aW5lSW5mbyh0aGlzLnF1YXJhbnRpbmUpO1xuXG4gICAgICAgIGlmICghdGhpcy5xdWFyYW50aW5lIHx8IHRoaXMuX2lzRmlyc3RRdWFyYW50aW5lQXR0ZW1wdCgpKSB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLmVtaXQoJ3Rlc3QtcnVuLWNyZWF0ZScsIHtcbiAgICAgICAgICAgICAgICB0ZXN0UnVuOiAgICB0aGlzLnRlc3RSdW4sXG4gICAgICAgICAgICAgICAgbGVnYWN5OiAgICAgVGVzdFJ1bkN0b3IgPT09IExlZ2FjeVRlc3RSdW4sXG4gICAgICAgICAgICAgICAgdGVzdDogICAgICAgdGhpcy50ZXN0LFxuICAgICAgICAgICAgICAgIGluZGV4OiAgICAgIHRoaXMuaW5kZXgsXG4gICAgICAgICAgICAgICAgcXVhcmFudGluZTogdGhpcy5xdWFyYW50aW5lLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gdGhpcy50ZXN0UnVuO1xuICAgIH1cblxuICAgIGFzeW5jIF9lbmRRdWFyYW50aW5lICgpIHtcbiAgICAgICAgaWYgKHRoaXMucXVhcmFudGluZS5hdHRlbXB0cy5sZW5ndGggPiAxKVxuICAgICAgICAgICAgdGhpcy50ZXN0UnVuLnVuc3RhYmxlID0gdGhpcy5xdWFyYW50aW5lLmdldFBhc3NlZEF0dGVtcHRzKCkubGVuZ3RoID4gMDtcblxuICAgICAgICBhd2FpdCB0aGlzLl9lbWl0VGVzdFJ1bkRvbmUoKTtcbiAgICB9XG5cbiAgICBfc2hvdWxkS2VlcEluUXVhcmFudGluZSAoKSB7XG4gICAgICAgIGNvbnN0IGVycm9ycyAgICAgICAgID0gdGhpcy50ZXN0UnVuLmVycnM7XG4gICAgICAgIGNvbnN0IGhhc0Vycm9ycyAgICAgID0gISFlcnJvcnMubGVuZ3RoO1xuICAgICAgICBjb25zdCBhdHRlbXB0cyAgICAgICA9IHRoaXMucXVhcmFudGluZS5hdHRlbXB0cztcbiAgICAgICAgY29uc3QgaXNGaXJzdEF0dGVtcHQgPSB0aGlzLl9pc0ZpcnN0UXVhcmFudGluZUF0dGVtcHQoKTtcblxuICAgICAgICBhdHRlbXB0cy5wdXNoKGVycm9ycyk7XG5cbiAgICAgICAgcmV0dXJuIGlzRmlyc3RBdHRlbXB0ID8gaGFzRXJyb3JzIDogIXRoaXMucXVhcmFudGluZS5pc1RocmVzaG9sZFJlYWNoZWQoKTtcbiAgICB9XG5cbiAgICBfaXNGaXJzdFF1YXJhbnRpbmVBdHRlbXB0ICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucXVhcmFudGluZSAmJiAhdGhpcy5xdWFyYW50aW5lLmF0dGVtcHRzLmxlbmd0aDtcbiAgICB9XG5cbiAgICBhc3luYyBfa2VlcEluUXVhcmFudGluZSAoKSB7XG4gICAgICAgIGF3YWl0IHRoaXMuX3Jlc3RhcnRUZXN0KCk7XG4gICAgfVxuXG4gICAgYXN5bmMgX3Jlc3RhcnRUZXN0ICgpIHtcbiAgICAgICAgYXdhaXQgdGhpcy5lbWl0KCd0ZXN0LXJ1bi1yZXN0YXJ0Jyk7XG4gICAgfVxuXG4gICAgYXN5bmMgX3Rlc3RSdW5Eb25lSW5RdWFyYW50aW5lTW9kZSAoKSB7XG4gICAgICAgIGlmICh0aGlzLl9zaG91bGRLZWVwSW5RdWFyYW50aW5lKCkpXG4gICAgICAgICAgICBhd2FpdCB0aGlzLl9rZWVwSW5RdWFyYW50aW5lKCk7XG4gICAgICAgIGVsc2VcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuX2VuZFF1YXJhbnRpbmUoKTtcbiAgICB9XG5cbiAgICBhc3luYyBfdGVzdFJ1bkRvbmUgKCkge1xuICAgICAgICBpZiAodGhpcy5xdWFyYW50aW5lKVxuICAgICAgICAgICAgYXdhaXQgdGhpcy5fdGVzdFJ1bkRvbmVJblF1YXJhbnRpbmVNb2RlKCk7XG4gICAgICAgIGVsc2VcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuX2VtaXRUZXN0UnVuRG9uZSgpO1xuICAgIH1cblxuICAgIGFzeW5jIF9lbWl0QWN0aW9uU3RhcnQgKGFyZ3MpIHtcbiAgICAgICAgYXdhaXQgdGhpcy5lbWl0KCd0ZXN0LWFjdGlvbi1zdGFydCcsIGFyZ3MpO1xuICAgIH1cblxuICAgIGFzeW5jIF9lbWl0QWN0aW9uRG9uZSAoYXJncykge1xuICAgICAgICBhd2FpdCB0aGlzLmVtaXQoJ3Rlc3QtYWN0aW9uLWRvbmUnLCBhcmdzKTtcbiAgICB9XG5cbiAgICBhc3luYyBfZW1pdFRlc3RSdW5Eb25lICgpIHtcbiAgICAgICAgLy8gTk9URTogd2Ugc2hvdWxkIHJlcG9ydCB0ZXN0IHJ1biBjb21wbGV0aW9uIGluIG9yZGVyIHRoZXkgd2VyZSBjb21wbGV0ZWQgaW4gYnJvd3Nlci5cbiAgICAgICAgLy8gVG8ga2VlcCBhIHNlcXVlbmNlIGFmdGVyIGZpeHR1cmUgaG9vayBleGVjdXRpb24gd2UgdXNlIGNvbXBsZXRpb24gcXVldWUuXG4gICAgICAgIGF3YWl0IHRoaXMuZml4dHVyZUhvb2tDb250cm9sbGVyLnJ1bkZpeHR1cmVBZnRlckhvb2tJZk5lY2Vzc2FyeSh0aGlzLnRlc3RSdW4pO1xuXG4gICAgICAgIHRoaXMuZG9uZSA9IHRydWU7XG5cbiAgICAgICAgYXdhaXQgdGhpcy5lbWl0KCd0ZXN0LXJ1bi1kb25lJyk7XG4gICAgfVxuXG4gICAgYXN5bmMgX2VtaXRUZXN0UnVuU3RhcnQgKCkge1xuICAgICAgICBhd2FpdCB0aGlzLmVtaXQoJ3Rlc3QtcnVuLXN0YXJ0Jyk7XG4gICAgfVxuXG4gICAgYXN5bmMgX3Rlc3RSdW5CZWZvcmVEb25lICgpIHtcbiAgICAgICAgbGV0IHJhaXNlRXZlbnQgPSAhdGhpcy5xdWFyYW50aW5lO1xuXG4gICAgICAgIGlmICghcmFpc2VFdmVudCkge1xuICAgICAgICAgICAgY29uc3QgaXNTdWNjZXNzZnVsUXVhcmFudGluZUZpcnN0QXR0ZW1wdCA9IHRoaXMuX2lzRmlyc3RRdWFyYW50aW5lQXR0ZW1wdCgpICYmICF0aGlzLnRlc3RSdW4uZXJycy5sZW5ndGg7XG4gICAgICAgICAgICBjb25zdCBpc0F0dGVtcHRzVGhyZXNob2xkUmVhY2hlZCAgICAgICAgID0gdGhpcy5xdWFyYW50aW5lLmlzVGhyZXNob2xkUmVhY2hlZCh0aGlzLnRlc3RSdW4uZXJycyk7XG5cbiAgICAgICAgICAgIHJhaXNlRXZlbnQgPSBpc1N1Y2Nlc3NmdWxRdWFyYW50aW5lRmlyc3RBdHRlbXB0IHx8IGlzQXR0ZW1wdHNUaHJlc2hvbGRSZWFjaGVkO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHJhaXNlRXZlbnQpXG4gICAgICAgICAgICBhd2FpdCB0aGlzLmVtaXQoJ3Rlc3QtcnVuLWJlZm9yZS1kb25lJyk7XG4gICAgfVxuXG4gICAgX3Rlc3RSdW5EaXNjb25uZWN0ZWQgKGNvbm5lY3Rpb24pIHtcbiAgICAgICAgdGhpcy5kaXNjb25uZWN0aW9uQ291bnQrKztcblxuICAgICAgICBjb25zdCBkaXNjb25uZWN0aW9uVGhyZXNob2xkRXhjZWVkZWVkID0gdGhpcy5kaXNjb25uZWN0aW9uQ291bnQgPj0gRElTQ09OTkVDVF9USFJFU0hPTEQ7XG5cbiAgICAgICAgcmV0dXJuIGNvbm5lY3Rpb25cbiAgICAgICAgICAgIC5wcm9jZXNzRGlzY29ubmVjdGlvbihkaXNjb25uZWN0aW9uVGhyZXNob2xkRXhjZWVkZWVkKVxuICAgICAgICAgICAgLnRoZW4oKCkgPT4ge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLl9yZXN0YXJ0VGVzdCgpO1xuICAgICAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgX2Fzc2lnblRlc3RSdW5FdmVudHMgKHRlc3RSdW4sIGNvbm5lY3Rpb24pIHtcbiAgICAgICAgdGVzdFJ1bi5vbignYWN0aW9uLXN0YXJ0JywgYXN5bmMgYXJncyA9PiB0aGlzLl9lbWl0QWN0aW9uU3RhcnQoT2JqZWN0LmFzc2lnbihhcmdzLCB7IHRlc3RSdW4gfSkpKTtcbiAgICAgICAgdGVzdFJ1bi5vbignYWN0aW9uLWRvbmUnLCBhc3luYyBhcmdzID0+IHRoaXMuX2VtaXRBY3Rpb25Eb25lKE9iamVjdC5hc3NpZ24oYXJncywgeyB0ZXN0UnVuIH0pKSk7XG5cbiAgICAgICAgdGVzdFJ1bi5vbmNlKCdzdGFydCcsIGFzeW5jICgpID0+IHRoaXMuX2VtaXRUZXN0UnVuU3RhcnQoKSk7XG4gICAgICAgIHRlc3RSdW4ub25jZSgncmVhZHknLCBhc3luYyAoKSA9PiB7XG4gICAgICAgICAgICBpZiAoIXRoaXMucXVhcmFudGluZSB8fCB0aGlzLl9pc0ZpcnN0UXVhcmFudGluZUF0dGVtcHQoKSlcbiAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLmVtaXQoJ3Rlc3QtcnVuLXJlYWR5Jyk7XG4gICAgICAgIH0pO1xuICAgICAgICB0ZXN0UnVuLm9uY2UoJ2JlZm9yZS1kb25lJywgKCkgPT4gdGhpcy5fdGVzdFJ1bkJlZm9yZURvbmUoKSk7XG4gICAgICAgIHRlc3RSdW4ub25jZSgnZG9uZScsICgpID0+IHRoaXMuX3Rlc3RSdW5Eb25lKCkpO1xuICAgICAgICB0ZXN0UnVuLm9uY2UoJ2Rpc2Nvbm5lY3RlZCcsICgpID0+IHRoaXMuX3Rlc3RSdW5EaXNjb25uZWN0ZWQoY29ubmVjdGlvbikpO1xuICAgIH1cblxuICAgIGdldCBibG9ja2VkICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZml4dHVyZUhvb2tDb250cm9sbGVyLmlzVGVzdEJsb2NrZWQodGhpcy50ZXN0KTtcbiAgICB9XG5cbiAgICBhc3luYyBzdGFydCAoY29ubmVjdGlvbikge1xuICAgICAgICBjb25zdCB0ZXN0UnVuID0gYXdhaXQgdGhpcy5fY3JlYXRlVGVzdFJ1bihjb25uZWN0aW9uKTtcblxuICAgICAgICBjb25zdCBob29rT2sgPSBhd2FpdCB0aGlzLmZpeHR1cmVIb29rQ29udHJvbGxlci5ydW5GaXh0dXJlQmVmb3JlSG9va0lmTmVjZXNzYXJ5KHRlc3RSdW4pO1xuXG4gICAgICAgIGlmICh0aGlzLnRlc3Quc2tpcCB8fCAhaG9va09rKSB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLmVtaXQoJ3Rlc3QtcnVuLXN0YXJ0Jyk7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLl9lbWl0VGVzdFJ1bkRvbmUoKTtcbiAgICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5fYXNzaWduVGVzdFJ1bkV2ZW50cyh0ZXN0UnVuLCBjb25uZWN0aW9uKTtcblxuICAgICAgICB0ZXN0UnVuLnN0YXJ0KCk7XG5cbiAgICAgICAgcmV0dXJuIFNlc3Npb25Db250cm9sbGVyLmdldFNlc3Npb25VcmwodGVzdFJ1biwgdGhpcy5wcm94eSk7XG4gICAgfVxufVxuIl19
\No newline at end of file