@aws-cdk-testing/cli-integ
Version:
Integration tests for the AWS CDK CLI
241 lines • 31 kB
JavaScript
;
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 () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.integTest = integTest;
exports.randomString = randomString;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const aws_1 = require("./aws");
const corking_1 = require("./corking");
(0, corking_1.registerSecrets)(...aws_1.CREDENTIAL_ENV_VARS.map(v => process.env[v]));
const SKIP_TESTS = [
...readSkipFile(path.join(__dirname, '..', 'skip-tests.txt')),
...readSkipFile(process.env.CDK_INTEG_SKIP_TESTS_FILE),
...(process.env.CDK_INTEG_SKIP_TESTS ?? '').split(','),
].map(x => x.trim())
.filter(x => x && !x.startsWith('#'));
if (SKIP_TESTS.length > 0) {
process.stderr.write(`ℹ️ Skipping tests: ${JSON.stringify(SKIP_TESTS)}\n`);
}
// Whether we want to stop after the first failure, for quicker debugging (hopefully).
const FAIL_FAST = process.env.FAIL_FAST === 'true';
// Keep track of whether the suite has failed. If so, we stop running.
let failed = false;
/**
* A wrapper for jest's 'test' which takes regression-disabled tests into account and prints a banner
*/
function integTest(name, callback, timeoutMillis) {
const runner = shouldSkip(name) ? test.skip : test;
jest.retryTimes(parseInt(process.env.JEST_RETRY_TIMES ?? '0'));
runner(name, async () => {
const output = new corking_1.MemoryStream();
output.write('================================================================\n');
output.write(`${name}\n`);
output.write('================================================================\n');
const start = Date.now();
let waitTime = 0;
process.stderr.write(`[INTEG TEST::${name}] Starting (pid ${process.pid})...\n`);
maybePrintMemoryUsage(name);
try {
if (FAIL_FAST && failed) {
throw new Error('FAIL_FAST requested and currently failing. Stopping test early.');
}
const ret = await callback({
output,
randomString: randomString(),
name,
log(s) {
output.write(`${s}\n`);
},
reportWaitTime(n) {
waitTime += n;
},
});
await writeLog(name, {
success: true,
output: output.toString(),
totalDuration: Date.now() - start,
waitTime,
});
return ret;
}
catch (e) {
// Print the buffered output, only if the test fails.
failed = true;
output.write(e.message);
output.write(e.stack);
await writeLog(name, {
success: false,
output: output.toString(),
totalDuration: Date.now() - start,
waitTime,
});
process.stderr.write(`[INTEG TEST::${name}] Failed: ${e}\n`);
const isGitHub = !!process.env.GITHUB_RUN_ID;
if (isGitHub) {
// GitHub Actions compatible output formatting
// https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#setting-an-error-message
let written = process.stderr.write(`::error title=Failed ${name}::${e.message}\n`);
if (!written) {
// Wait for drain
await new Promise((ok) => process.stderr.once('drain', ok));
}
// Print output only if the test fails. Use 'console.log' so the output is buffered by
// jest and prints without a stack trace (if verbose: false).
written = process.stdout.write([
`::group::Failure details: ${name} (click to expand)\n`,
`${output.buffer().toString()}\n`,
'::endgroup::\n',
].join(''));
if (!written) {
// Wait for drain
await new Promise((ok) => process.stdout.once('drain', ok));
}
}
else {
// Use 'console.log' so the output is buffered by
// jest and prints without a stack trace (if verbose: false).
// eslint-disable-next-line no-console
console.log(output.buffer().toString());
}
throw e;
}
finally {
const duration = Date.now() - start;
process.stderr.write(`[INTEG TEST::${name}] Done (${humanTime(duration)}).\n`);
maybePrintMemoryUsage(name);
}
}, timeoutMillis);
}
function shouldSkip(testName) {
return SKIP_TESTS.includes(testName);
}
function maybePrintMemoryUsage(testName) {
if (process.env.INTEG_MEMORY_DEBUG !== 'true') {
return;
}
const memoryUsage = process.memoryUsage();
const report = {};
for (const [key, value] of Object.entries(memoryUsage)) {
report[key] = `${Math.round(value / 1024 / 1024)} MB`;
}
process.stderr.write(`[INTEG TEST::${testName}] Memory Usage: ${JSON.stringify(report)}`);
}
function randomString() {
// Crazy
return Math.random().toString(36).replace(/[^a-z0-9]+/g, '');
}
/**
* Write log files
*
* Write a text log to `${INTEG_LOGS}/[FAILED-]description-of-test.txt`, and a single
* line of a Markdown table to `${INTEG_LOGS}/md/1-description-of-test.md`.
*
* The latter are designed to be globcatted to $GITHUB_STEP_SUMMARY after tests
* (we don't write there directly to avoid concurrency issues with multiple processes
* reading and mutating the same file).
*
* We do use `atomicWrite` to write files -- it's only necessary for the header file,
* which gets overwritten by every test, just to make sure it properly exists (shouldn't
* end up empty or with interleaved contents). The other writes are not
* contended and don't need to be atomic, but the function is just ergonomic to use.
*/
async function writeLog(testName, result) {
if (process.env.INTEG_LOGS) {
// Write the log file
const slug = slugify(testName);
const logFileName = `${process.env.INTEG_LOGS}/${result.success ? '' : 'FAILED-'}${slug}.txt`;
await atomicWrite(logFileName, result.output);
// Write a row for the markdown table
// Sort failures before successes, and the table header before all
const mdFileName = `${process.env.INTEG_LOGS}/md/${result.success ? '2' : '1'}-${slug}.md`;
const columns = [
['Result', result.success ? 'pass ✅' : 'fail ❌'],
['Test Name', testName],
['Test Duration', humanTime(result.totalDuration - result.waitTime)],
['Wait Time', result.waitTime > 0 ? humanTime(result.waitTime) : '-'],
];
await atomicWrite(`${process.env.INTEG_LOGS}/md/0-header.md`, [
`| ${columns.map(([col, _val]) => col).join(' | ')} |`,
`| ${columns.map(() => '-----------').join(' | ')} |`,
].map(x => `${x}\n`).join(''));
await atomicWrite(mdFileName, `| ${columns.map(([_col, val]) => val).join(' | ')} |\n`);
}
}
function humanTime(delta) {
const components = [];
const S = 1000;
const M = 60 * S;
const H = 60 * M;
const hours = Math.floor(delta / H);
if (hours > 0) {
components.push(`${hours}h`);
delta -= hours * H;
}
const minutes = Math.floor(delta / M);
if (minutes > 0) {
components.push(`${minutes}m`);
delta -= minutes * M;
}
const seconds = Math.floor(delta / S);
if (seconds > 0) {
components.push(`${seconds}s`);
delta -= seconds * S;
}
components.push(`${delta}ms`);
// Retain the 2 most significant components
return components.slice(0, 2).join('');
}
function slugify(x) {
return x.replace(/[^a-zA-Z0-9_,]+/g, '-');
}
async function atomicWrite(fileName, contents) {
await fs.promises.mkdir(path.dirname(fileName), { recursive: true });
const tmp = `${fileName}.${process.pid}`;
await fs.promises.writeFile(tmp, contents);
await fs.promises.rename(tmp, fileName);
}
function readSkipFile(filePath) {
if (!filePath) {
return [];
}
try {
return fs.readFileSync(filePath, { encoding: 'utf-8' }).split('\n');
}
catch {
return [];
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW50ZWctdGVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImludGVnLXRlc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFtQ0EsOEJBZ0dDO0FBa0JELG9DQUdDO0FBeEpELHVDQUF5QjtBQUN6QiwyQ0FBNkI7QUFDN0IsK0JBQTRDO0FBQzVDLHVDQUEwRDtBQUUxRCxJQUFBLHlCQUFlLEVBQUMsR0FBRyx5QkFBbUIsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBRSxDQUFDLENBQUMsQ0FBQztBQUVsRSxNQUFNLFVBQVUsR0FBRztJQUNqQixHQUFHLFlBQVksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxJQUFJLEVBQUUsZ0JBQWdCLENBQUMsQ0FBQztJQUM3RCxHQUFHLFlBQVksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLHlCQUF5QixDQUFDO0lBQ3RELEdBQUcsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLG9CQUFvQixJQUFJLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUM7Q0FDdkQsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUM7S0FDakIsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO0FBRXhDLElBQUksVUFBVSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztJQUMxQixPQUFPLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxzQkFBc0IsSUFBSSxDQUFDLFNBQVMsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLENBQUM7QUFDN0UsQ0FBQztBQUVELHNGQUFzRjtBQUN0RixNQUFNLFNBQVMsR0FBRyxP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QztBQUMxQyxDQUFDO0FBRUQsU0FBUyxZQUFZLENBQUMsUUFBaUI7SUFDckMsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBQ2QsT0FBTyxFQUFFLENBQUM7SUFDWixDQUFDO0lBQ0QsSUFBSSxDQUFDO1FBQ0gsT0FBTyxFQUFFLENBQUMsWUFBWSxDQUFDLFFBQVEsRUFBRSxFQUFFLFFBQVEsRUFBRSxPQUFPLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUN0RSxDQUFDO0lBQUMsTUFBTSxDQUFDO1FBQ1AsT0FBTyxFQUFFLENBQUM7SUFDWixDQUFDO0FBQ0gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIGZzIGZyb20gJ2ZzJztcbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgeyBDUkVERU5USUFMX0VOVl9WQVJTIH0gZnJvbSAnLi9hd3MnO1xuaW1wb3J0IHsgTWVtb3J5U3RyZWFtLCByZWdpc3RlclNlY3JldHMgfSBmcm9tICcuL2NvcmtpbmcnO1xuXG5yZWdpc3RlclNlY3JldHMoLi4uQ1JFREVOVElBTF9FTlZfVkFSUy5tYXAodiA9PiBwcm9jZXNzLmVudlt2XSEpKTtcblxuY29uc3QgU0tJUF9URVNUUyA9IFtcbiAgLi4ucmVhZFNraXBGaWxlKHBhdGguam9pbihfX2Rpcm5hbWUsICcuLicsICdza2lwLXRlc3RzLnR4dCcpKSxcbiAgLi4ucmVhZFNraXBGaWxlKHByb2Nlc3MuZW52LkNES19JTlRFR19TS0lQX1RFU1RTX0ZJTEUpLFxuICAuLi4ocHJvY2Vzcy5lbnYuQ0RLX0lOVEVHX1NLSVBfVEVTVFMgPz8gJycpLnNwbGl0KCcsJyksXG5dLm1hcCh4ID0+IHgudHJpbSgpKVxuICAuZmlsdGVyKHggPT4geCAmJiAheC5zdGFydHNXaXRoKCcjJykpO1xuXG5pZiAoU0tJUF9URVNUUy5sZW5ndGggPiAwKSB7XG4gIHByb2Nlc3Muc3RkZXJyLndyaXRlKGDihLnvuI8gU2tpcHBpbmcgdGVzdHM6ICR7SlNPTi5zdHJpbmdpZnkoU0tJUF9URVNUUyl9XFxuYCk7XG59XG5cbi8vIFdoZXRoZXIgd2Ugd2FudCB0byBzdG9wIGFmdGVyIHRoZSBmaXJzdCBmYWlsdXJlLCBmb3IgcXVpY2tlciBkZWJ1Z2dpbmcgKGhvcGVmdWxseSkuXG5jb25zdCBGQUlMX0ZBU1QgPSBwcm9jZXNzLmVudi5GQUlMX0ZBU1QgPT09ICd0cnVlJztcblxuLy8gS2VlcCB0cmFjayBvZiB3aGV0aGVyIHRoZSBzdWl0ZSBoYXMgZmFpbGVkLiBJZiBzbywgd2Ugc3RvcCBydW5uaW5nLlxubGV0IGZhaWxlZCA9IGZhbHNlO1xuXG5leHBvcnQgaW50ZXJmYWNlIFRlc3RDb250ZXh0IHtcbiAgcmVhZG9ubHkgcmFuZG9tU3RyaW5nOiBzdHJpbmc7XG4gIHJlYWRvbmx5IG5hbWU6IHN0cmluZztcbiAgcmVhZG9ubHkgb3V0cHV0OiBOb2RlSlMuV3JpdGFibGVTdHJlYW07XG4gIGxvZyhzOiBzdHJpbmcpOiB2b2lkO1xuICByZXBvcnRXYWl0VGltZShtczogbnVtYmVyKTogdm9pZDtcbn1cblxuLyoqXG4gKiBBIHdyYXBwZXIgZm9yIGplc3QncyAndGVzdCcgd2hpY2ggdGFrZXMgcmVncmVzc2lvbi1kaXNhYmxlZCB0ZXN0cyBpbnRvIGFjY291bnQgYW5kIHByaW50cyBhIGJhbm5lclxuICovXG5leHBvcnQgZnVuY3Rpb24gaW50ZWdUZXN0KFxuICBuYW1lOiBzdHJpbmcsXG4gIGNhbGxiYWNrOiAoY29udGV4dDogVGVzdENvbnRleHQpID0+IFByb21pc2U8dm9pZD4sXG4gIHRpbWVvdXRNaWxsaXM/OiBudW1iZXIsXG4pOiB2b2lkIHtcbiAgY29uc3QgcnVubmVyID0gc2hvdWxkU2tpcChuYW1lKSA/IHRlc3Quc2tpcCA6IHRlc3Q7XG5cbiAgamVzdC5yZXRyeVRpbWVzKHBhcnNlSW50KHByb2Nlc3MuZW52LkpFU1RfUkVUUllfVElNRVMgPz8gJzAnKSk7XG5cbiAgcnVubmVyKG5hbWUsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBvdXRwdXQgPSBuZXcgTWVtb3J5U3RyZWFtKCk7XG5cbiAgICBvdXRwdXQud3JpdGUoJz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cXG4nKTtcbiAgICBvdXRwdXQud3JpdGUoYCR7bmFtZX1cXG5gKTtcbiAgICBvdXRwdXQud3JpdGUoJz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cXG4nKTtcblxuICAgIGNvbnN0IHN0YXJ0ID0gRGF0ZS5ub3coKTtcbiAgICBsZXQgd2FpdFRpbWUgPSAwO1xuXG4gICAgcHJvY2Vzcy5zdGRlcnIud3JpdGUoYFtJTlRFRyBURVNUOjoke25hbWV9XSBTdGFydGluZyAocGlkICR7cHJvY2Vzcy5waWR9KS4uLlxcbmApO1xuICAgIG1heWJlUHJpbnRNZW1vcnlVc2FnZShuYW1lKTtcbiAgICB0cnkge1xuICAgICAgaWYgKEZBSUxfRkFTVCAmJiBmYWlsZWQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdGQUlMX0ZBU1QgcmVxdWVzdGVkIGFuZCBjdXJyZW50bHkgZmFpbGluZy4gU3RvcHBpbmcgdGVzdCBlYXJseS4nKTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgcmV0ID0gYXdhaXQgY2FsbGJhY2soe1xuICAgICAgICBvdXRwdXQsXG4gICAgICAgIHJhbmRvbVN0cmluZzogcmFuZG9tU3RyaW5nKCksXG4gICAgICAgIG5hbWUsXG4gICAgICAgIGxvZyhzOiBzdHJpbmcpIHtcbiAgICAgICAgICBvdXRwdXQud3JpdGUoYCR7c31cXG5gKTtcbiAgICAgICAgfSxcbiAgICAgICAgcmVwb3J0V2FpdFRpbWUobikge1xuICAgICAgICAgIHdhaXRUaW1lICs9IG47XG4gICAgICAgIH0sXG4gICAgICB9KTtcblxuICAgICAgYXdhaXQgd3JpdGVMb2cobmFtZSwge1xuICAgICAgICBzdWNjZXNzOiB0cnVlLFxuICAgICAgICBvdXRwdXQ6IG91dHB1dC50b1N0cmluZygpLFxuICAgICAgICB0b3RhbER1cmF0aW9uOiBEYXRlLm5vdygpIC0gc3RhcnQsXG4gICAgICAgIHdhaXRUaW1lLFxuICAgICAgfSk7XG5cbiAgICAgIHJldHVybiByZXQ7XG4gICAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgICAvLyBQcmludCB0aGUgYnVmZmVyZWQgb3V0cHV0LCBvbmx5IGlmIHRoZSB0ZXN0IGZhaWxzLlxuICAgICAgZmFpbGVkID0gdHJ1ZTtcblxuICAgICAgb3V0cHV0LndyaXRlKGUubWVzc2FnZSk7XG4gICAgICBvdXRwdXQud3JpdGUoZS5zdGFjayk7XG5cbiAgICAgIGF3YWl0IHdyaXRlTG9nKG5hbWUsIHtcbiAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgIG91dHB1dDogb3V0cHV0LnRvU3RyaW5nKCksXG4gICAgICAgIHRvdGFsRHVyYXRpb246IERhdGUubm93KCkgLSBzdGFydCxcbiAgICAgICAgd2FpdFRpbWUsXG4gICAgICB9KTtcbiAgICAgIHByb2Nlc3Muc3RkZXJyLndyaXRlKGBbSU5URUcgVEVTVDo6JHtuYW1lfV0gRmFpbGVkOiAke2V9XFxuYCk7XG5cbiAgICAgIGNvbnN0IGlzR2l0SHViID0gISFwcm9jZXNzLmVudi5HSVRIVUJfUlVOX0lEO1xuXG4gICAgICBpZiAoaXNHaXRIdWIpIHtcbiAgICAgICAgLy8gR2l0SHViIEFjdGlvbnMgY29tcGF0aWJsZSBvdXRwdXQgZm9ybWF0dGluZ1xuICAgICAgICAvLyBodHRwczovL2RvY3MuZ2l0aHViLmNvbS9lbi9hY3Rpb25zL3dyaXRpbmctd29ya2Zsb3dzL2Nob29zaW5nLXdoYXQteW91ci13b3JrZmxvdy1kb2VzL3dvcmtmbG93LWNvbW1hbmRzLWZvci1naXRodWItYWN0aW9ucyNzZXR0aW5nLWFuLWVycm9yLW1lc3NhZ2VcbiAgICAgICAgbGV0IHdyaXR0ZW4gPSBwcm9jZXNzLnN0ZGVyci53cml0ZShgOjplcnJvciB0aXRsZT1GYWlsZWQgJHtuYW1lfTo6JHtlLm1lc3NhZ2V9XFxuYCk7XG4gICAgICAgIGlmICghd3JpdHRlbikge1xuICAgICAgICAgIC8vIFdhaXQgZm9yIGRyYWluXG4gICAgICAgICAgYXdhaXQgbmV3IFByb21pc2UoKG9rKSA9PiBwcm9jZXNzLnN0ZGVyci5vbmNlKCdkcmFpbicsIG9rKSk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBQcmludCBvdXRwdXQgb25seSBpZiB0aGUgdGVzdCBmYWlscy4gVXNlICdjb25zb2xlLmxvZycgc28gdGhlIG91dHB1dCBpcyBidWZmZXJlZCBieVxuICAgICAgICAvLyBqZXN0IGFuZCBwcmludHMgd2l0aG91dCBhIHN0YWNrIHRyYWNlIChpZiB2ZXJib3NlOiBmYWxzZSkuXG4gICAgICAgIHdyaXR0ZW4gPSBwcm9jZXNzLnN0ZG91dC53cml0ZShbXG4gICAgICAgICAgYDo6Z3JvdXA6OkZhaWx1cmUgZGV0YWlsczogJHtuYW1lfSAoY2xpY2sgdG8gZXhwYW5kKVxcbmAsXG4gICAgICAgICAgYCR7b3V0cHV0LmJ1ZmZlcigpLnRvU3RyaW5nKCl9XFxuYCxcbiAgICAgICAgICAnOjplbmRncm91cDo6XFxuJyxcbiAgICAgICAgXS5qb2luKCcnKSk7XG4gICAgICAgIGlmICghd3JpdHRlbikge1xuICAgICAgICAgIC8vIFdhaXQgZm9yIGRyYWluXG4gICAgICAgICAgYXdhaXQgbmV3IFByb21pc2UoKG9rKSA9PiBwcm9jZXNzLnN0ZG91dC5vbmNlKCdkcmFpbicsIG9rKSk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIFVzZSAnY29uc29sZS5sb2cnIHNvIHRoZSBvdXRwdXQgaXMgYnVmZmVyZWQgYnlcbiAgICAgICAgLy8gamVzdCBhbmQgcHJpbnRzIHdpdGhvdXQgYSBzdGFjayB0cmFjZSAoaWYgdmVyYm9zZTogZmFsc2UpLlxuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tY29uc29sZVxuICAgICAgICBjb25zb2xlLmxvZyhvdXRwdXQuYnVmZmVyKCkudG9TdHJpbmcoKSk7XG4gICAgICB9XG4gICAgICB0aHJvdyBlO1xuICAgIH0gZmluYWxseSB7XG4gICAgICBjb25zdCBkdXJhdGlvbiA9IERhdGUubm93KCkgLSBzdGFydDtcbiAgICAgIHByb2Nlc3Muc3RkZXJyLndyaXRlKGBbSU5URUcgVEVTVDo6JHtuYW1lfV0gRG9uZSAoJHtodW1hblRpbWUoZHVyYXRpb24pfSkuXFxuYCk7XG4gICAgICBtYXliZVByaW50TWVtb3J5VXNhZ2UobmFtZSk7XG4gICAgfVxuICB9LCB0aW1lb3V0TWlsbGlzKTtcbn1cblxuZnVuY3Rpb24gc2hvdWxkU2tpcCh0ZXN0TmFtZTogc3RyaW5nKSB7XG4gIHJldHVybiBTS0lQX1RFU1RTLmluY2x1ZGVzKHRlc3ROYW1lKTtcbn1cblxuZnVuY3Rpb24gbWF5YmVQcmludE1lbW9yeVVzYWdlKHRlc3ROYW1lOiBzdHJpbmcpIHtcbiAgaWYgKHByb2Nlc3MuZW52LklOVEVHX01FTU9SWV9ERUJVRyAhPT0gJ3RydWUnKSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIGNvbnN0IG1lbW9yeVVzYWdlID0gcHJvY2Vzcy5tZW1vcnlVc2FnZSgpIGFzIGFueTtcbiAgY29uc3QgcmVwb3J0OiBhbnkgPSB7fTtcbiAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMobWVtb3J5VXNhZ2UpKSB7XG4gICAgcmVwb3J0W2tleV0gPSBgJHtNYXRoLnJvdW5kKHZhbHVlIGFzIG51bWJlciAvIDEwMjQgLyAxMDI0KX0gTUJgO1xuICB9XG4gIHByb2Nlc3Muc3RkZXJyLndyaXRlKGBbSU5URUcgVEVTVDo6JHt0ZXN0TmFtZX1dIE1lbW9yeSBVc2FnZTogJHtKU09OLnN0cmluZ2lmeShyZXBvcnQpfWApO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcmFuZG9tU3RyaW5nKCkge1xuICAvLyBDcmF6eVxuICByZXR1cm4gTWF0aC5yYW5kb20oKS50b1N0cmluZygzNikucmVwbGFjZSgvW15hLXowLTldKy9nLCAnJyk7XG59XG5cbi8qKlxuICogV3JpdGUgbG9nIGZpbGVzXG4gKlxuICogV3JpdGUgYSB0ZXh0IGxvZyB0byBgJHtJTlRFR19MT0dTfS9bRkFJTEVELV1kZXNjcmlwdGlvbi1vZi10ZXN0LnR4dGAsIGFuZCBhIHNpbmdsZVxuICogbGluZSBvZiBhIE1hcmtkb3duIHRhYmxlIHRvIGAke0lOVEVHX0xPR1N9L21kLzEtZGVzY3JpcHRpb24tb2YtdGVzdC5tZGAuXG4gKlxuICogVGhlIGxhdHRlciBhcmUgZGVzaWduZWQgdG8gYmUgZ2xvYmNhdHRlZCB0byAkR0lUSFVCX1NURVBfU1VNTUFSWSBhZnRlciB0ZXN0c1xuICogKHdlIGRvbid0IHdyaXRlIHRoZXJlIGRpcmVjdGx5IHRvIGF2b2lkIGNvbmN1cnJlbmN5IGlzc3VlcyB3aXRoIG11bHRpcGxlIHByb2Nlc3Nlc1xuICogcmVhZGluZyBhbmQgbXV0YXRpbmcgdGhlIHNhbWUgZmlsZSkuXG4gKlxuICogV2UgZG8gdXNlIGBhdG9taWNXcml0ZWAgdG8gd3JpdGUgZmlsZXMgLS0gaXQncyBvbmx5IG5lY2Vzc2FyeSBmb3IgdGhlIGhlYWRlciBmaWxlLFxuICogd2hpY2ggZ2V0cyBvdmVyd3JpdHRlbiBieSBldmVyeSB0ZXN0LCBqdXN0IHRvIG1ha2Ugc3VyZSBpdCBwcm9wZXJseSBleGlzdHMgKHNob3VsZG4ndFxuICogZW5kIHVwIGVtcHR5IG9yIHdpdGggaW50ZXJsZWF2ZWQgY29udGVudHMpLiBUaGUgb3RoZXIgd3JpdGVzIGFyZSBub3RcbiAqIGNvbnRlbmRlZCBhbmQgZG9uJ3QgbmVlZCB0byBiZSBhdG9taWMsIGJ1dCB0aGUgZnVuY3Rpb24gaXMganVzdCBlcmdvbm9taWMgdG8gdXNlLlxuICovXG5hc3luYyBmdW5jdGlvbiB3cml0ZUxvZyh0ZXN0TmFtZTogc3RyaW5nLCByZXN1bHQ6IHtcbiAgc3VjY2VzczogYm9vbGVhbjtcbiAgb3V0cHV0OiBzdHJpbmc7XG4gIHRvdGFsRHVyYXRpb246IG51bWJlcjtcbiAgd2FpdFRpbWU6IG51bWJlcjtcbn0pIHtcbiAgaWYgKHByb2Nlc3MuZW52LklOVEVHX0xPR1MpIHtcbiAgICAvLyBXcml0ZSB0aGUgbG9nIGZpbGVcbiAgICBjb25zdCBzbHVnID0gc2x1Z2lmeSh0ZXN0TmFtZSk7XG4gICAgY29uc3QgbG9nRmlsZU5hbWUgPSBgJHtwcm9jZXNzLmVudi5JTlRFR19MT0dTfS8ke3Jlc3VsdC5zdWNjZXNzID8gJycgOiAnRkFJTEVELSd9JHtzbHVnfS50eHRgO1xuICAgIGF3YWl0IGF0b21pY1dyaXRlKGxvZ0ZpbGVOYW1lLCByZXN1bHQub3V0cHV0KTtcblxuICAgIC8vIFdyaXRlIGEgcm93IGZvciB0aGUgbWFya2Rvd24gdGFibGVcbiAgICAvLyBTb3J0IGZhaWx1cmVzIGJlZm9yZSBzdWNjZXNzZXMsIGFuZCB0aGUgdGFibGUgaGVhZGVyIGJlZm9yZSBhbGxcbiAgICBjb25zdCBtZEZpbGVOYW1lID0gYCR7cHJvY2Vzcy5lbnYuSU5URUdfTE9HU30vbWQvJHtyZXN1bHQuc3VjY2VzcyA/ICcyJyA6ICcxJ30tJHtzbHVnfS5tZGA7XG4gICAgY29uc3QgY29sdW1uczogQXJyYXk8W3N0cmluZywgc3RyaW5nXT4gPSBbXG4gICAgICBbJ1Jlc3VsdCcsIHJlc3VsdC5zdWNjZXNzID8gJ3Bhc3Mg4pyFJyA6ICdmYWlsIOKdjCddLFxuICAgICAgWydUZXN0IE5hbWUnLCB0ZXN0TmFtZV0sXG4gICAgICBbJ1Rlc3QgRHVyYXRpb24nLCBodW1hblRpbWUocmVzdWx0LnRvdGFsRHVyYXRpb24gLSByZXN1bHQud2FpdFRpbWUpXSxcbiAgICAgIFsnV2FpdCBUaW1lJywgcmVzdWx0LndhaXRUaW1lID4gMCA/IGh1bWFuVGltZShyZXN1bHQud2FpdFRpbWUpIDogJy0nXSxcbiAgICBdO1xuICAgIGF3YWl0IGF0b21pY1dyaXRlKGAke3Byb2Nlc3MuZW52LklOVEVHX0xPR1N9L21kLzAtaGVhZGVyLm1kYCwgW1xuICAgICAgYHwgJHtjb2x1bW5zLm1hcCgoW2NvbCwgX3ZhbF0pID0+IGNvbCkuam9pbignIHwgJyl9IHxgLFxuICAgICAgYHwgJHtjb2x1bW5zLm1hcCgoKSA9PiAnLS0tLS0tLS0tLS0nKS5qb2luKCcgfCAnKX0gfGAsXG4gICAgXS5tYXAoeCA9PiBgJHt4fVxcbmApLmpvaW4oJycpKTtcbiAgICBhd2FpdCBhdG9taWNXcml0ZShtZEZpbGVOYW1lLFxuICAgICAgYHwgJHtjb2x1bW5zLm1hcCgoW19jb2wsIHZhbF0pID0+IHZhbCkuam9pbignIHwgJyl9IHxcXG5gKTtcbiAgfVxufVxuXG5mdW5jdGlvbiBodW1hblRpbWUoZGVsdGE6IG51bWJlcikge1xuICBjb25zdCBjb21wb25lbnRzID0gW107XG5cbiAgY29uc3QgUyA9IDEwMDA7XG4gIGNvbnN0IE0gPSA2MCAqIFM7XG4gIGNvbnN0IEggPSA2MCAqIE07XG5cbiAgY29uc3QgaG91cnMgPSBNYXRoLmZsb29yKGRlbHRhIC8gSCk7XG4gIGlmIChob3VycyA+IDApIHtcbiAgICBjb21wb25lbnRzLnB1c2goYCR7aG91cnN9aGApO1xuICAgIGRlbHRhIC09IGhvdXJzICogSDtcbiAgfVxuICBjb25zdCBtaW51dGVzID0gTWF0aC5mbG9vcihkZWx0YSAvIE0pO1xuICBpZiAobWludXRlcyA+IDApIHtcbiAgICBjb21wb25lbnRzLnB1c2goYCR7bWludXRlc31tYCk7XG4gICAgZGVsdGEgLT0gbWludXRlcyAqIE07XG4gIH1cbiAgY29uc3Qgc2Vjb25kcyA9IE1hdGguZmxvb3IoZGVsdGEgLyBTKTtcbiAgaWYgKHNlY29uZHMgPiAwKSB7XG4gICAgY29tcG9uZW50cy5wdXNoKGAke3NlY29uZHN9c2ApO1xuICAgIGRlbHRhIC09IHNlY29uZHMgKiBTO1xuICB9XG4gIGNvbXBvbmVudHMucHVzaChgJHtkZWx0YX1tc2ApO1xuXG4gIC8vIFJldGFpbiB0aGUgMiBtb3N0IHNpZ25pZmljYW50IGNvbXBvbmVudHNcbiAgcmV0dXJuIGNvbXBvbmVudHMuc2xpY2UoMCwgMikuam9pbignJyk7XG59XG5cbmZ1bmN0aW9uIHNsdWdpZnkoeDogc3RyaW5nKSB7XG4gIHJldHVybiB4LnJlcGxhY2UoL1teYS16QS1aMC05XyxdKy9nLCAnLScpO1xufVxuXG5hc3luYyBmdW5jdGlvbiBhdG9taWNXcml0ZShmaWxlTmFtZTogc3RyaW5nLCBjb250ZW50czogc3RyaW5nKSB7XG4gIGF3YWl0IGZzLnByb21pc2VzLm1rZGlyKHBhdGguZGlybmFtZShmaWxlTmFtZSksIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuXG4gIGNvbnN0IHRtcCA9IGAke2ZpbGVOYW1lfS4ke3Byb2Nlc3MucGlkfWA7XG4gIGF3YWl0IGZzLnByb21pc2VzLndyaXRlRmlsZSh0bXAsIGNvbnRlbnRzKTtcbiAgYXdhaXQgZnMucHJvbWlzZXMucmVuYW1lKHRtcCwgZmlsZU5hbWUpO1xufVxuXG5mdW5jdGlvbiByZWFkU2tpcEZpbGUoZmlsZVBhdGg/OiBzdHJpbmcpOiBzdHJpbmdbXSB7XG4gIGlmICghZmlsZVBhdGgpIHtcbiAgICByZXR1cm4gW107XG4gIH1cbiAgdHJ5IHtcbiAgICByZXR1cm4gZnMucmVhZEZpbGVTeW5jKGZpbGVQYXRoLCB7IGVuY29kaW5nOiAndXRmLTgnIH0pLnNwbGl0KCdcXG4nKTtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIFtdO1xuICB9XG59XG4iXX0=