faastjs
Version:
Serverless batch computing made simple.
176 lines • 25.9 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const ava_1 = tslib_1.__importDefault(require("ava"));
const uuid_1 = require("uuid");
const index_1 = require("../index");
const aws_faast_1 = require("../src/aws/aws-faast");
const functions = tslib_1.__importStar(require("./fixtures/functions"));
const util_1 = require("./fixtures/util");
const util_aws_1 = require("./fixtures/util-aws");
const assert_1 = tslib_1.__importDefault(require("assert"));
async function waitForLogGroupCreation(cloudwatch, logGroupName, message) {
let n = 0;
while (true) {
await (0, util_1.sleep)(1000);
try {
n++;
const described = await cloudwatch.describeLogGroups({
logGroupNamePrefix: logGroupName
});
if (!described.logGroups) {
continue;
}
const retrievedLogGroup = described.logGroups?.[0]?.logGroupName;
if (!retrievedLogGroup) {
continue;
}
(0, assert_1.default)(retrievedLogGroup === logGroupName, `Unexpected logGroupName: ${retrievedLogGroup}, expecting ${logGroupName}`);
const logResult = await cloudwatch.filterLogEvents({ logGroupName });
const events = logResult.events ?? [];
// console.log(`[${n}] Found log group: ${logGroupName}`);
let foundMessage = false;
for (const event of events) {
// console.log(
// `[${n}] ${event.logStreamName} ${event.eventId} ${event.timestamp} ${event.message}`
// );
if (event.message.includes(message)) {
foundMessage = true;
}
if (foundMessage && event.message.match(/REPORT RequestId/)) {
return;
}
}
}
catch (err) {
console.error(`Transient error waiting for log group creation: ${err}`);
}
}
}
ava_1.default.serial((0, util_1.title)("aws", "garbage collects functions that are called"), async (t) => {
// Idea behind this test: create a faast module and make a call. Then
// cleanup while leaving the resources in place. Then create another faast
// module and set its retention to 0, and use a synthetic gc worker to
// observe and verify the garbage collector actually cleans up.
const mod = await (0, index_1.faastAws)(functions, {
gc: "off",
mode: "queue",
description: t.title,
packageJson: {
name: (0, uuid_1.v4)(),
dependencies: {
tslib: "^1.9.1"
}
},
maxRetries: 0
});
try {
await mod.functions.consoleLog("gc-test-string");
const { cloudwatch } = mod.state.services;
const { logGroupName } = mod.state.resources;
await waitForLogGroupCreation(cloudwatch, logGroupName, "gc-test-string");
await mod.cleanup({ deleteResources: false, gcTimeout: 0 });
// Create some work for gc to do by removing the log retention policy, gc
// should add it back.
const deleteRetentionPolicy = (0, index_1.throttle)({ concurrency: 1, retry: 5 }, () => cloudwatch.deleteRetentionPolicy({ logGroupName }));
await deleteRetentionPolicy();
let deletedLayer = false;
const { layer, FunctionName } = mod.state.resources;
// log.gc.enabled = true;
const mod2 = await (0, index_1.faastAws)(functions, {
gc: "force",
retentionInDays: 0,
description: t.title,
_gcWorker: async (work, services) => {
switch (work.type) {
case "SetLogRetention":
// checkResourcesCleanedUp will verify the log group is
// deleted.
await (0, aws_faast_1.defaultGcWorker)(work, services);
break;
case "DeleteLayerVersion":
if (work.LayerName === layer.LayerName) {
index_1.log.gc(`deleting layer ${work.LayerName}`);
await (0, aws_faast_1.defaultGcWorker)(work, services);
deletedLayer = true;
}
break;
case "DeleteResources":
if (work.resources.FunctionName === FunctionName) {
index_1.log.gc(`deleting resources for ${FunctionName}`);
await (0, aws_faast_1.defaultGcWorker)(work, services);
}
}
}
});
await mod2.cleanup({ gcTimeout: 0 });
t.true(deletedLayer, "Deleted layer is true");
await (0, util_1.checkResourcesCleanedUp)(t, await (0, util_aws_1.getAWSResources)(mod, true));
}
finally {
index_1.log.gc.enabled = false;
await mod.cleanup({ deleteResources: true, deleteCaches: true, gcTimeout: 0 });
}
});
ava_1.default.serial((0, util_1.title)("aws", "garbage collects functions that are never called"), async (t) => {
const mod = await (0, index_1.faastAws)(functions, {
gc: "off",
mode: "queue",
description: t.title,
maxRetries: 0
});
try {
await mod.cleanup({ deleteResources: false, gcTimeout: 0 });
const { FunctionName } = mod.state.resources;
const mod2 = await (0, index_1.faastAws)(functions, {
gc: "force",
retentionInDays: 0,
description: t.title,
_gcWorker: async (work, services) => {
switch (work.type) {
case "DeleteResources":
if (work.resources.FunctionName === FunctionName) {
index_1.log.gc(`deleting resources for ${FunctionName}`);
await (0, aws_faast_1.defaultGcWorker)(work, services);
}
}
}
});
await mod2.cleanup({ gcTimeout: 0 });
// Don't fail if a log group exists because we didn't wait for its
// creation; it might be created by AWS after the cleanup occurs. The
// reason is that the log group will only be created if there's an
// invocation test, which only happens in the special case that the role
// was recently created. Which is true for the nightly testsuite but
// rarely elsewhere.
const { logGroupResult, ...resources } = await (0, util_aws_1.getAWSResources)(mod, true);
await (0, util_1.checkResourcesCleanedUp)(t, resources);
}
finally {
await mod.cleanup({ deleteResources: true, deleteCaches: true, gcTimeout: 0 });
}
});
ava_1.default.skip((0, util_1.title)("aws", "garbage collection caching"), async (t) => {
{
// Run a real gc so the build account doesn't accumulate garbage.
const mod = await (0, index_1.faastAws)(functions, { gc: "force", description: t.title });
await mod.cleanup({ gcTimeout: 0 });
t.is(await mod.state.gcPromise, "done");
}
{
// Test the in-memory cache that prevents gc from multiple faast.js
// instances from running at the same time.
const mod = await (0, index_1.faastAws)(functions, { description: t.title });
await mod.cleanup();
t.is(await mod.state.gcPromise, "skipped");
}
{
// Test the persistent cache that prevents gc from running too often
// even across processes.
(0, aws_faast_1.clearLastGc)();
const mod = await (0, index_1.faastAws)(functions, { description: t.title });
await mod.cleanup();
t.is(await mod.state.gcPromise, "skipped");
}
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXdzLWdjLnRlc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90ZXN0L2F3cy1nYy50ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUNBLHNEQUF1QjtBQUN2QiwrQkFBa0M7QUFDbEMsb0NBQW1EO0FBQ25ELG9EQUFvRTtBQUNwRSx3RUFBa0Q7QUFDbEQsMENBQXdFO0FBQ3hFLGtEQUFzRDtBQUN0RCw0REFBNEI7QUFFNUIsS0FBSyxVQUFVLHVCQUF1QixDQUNsQyxVQUEwQixFQUMxQixZQUFvQixFQUNwQixPQUFlO0lBRWYsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ1YsT0FBTyxJQUFJLEVBQUU7UUFDVCxNQUFNLElBQUEsWUFBSyxFQUFDLElBQUksQ0FBQyxDQUFDO1FBQ2xCLElBQUk7WUFDQSxDQUFDLEVBQUUsQ0FBQztZQUNKLE1BQU0sU0FBUyxHQUFHLE1BQU0sVUFBVSxDQUFDLGlCQUFpQixDQUFDO2dCQUNqRCxrQkFBa0IsRUFBRSxZQUFZO2FBQ25DLENBQUMsQ0FBQztZQUNILElBQUksQ0FBQyxTQUFTLENBQUMsU0FBUyxFQUFFO2dCQUN0QixTQUFTO2FBQ1o7WUFDRCxNQUFNLGlCQUFpQixHQUFHLFNBQVMsQ0FBQyxTQUFTLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxZQUFZLENBQUM7WUFDakUsSUFBSSxDQUFDLGlCQUFpQixFQUFFO2dCQUNwQixTQUFTO2FBQ1o7WUFDRCxJQUFBLGdCQUFNLEVBQ0YsaUJBQWlCLEtBQUssWUFBWSxFQUNsQyw0QkFBNEIsaUJBQWlCLGVBQWUsWUFBWSxFQUFFLENBQzdFLENBQUM7WUFDRixNQUFNLFNBQVMsR0FBRyxNQUFNLFVBQVUsQ0FBQyxlQUFlLENBQUMsRUFBRSxZQUFZLEVBQUUsQ0FBQyxDQUFDO1lBQ3JFLE1BQU0sTUFBTSxHQUFHLFNBQVMsQ0FBQyxNQUFNLElBQUksRUFBRSxDQUFDO1lBQ3RDLDBEQUEwRDtZQUMxRCxJQUFJLFlBQVksR0FBRyxLQUFL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QUFFLENBQUM7UUFDZCxNQUFNLEdBQUcsR0FBRyxNQUFNLElBQUEsZ0JBQVEsRUFBQyxTQUFTLEVBQUUsRUFBRSxXQUFXLEVBQUUsQ0FBQyxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUM7UUFDaEUsTUFBTSxHQUFHLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDcEIsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxLQUFLLENBQUMsU0FBUyxFQUFFLFNBQVMsQ0FBQyxDQUFDO0tBQzlDO0FBQ0wsQ0FBQyxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDbG91ZFdhdGNoTG9ncyB9IGZyb20gXCJAYXdzLXNkay9jbGllbnQtY2xvdWR3YXRjaC1sb2dzXCI7XG5pbXBvcnQgdGVzdCBmcm9tIFwiYXZhXCI7XG5pbXBvcnQgeyB2NCBhcyB1dWlkIH0gZnJvbSBcInV1aWRcIjtcbmltcG9ydCB7IGZhYXN0QXdzLCBsb2csIHRocm90dGxlIH0gZnJvbSBcIi4uL2luZGV4XCI7XG5pbXBvcnQgeyBjbGVhckxhc3RHYywgZGVmYXVsdEdjV29ya2VyIH0gZnJvbSBcIi4uL3NyYy9hd3MvYXdzLWZhYXN0XCI7XG5pbXBvcnQgKiBhcyBmdW5jdGlvbnMgZnJvbSBcIi4vZml4dHVyZXMvZnVuY3Rpb25zXCI7XG5pbXBvcnQgeyBjaGVja1Jlc291cmNlc0NsZWFuZWRVcCwgc2xlZXAsIHRpdGxlIH0gZnJvbSBcIi4vZml4dHVyZXMvdXRpbFwiO1xuaW1wb3J0IHsgZ2V0QVdTUmVzb3VyY2VzIH0gZnJvbSBcIi4vZml4dHVyZXMvdXRpbC1hd3NcIjtcbmltcG9ydCBhc3NlcnQgZnJvbSBcImFzc2VydFwiO1xuXG5hc3luYyBmdW5jdGlvbiB3YWl0Rm9yTG9nR3JvdXBDcmVhdGlvbihcbiAgICBjbG91ZHdhdGNoOiBDbG91ZFdhdGNoTG9ncyxcbiAgICBsb2dHcm91cE5hbWU6IHN0cmluZyxcbiAgICBtZXNzYWdlOiBzdHJpbmdcbikge1xuICAgIGxldCBuID0gMDtcbiAgICB3aGlsZSAodHJ1ZSkge1xuICAgICAgICBhd2FpdCBzbGVlcCgxMDAwKTtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIG4rKztcbiAgICAgICAgICAgIGNvbnN0IGRlc2NyaWJlZCA9IGF3YWl0IGNsb3Vkd2F0Y2guZGVzY3JpYmVMb2dHcm91cHMoe1xuICAgICAgICAgICAgICAgIGxvZ0dyb3VwTmFtZVByZWZpeDogbG9nR3JvdXBOYW1lXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIGlmICghZGVzY3JpYmVkLmxvZ0dyb3Vwcykge1xuICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY29uc3QgcmV0cmlldmVkTG9nR3JvdXAgPSBkZXNjcmliZWQubG9nR3JvdXBzPy5bMF0/LmxvZ0dyb3VwTmFtZTtcbiAgICAgICAgICAgIGlmICghcmV0cmlldmVkTG9nR3JvdXApIHtcbiAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGFzc2VydChcbiAgICAgICAgICAgICAgICByZXRyaWV2ZWRMb2dHcm91cCA9PT0gbG9nR3JvdXBOYW1lLFxuICAgICAgICAgICAgICAgIGBVbmV4cGVjdGVkIGxvZ0dyb3VwTmFtZTogJHtyZXRyaWV2ZWRMb2dHcm91cH0sIGV4cGVjdGluZyAke2xvZ0dyb3VwTmFtZX1gXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgY29uc3QgbG9nUmVzdWx0ID0gYXdhaXQgY2xvdWR3YXRjaC5maWx0ZXJMb2dFdmVudHMoeyBsb2dHcm91cE5hbWUgfSk7XG4gICAgICAgICAgICBjb25zdCBldmVudHMgPSBsb2dSZXN1bHQuZXZlbnRzID8/IFtdO1xuICAgICAgICAgICAgLy8gY29uc29sZS5sb2coYFske259XSBGb3VuZCBsb2cgZ3JvdXA6ICR7bG9nR3JvdXBOYW1lfWApO1xuICAgICAgICAgICAgbGV0IGZvdW5kTWVzc2FnZSA9IGZhbHNlO1xuICAgICAgICAgICAgZm9yIChjb25zdCBldmVudCBvZiBldmVudHMpIHtcbiAgICAgICAgICAgICAgICAvLyBjb25zb2xlLmxvZyhcbiAgICAgICAgICAgICAgICAvLyAgICAgYFske259XSAke2V2ZW50LmxvZ1N0cmVhbU5hbWV9ICR7ZXZlbnQuZXZlbnRJZH0gJHtldmVudC50aW1lc3RhbXB9ICR7ZXZlbnQubWVzc2FnZX1gXG4gICAgICAgICAgICAgICAgLy8gKTtcbiAgICAgICAgICAgICAgICBpZiAoZXZlbnQubWVzc2FnZSEuaW5jbHVkZXMobWVzc2FnZSkpIHtcbiAgICAgICAgICAgICAgICAgICAgZm91bmRNZXNzYWdlID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKGZvdW5kTWVzc2FnZSAmJiBldmVudC5tZXNzYWdlIS5tYXRjaCgvUkVQT1JUIFJlcXVlc3RJZC8pKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gY2F0Y2ggKGVycjogYW55KSB7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKGBUcmFuc2llbnQgZXJyb3Igd2FpdGluZyBmb3IgbG9nIGdyb3VwIGNyZWF0aW9uOiAke2Vycn1gKTtcbiAgICAgICAgfVxuICAgIH1cbn1cblxudGVzdC5zZXJpYWwodGl0bGUoXCJhd3NcIiwgXCJnYXJiYWdlIGNvbGxlY3RzIGZ1bmN0aW9ucyB0aGF0IGFyZSBjYWxsZWRcIiksIGFzeW5jIHQgPT4ge1xuICAgIC8vIElkZWEgYmVoaW5kIHRoaXMgdGVzdDogY3JlYXRlIGEgZmFhc3QgbW9kdWxlIGFuZCBtYWtlIGEgY2FsbC4gVGhlblxuICAgIC8vIGNsZWFudXAgd2hpbGUgbGVhdmluZyB0aGUgcmVzb3VyY2VzIGluIHBsYWNlLiBUaGVuIGNyZWF0ZSBhbm90aGVyIGZhYXN0XG4gICAgLy8gbW9kdWxlIGFuZCBzZXQgaXRzIHJldGVudGlvbiB0byAwLCBhbmQgdXNlIGEgc3ludGhldGljIGdjIHdvcmtlciB0b1xuICAgIC8vIG9ic2VydmUgYW5kIHZlcmlmeSB0aGUgZ2FyYmFnZSBjb2xsZWN0b3IgYWN0dWFsbHkgY2xlYW5zIHVwLlxuICAgIGNvbnN0IG1vZCA9IGF3YWl0IGZhYXN0QXdzKGZ1bmN0aW9ucywge1xuICAgICAgICBnYzogXCJvZmZcIixcbiAgICAgICAgbW9kZTogXCJxdWV1ZVwiLFxuICAgICAgICBkZXNjcmlwdGlvbjogdC50aXRsZSxcbiAgICAgICAgcGFja2FnZUpzb246IHtcbiAgICAgICAgICAgIG5hbWU6IHV1aWQoKSxcbiAgICAgICAgICAgIGRlcGVuZGVuY2llczoge1xuICAgICAgICAgICAgICAgIHRzbGliOiBcIl4xLjkuMVwiXG4gICAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIG1heFJldHJpZXM6IDBcbiAgICB9KTtcbiAgICB0cnkge1xuICAgICAgICBhd2FpdCBtb2QuZnVuY3Rpb25zLmNvbnNvbGVMb2coXCJnYy10ZXN0LXN0cmluZ1wiKTtcbiAgICAgICAgY29uc3QgeyBjbG91ZHdhdGNoIH0gPSBtb2Quc3RhdGUuc2VydmljZXM7XG4gICAgICAgIGNvbnN0IHsgbG9nR3JvdXBOYW1lIH0gPSBtb2Quc3RhdGUucmVzb3VyY2VzO1xuICAgICAgICBhd2FpdCB3YWl0Rm9yTG9nR3JvdXBDcmVhdGlvbihjbG91ZHdhdGNoLCBsb2dHcm91cE5hbWUsIFwiZ2MtdGVzdC1zdHJpbmdcIik7XG4gICAgICAgIGF3YWl0IG1vZC5jbGVhbnVwKHsgZGVsZXRlUmVzb3VyY2VzOiBmYWxzZSwgZ2NUaW1lb3V0OiAwIH0pO1xuXG4gICAgICAgIC8vIENyZWF0ZSBzb21lIHdvcmsgZm9yIGdjIHRvIGRvIGJ5IHJlbW92aW5nIHRoZSBsb2cgcmV0ZW50aW9uIHBvbGljeSwgZ2NcbiAgICAgICAgLy8gc2hvdWxkIGFkZCBpdCBiYWNrLlxuICAgICAgICBjb25zdCBkZWxldGVSZXRlbnRpb25Qb2xpY3kgPSB0aHJvdHRsZSh7IGNvbmN1cnJlbmN5OiAxLCByZXRyeTogNSB9LCAoKSA9PlxuICAgICAgICAgICAgY2xvdWR3YXRjaC5kZWxldGVSZXRlbnRpb25Qb2xpY3koeyBsb2dHcm91cE5hbWUgfSlcbiAgICAgICAgKTtcbiAgICAgICAgYXdhaXQgZGVsZXRlUmV0ZW50aW9uUG9saWN5KCk7XG5cbiAgICAgICAgbGV0IGRlbGV0ZWRMYXllciA9IGZhbHNlO1xuICAgICAgICBjb25zdCB7IGxheWVyLCBGdW5jdGlvbk5hbWUgfSA9IG1vZC5zdGF0ZS5yZXNvdXJjZXM7XG4gICAgICAgIC8vIGxvZy5nYy5lbmFibGVkID0gdHJ1ZTtcbiAgICAgICAgY29uc3QgbW9kMiA9IGF3YWl0IGZhYXN0QXdzKGZ1bmN0aW9ucywge1xuICAgICAgICAgICAgZ2M6IFwiZm9yY2VcIixcbiAgICAgICAgICAgIHJldGVudGlvbkluRGF5czogMCxcbiAgICAgICAgICAgIGRlc2NyaXB0aW9uOiB0LnRpdGxlLFxuICAgICAgICAgICAgX2djV29ya2VyOiBhc3luYyAod29yaywgc2VydmljZXMpID0+IHtcbiAgICAgICAgICAgICAgICBzd2l0Y2ggKHdvcmsudHlwZSkge1xuICAgICAgICAgICAgICAgICAgICBjYXNlIFwiU2V0TG9nUmV0ZW50aW9uXCI6XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBjaGVja1Jlc291cmNlc0NsZWFuZWRVcCB3aWxsIHZlcmlmeSB0aGUgbG9nIGdyb3VwIGlzXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBkZWxldGVkLlxuICAgICAgICAgICAgICAgICAgICAgICAgYXdhaXQgZGVmYXVsdEdjV29ya2VyKHdvcmssIHNlcnZpY2VzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICBjYXNlIFwiRGVsZXRlTGF5ZXJWZXJzaW9uXCI6XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAod29yay5MYXllck5hbWUgPT09IGxheWVyIS5MYXllck5hbWUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2cuZ2MoYGRlbGV0aW5nIGxheWVyICR7d29yay5MYXllck5hbWV9YCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYXdhaXQgZGVmYXVsdEdjV29ya2VyKHdvcmssIHNlcnZpY2VzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWxldGVkTGF5ZXIgPSB0cnVlO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgIGNhc2UgXCJEZWxldGVSZXNvdXJjZXNcIjpcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICh3b3JrLnJlc291cmNlcy5GdW5jdGlvbk5hbWUgPT09IEZ1bmN0aW9uTmFtZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZy5nYyhgZGVsZXRpbmcgcmVzb3VyY2VzIGZvciAke0Z1bmN0aW9uTmFtZX1gKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhd2FpdCBkZWZhdWx0R2NXb3JrZXIod29yaywgc2VydmljZXMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG5cbiAgICAgICAgYXdhaXQgbW9kMi5jbGVhbnVwKHsgZ2NUaW1lb3V0OiAwIH0pO1xuICAgICAgICB0LnRydWUoZGVsZXRlZExheWVyLCBcIkRlbGV0ZWQgbGF5ZXIgaXMgdHJ1ZVwiKTtcbiAgICAgICAgYXdhaXQgY2hlY2tSZXNvdXJjZXNDbGVhbmVkVXAodCwgYXdhaXQgZ2V0QVdTUmVzb3VyY2VzKG1vZCwgdHJ1ZSkpO1xuICAgIH0gZmluYWxseSB7XG4gICAgICAgIGxvZy5nYy5lbmFibGVkID0gZmFsc2U7XG4gICAgICAgIGF3YWl0IG1vZC5jbGVhbnVwKHsgZGVsZXRlUmVzb3VyY2VzOiB0cnVlLCBkZWxldGVDYWNoZXM6IHRydWUsIGdjVGltZW91dDogMCB9KTtcbiAgICB9XG59KTtcblxudGVzdC5zZXJpYWwodGl0bGUoXCJhd3NcIiwgXCJnYXJiYWdlIGNvbGxlY3RzIGZ1bmN0aW9ucyB0aGF0IGFyZSBuZXZlciBjYWxsZWRcIiksIGFzeW5jIHQgPT4ge1xuICAgIGNvbnN0IG1vZCA9IGF3YWl0IGZhYXN0QXdzKGZ1bmN0aW9ucywge1xuICAgICAgICBnYzogXCJvZmZcIixcbiAgICAgICAgbW9kZTogXCJxdWV1ZVwiLFxuICAgICAgICBkZXNjcmlwdGlvbjogdC50aXRsZSxcbiAgICAgICAgbWF4UmV0cmllczogMFxuICAgIH0pO1xuICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IG1vZC5jbGVhbnVwKHsgZGVsZXRlUmVzb3VyY2VzOiBmYWxzZSwgZ2NUaW1lb3V0OiAwIH0pO1xuICAgICAgICBjb25zdCB7IEZ1bmN0aW9uTmFtZSB9ID0gbW9kLnN0YXRlLnJlc291cmNlcztcbiAgICAgICAgY29uc3QgbW9kMiA9IGF3YWl0IGZhYXN0QXdzKGZ1bmN0aW9ucywge1xuICAgICAgICAgICAgZ2M6IFwiZm9yY2VcIixcbiAgICAgICAgICAgIHJldGVudGlvbkluRGF5czogMCxcbiAgICAgICAgICAgIGRlc2NyaXB0aW9uOiB0LnRpdGxlLFxuICAgICAgICAgICAgX2djV29ya2VyOiBhc3luYyAod29yaywgc2VydmljZXMpID0+IHtcbiAgICAgICAgICAgICAgICBzd2l0Y2ggKHdvcmsudHlwZSkge1xuICAgICAgICAgICAgICAgICAgICBjYXNlIFwiRGVsZXRlUmVzb3VyY2VzXCI6XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAod29yay5yZXNvdXJjZXMuRnVuY3Rpb25OYW1lID09PSBGdW5jdGlvbk5hbWUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2cuZ2MoYGRlbGV0aW5nIHJlc291cmNlcyBmb3IgJHtGdW5jdGlvbk5hbWV9YCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYXdhaXQgZGVmYXVsdEdjV29ya2VyKHdvcmssIHNlcnZpY2VzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGF3YWl0IG1vZDIuY2xlYW51cCh7IGdjVGltZW91dDogMCB9KTtcbiAgICAgICAgLy8gRG9uJ3QgZmFpbCBpZiBhIGxvZyBncm91cCBleGlzdHMgYmVjYXVzZSB3ZSBkaWRuJ3Qgd2FpdCBmb3IgaXRzXG4gICAgICAgIC8vIGNyZWF0aW9uOyBpdCBtaWdodCBiZSBjcmVhdGVkIGJ5IEFXUyBhZnRlciB0aGUgY2xlYW51cCBvY2N1cnMuIFRoZVxuICAgICAgICAvLyByZWFzb24gaXMgdGhhdCB0aGUgbG9nIGdyb3VwIHdpbGwgb25seSBiZSBjcmVhdGVkIGlmIHRoZXJlJ3MgYW5cbiAgICAgICAgLy8gaW52b2NhdGlvbiB0ZXN0LCB3aGljaCBvbmx5IGhhcHBlbnMgaW4gdGhlIHNwZWNpYWwgY2FzZSB0aGF0IHRoZSByb2xlXG4gICAgICAgIC8vIHdhcyByZWNlbnRseSBjcmVhdGVkLiBXaGljaCBpcyB0cnVlIGZvciB0aGUgbmlnaHRseSB0ZXN0c3VpdGUgYnV0XG4gICAgICAgIC8vIHJhcmVseSBlbHNld2hlcmUuXG4gICAgICAgIGNvbnN0IHsgbG9nR3JvdXBSZXN1bHQsIC4uLnJlc291cmNlcyB9ID0gYXdhaXQgZ2V0QVdTUmVzb3VyY2VzKG1vZCwgdHJ1ZSk7XG4gICAgICAgIGF3YWl0IGNoZWNrUmVzb3VyY2VzQ2xlYW5lZFVwKHQsIHJlc291cmNlcyk7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgICAgYXdhaXQgbW9kLmNsZWFudXAoeyBkZWxldGVSZXNvdXJjZXM6IHRydWUsIGRlbGV0ZUNhY2hlczogdHJ1ZSwgZ2NUaW1lb3V0OiAwIH0pO1xuICAgIH1cbn0pO1xuXG50ZXN0LnNraXAodGl0bGUoXCJhd3NcIiwgXCJnYXJiYWdlIGNvbGxlY3Rpb24gY2FjaGluZ1wiKSwgYXN5bmMgdCA9PiB7XG4gICAge1xuICAgICAgICAvLyBSdW4gYSByZWFsIGdjIHNvIHRoZSBidWlsZCBhY2NvdW50IGRvZXNuJ3QgYWNjdW11bGF0ZSBnYXJiYWdlLlxuICAgICAgICBjb25zdCBtb2QgPSBhd2FpdCBmYWFzdEF3cyhmdW5jdGlvbnMsIHsgZ2M6IFwiZm9yY2VcIiwgZGVzY3JpcHRpb246IHQudGl0bGUgfSk7XG4gICAgICAgIGF3YWl0IG1vZC5jbGVhbnVwKHsgZ2NUaW1lb3V0OiAwIH0pO1xuICAgICAgICB0LmlzKGF3YWl0IG1vZC5zdGF0ZS5nY1Byb21pc2UsIFwiZG9uZVwiKTtcbiAgICB9XG5cbiAgICB7XG4gICAgICAgIC8vIFRlc3QgdGhlIGluLW1lbW9yeSBjYWNoZSB0aGF0IHByZXZlbnRzIGdjIGZyb20gbXVsdGlwbGUgZmFhc3QuanNcbiAgICAgICAgLy8gaW5zdGFuY2VzIGZyb20gcnVubmluZyBhdCB0aGUgc2FtZSB0aW1lLlxuICAgICAgICBjb25zdCBtb2QgPSBhd2FpdCBmYWFzdEF3cyhmdW5jdGlvbnMsIHsgZGVzY3JpcHRpb246IHQudGl0bGUgfSk7XG4gICAgICAgIGF3YWl0IG1vZC5jbGVhbnVwKCk7XG4gICAgICAgIHQuaXMoYXdhaXQgbW9kLnN0YXRlLmdjUHJvbWlzZSwgXCJza2lwcGVkXCIpO1xuICAgIH1cblxuICAgIHtcbiAgICAgICAgLy8gVGVzdCB0aGUgcGVyc2lzdGVudCBjYWNoZSB0aGF0IHByZXZlbnRzIGdjIGZyb20gcnVubmluZyB0b28gb2Z0ZW5cbiAgICAgICAgLy8gZXZlbiBhY3Jvc3MgcHJvY2Vzc2VzLlxuICAgICAgICBjbGVhckxhc3RHYygpO1xuICAgICAgICBjb25zdCBtb2QgPSBhd2FpdCBmYWFzdEF3cyhmdW5jdGlvbnMsIHsgZGVzY3JpcHRpb246IHQudGl0bGUgfSk7XG4gICAgICAgIGF3YWl0IG1vZC5jbGVhbnVwKCk7XG4gICAgICAgIHQuaXMoYXdhaXQgbW9kLnN0YXRlLmdjUHJvbWlzZSwgXCJza2lwcGVkXCIpO1xuICAgIH1cbn0pO1xuIl19