UNPKG

aws-cdk

Version:

CDK Toolkit, the command line tool for CDK apps

197 lines 26.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.sleep = exports.withMocked = exports.withMockedClassSingleton = exports.instanceMockFrom = exports.testStack = exports.testAssembly = exports.MockCloudExecutable = exports.DEFAULT_FAKE_TEMPLATE = void 0; /* eslint-disable import/order */ const fs = require("fs"); const path = require("path"); const cxschema = require("@aws-cdk/cloud-assembly-schema"); const cxapi = require("@aws-cdk/cx-api"); const mock_sdk_1 = require("./util/mock-sdk"); const cloud_executable_1 = require("../lib/api/cxapp/cloud-executable"); const settings_1 = require("../lib/settings"); exports.DEFAULT_FAKE_TEMPLATE = { No: 'Resources' }; class MockCloudExecutable extends cloud_executable_1.CloudExecutable { constructor(assembly) { const configuration = new settings_1.Configuration(); const sdkProvider = new mock_sdk_1.MockSdkProvider(); super({ configuration, sdkProvider, synthesizer: () => Promise.resolve(testAssembly(assembly)), }); this.configuration = configuration; this.sdkProvider = sdkProvider; } } exports.MockCloudExecutable = MockCloudExecutable; function clone(obj) { return JSON.parse(JSON.stringify(obj)); } function addAttributes(assembly, builder) { for (const stack of assembly.stacks) { const templateFile = `${stack.stackName}.template.json`; const template = stack.template ?? exports.DEFAULT_FAKE_TEMPLATE; fs.writeFileSync(path.join(builder.outdir, templateFile), JSON.stringify(template, undefined, 2)); addNestedStacks(templateFile, builder.outdir, template); // we call patchStackTags here to simulate the tags formatter // that is used when building real manifest files. const metadata = patchStackTags({ ...stack.metadata }); for (const asset of stack.assets || []) { metadata[asset.id] = [ { type: cxschema.ArtifactMetadataEntryType.ASSET, data: asset }, ]; } for (const missing of assembly.missing || []) { builder.addMissing(missing); } const dependencies = [...stack.depends ?? []]; if (stack.assetManifest) { const manifestFile = `${stack.stackName}.assets.json`; fs.writeFileSync(path.join(builder.outdir, manifestFile), JSON.stringify(stack.assetManifest, undefined, 2)); dependencies.push(`${stack.stackName}.assets`); builder.addArtifact(`${stack.stackName}.assets`, { type: cxschema.ArtifactType.ASSET_MANIFEST, environment: stack.env || 'aws://123456789012/here', properties: { file: manifestFile, }, }); } builder.addArtifact(stack.stackName, { type: cxschema.ArtifactType.AWS_CLOUDFORMATION_STACK, environment: stack.env || 'aws://123456789012/here', dependencies, metadata, properties: { ...stack.properties, templateFile, terminationProtection: stack.terminationProtection, }, displayName: stack.displayName, }); } } function addNestedStacks(templatePath, outdir, rootStackTemplate) { let template = rootStackTemplate; if (!template) { const templatePathWithDir = path.join('nested-stack-templates', templatePath); template = JSON.parse(fs.readFileSync(path.join(__dirname, templatePathWithDir)).toString()); fs.writeFileSync(path.join(outdir, templatePath), JSON.stringify(template, undefined, 2)); } for (const logicalId in template.Resources) { if (template.Resources[logicalId].Type === 'AWS::CloudFormation::Stack') { if (template.Resources[logicalId].Metadata && template.Resources[logicalId].Metadata['aws:asset:path']) { const nestedTemplatePath = template.Resources[logicalId].Metadata['aws:asset:path']; addNestedStacks(nestedTemplatePath, outdir); } } } } function testAssembly(assembly) { const builder = new cxapi.CloudAssemblyBuilder(); addAttributes(assembly, builder); if (assembly.nestedAssemblies != null && assembly.nestedAssemblies.length > 0) { assembly.nestedAssemblies?.forEach((nestedAssembly, i) => { const nestedAssemblyBuilder = builder.createNestedAssembly(`nested${i}`, `nested${i}`); addAttributes(nestedAssembly, nestedAssemblyBuilder); nestedAssemblyBuilder.buildAssembly(); }); } return builder.buildAssembly(); } exports.testAssembly = testAssembly; /** * Transform stack tags from how they are decalred in source code (lower cased) * to how they are stored on disk (upper cased). In real synthesis this is done * by a special tags formatter. * * @see aws-cdk-lib/lib/stack.ts */ function patchStackTags(metadata) { const cloned = clone(metadata); for (const metadataEntries of Object.values(cloned)) { for (const metadataEntry of metadataEntries) { if (metadataEntry.type === cxschema.ArtifactMetadataEntryType.STACK_TAGS && metadataEntry.data) { const metadataAny = metadataEntry; metadataAny.data = metadataAny.data.map((t) => { return { Key: t.key, Value: t.value }; }); } } } return cloned; } function testStack(stack) { const assembly = testAssembly({ stacks: [stack] }); return assembly.getStackByName(stack.stackName); } exports.testStack = testStack; /** * Return a mocked instance of a class, given its constructor * * I don't understand why jest doesn't provide this by default, * but there you go. * * FIXME: Currently very limited. Doesn't support inheritance, getters or * automatic detection of properties (as those exist on instances, not * classes). */ function instanceMockFrom(ctr) { const ret = {}; for (const methodName of Object.getOwnPropertyNames(ctr.prototype)) { ret[methodName] = jest.fn(); } return ret; } exports.instanceMockFrom = instanceMockFrom; /** * Run an async block with a class (constructor) replaced with a mock * * The class constructor will be replaced with a constructor that returns * a singleton, and the singleton will be passed to the block so that its * methods can be mocked individually. * * Uses `instanceMockFrom` so is subject to the same limitations that hold * for that function. */ async function withMockedClassSingleton(obj, key, cb) { const original = obj[key]; try { const mock = instanceMockFrom(original); obj[key] = jest.fn().mockReturnValue(mock); const ret = await cb(mock); return ret; } finally { obj[key] = original; } } exports.withMockedClassSingleton = withMockedClassSingleton; function withMocked(obj, key, block) { const original = obj[key]; const mockFn = jest.fn(); obj[key] = mockFn; let asyncFinally = false; try { const ret = block(mockFn); if (!isPromise(ret)) { return ret; } asyncFinally = true; return ret.finally(() => { obj[key] = original; }); } finally { if (!asyncFinally) { obj[key] = original; } } } exports.withMocked = withMocked; function isPromise(object) { return Promise.resolve(object) === object; } async function sleep(ms) { return new Promise(ok => setTimeout(ok, ms)); } exports.sleep = sleep; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInV0aWwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsaUNBQWlDO0FBQ2pDLHlCQUF5QjtBQUN6Qiw2QkFBNkI7QUFDN0IsMkRBQTJEO0FBRTNELHlDQUF5QztBQUN6Qyw4Q0FBa0Q7QUFDbEQsd0VBQW9FO0FBQ3BFLDhDQUFnRDtBQUVuQyxRQUFBLHFCQUFxQixHQUFHLEVBQUUsRUFBRSxFQUFFLFdBQVcsRUFBRSxDQUFDO0FBeUJ6RCxNQUFhLG1CQUFvQixTQUFRLGtDQUFlO0lBSXRELFlBQVksUUFBc0I7UUFDaEMsTUFBTSxhQUFhLEdBQUcsSUFBSSx3QkFBYSxFQUFFLENBQUM7UUFDMUMsTUFBTSxXQUFXLEdBQUcsSUFBSSwwQkFBZSxFQUFFLENBQUM7UUFFMUMsS0FBSyxDQUFDO1lBQ0osYUFBYTtZQUNiLFdBQVc7WUFDWCxXQUFXLEVBQUUsR0FBRyxFQUFFLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxZQUFZLENBQUMsUUFBUSxDQUFDLENBQUM7U0FDM0QsQ0FBQyxDQUFDO1FBRUgsSUFBSSxDQUFDLGFBQWEsR0FBRyxhQUFhLENBQUM7UUFDbkMsSUFBSSxDQUFDLFdBQVcsR0FBRyxXQUFXLENBQUM7SUFDakMsQ0FBQztDQUNGO0FBakJELGtEQWlCQztBQUVELFNBQVMsS0FBSyxDQUFDLEdBQVE7SUFDckIsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztBQUN6QyxDQUFDO0FBRUQsU0FBUyxhQUFhLENBQUMsUUFBc0IsRUFBRSxPQUFtQztJQUNoRixLQUFLLE1BQU0sS0FBSyxJQUFJLFFBQVEsQ0FBQyxNQUFNLEVBQUU7UUFDbkMsTUFBTSxZQUFZLEdBQUcsR0FBRyxLQUFLLENBQUMsU0FBUyxnQkFBZ0IsQ0FBQztRQUN4RCxNQUFNLFFBQVEsR0FBRyxLQUFLLENBQUMsUUFBUSxJQUFJLDZCQUFxQixD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LE9BQU8sR0FBRyxDQUFDO1NBQUU7UUFFcEMsWUFBWSxHQUFHLElBQUksQ0FBQztRQUNwQixPQUFPLEdBQUcsQ0FBQyxPQUFPLENBQUMsR0FBRyxFQUFFLEdBQUcsR0FBRyxDQUFDLEdBQUcsQ0FBQyxHQUFHLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBUSxDQUFDO0tBQzNEO1lBQVM7UUFDUixJQUFJLENBQUMsWUFBWSxFQUFFO1lBQ2pCLEdBQUcsQ0FBQyxHQUFHLENBQUMsR0FBRyxRQUFRLENBQUM7U0FDckI7S0FDRjtBQUNILENBQUM7QUFqQkQsZ0NBaUJDO0FBRUQsU0FBUyxTQUFTLENBQUksTUFBVztJQUMvQixPQUFPLE9BQU8sQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLEtBQUssTUFBTSxDQUFDO0FBQzVDLENBQUM7QUFFTSxLQUFLLFVBQVUsS0FBSyxDQUFDLEVBQVU7SUFDcEMsT0FBTyxJQUFJLE9BQU8sQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLFVBQVUsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQztBQUMvQyxDQUFDO0FBRkQsc0JBRUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKiBlc2xpbnQtZGlzYWJsZSBpbXBvcnQvb3JkZXIgKi9cbmltcG9ydCAqIGFzIGZzIGZyb20gJ2ZzJztcbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgKiBhcyBjeHNjaGVtYSBmcm9tICdAYXdzLWNkay9jbG91ZC1hc3NlbWJseS1zY2hlbWEnO1xuaW1wb3J0IHsgQXNzZXRNYW5pZmVzdCB9IGZyb20gJ0Bhd3MtY2RrL2Nsb3VkLWFzc2VtYmx5LXNjaGVtYSc7XG5pbXBvcnQgKiBhcyBjeGFwaSBmcm9tICdAYXdzLWNkay9jeC1hcGknO1xuaW1wb3J0IHsgTW9ja1Nka1Byb3ZpZGVyIH0gZnJvbSAnLi91dGlsL21vY2stc2RrJztcbmltcG9ydCB7IENsb3VkRXhlY3V0YWJsZSB9IGZyb20gJy4uL2xpYi9hcGkvY3hhcHAvY2xvdWQtZXhlY3V0YWJsZSc7XG5pbXBvcnQgeyBDb25maWd1cmF0aW9uIH0gZnJvbSAnLi4vbGliL3NldHRpbmdzJztcblxuZXhwb3J0IGNvbnN0IERFRkFVTFRfRkFLRV9URU1QTEFURSA9IHsgTm86ICdSZXNvdXJjZXMnIH07XG5cbmV4cG9ydCBpbnRlcmZhY2UgVGVzdFN0YWNrQXJ0aWZhY3Qge1xuICBzdGFja05hbWU6IHN0cmluZztcbiAgdGVtcGxhdGU/OiBhbnk7XG4gIGVudj86IHN0cmluZyxcbiAgZGVwZW5kcz86IHN0cmluZ1tdO1xuICBtZXRhZGF0YT86IGN4YXBpLlN0YWNrTWV0YWRhdGE7XG5cbiAgLyoqIE9sZC1zdHlsZSBhc3NldHMgKi9cbiAgYXNzZXRzPzogY3hzY2hlbWEuQXNzZXRNZXRhZGF0YUVudHJ5W107XG4gIHByb3BlcnRpZXM/OiBQYXJ0aWFsPGN4c2NoZW1hLkF3c0Nsb3VkRm9ybWF0aW9uU3RhY2tQcm9wZXJ0aWVzPjtcbiAgdGVybWluYXRpb25Qcm90ZWN0aW9uPzogYm9vbGVhbjtcbiAgZGlzcGxheU5hbWU/OiBzdHJpbmc7XG5cbiAgLyoqIE5ldy1zdHlsZSBhc3NldHMgKi9cbiAgYXNzZXRNYW5pZmVzdD86IEFzc2V0TWFuaWZlc3Q7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgVGVzdEFzc2VtYmx5IHtcbiAgc3RhY2tzOiBUZXN0U3RhY2tBcnRpZmFjdFtdO1xuICBtaXNzaW5nPzogY3hzY2hlbWEuTWlzc2luZ0NvbnRleHRbXTtcbiAgbmVzdGVkQXNzZW1ibGllcz86IFRlc3RBc3NlbWJseVtdO1xufVxuXG5leHBvcnQgY2xhc3MgTW9ja0Nsb3VkRXhlY3V0YWJsZSBleHRlbmRzIENsb3VkRXhlY3V0YWJsZSB7XG4gIHB1YmxpYyByZWFkb25seSBjb25maWd1cmF0aW9uOiBDb25maWd1cmF0aW9uO1xuICBwdWJsaWMgcmVhZG9ubHkgc2RrUHJvdmlkZXI6IE1vY2tTZGtQcm92aWRlcjtcblxuICBjb25zdHJ1Y3Rvcihhc3NlbWJseTogVGVzdEFzc2VtYmx5KSB7XG4gICAgY29uc3QgY29uZmlndXJhdGlvbiA9IG5ldyBDb25maWd1cmF0aW9uKCk7XG4gICAgY29uc3Qgc2RrUHJvdmlkZXIgPSBuZXcgTW9ja1Nka1Byb3ZpZGVyKCk7XG5cbiAgICBzdXBlcih7XG4gICAgICBjb25maWd1cmF0aW9uLFxuICAgICAgc2RrUHJvdmlkZXIsXG4gICAgICBzeW50aGVzaXplcjogKCkgPT4gUHJvbWlzZS5yZXNvbHZlKHRlc3RBc3NlbWJseShhc3NlbWJseSkpLFxuICAgIH0pO1xuXG4gICAgdGhpcy5jb25maWd1cmF0aW9uID0gY29uZmlndXJhdGlvbjtcbiAgICB0aGlzLnNka1Byb3ZpZGVyID0gc2RrUHJvdmlkZXI7XG4gIH1cbn1cblxuZnVuY3Rpb24gY2xvbmUob2JqOiBhbnkpIHtcbiAgcmV0dXJuIEpTT04ucGFyc2UoSlNPTi5zdHJpbmdpZnkob2JqKSk7XG59XG5cbmZ1bmN0aW9uIGFkZEF0dHJpYnV0ZXMoYXNzZW1ibHk6IFRlc3RBc3NlbWJseSwgYnVpbGRlcjogY3hhcGkuQ2xvdWRBc3NlbWJseUJ1aWxkZXIpIHtcbiAgZm9yIChjb25zdCBzdGFjayBvZiBhc3NlbWJseS5zdGFja3MpIHtcbiAgICBjb25zdCB0ZW1wbGF0ZUZpbGUgPSBgJHtzdGFjay5zdGFja05hbWV9LnRlbXBsYXRlLmpzb25gO1xuICAgIGNvbnN0IHRlbXBsYXRlID0gc3RhY2sudGVtcGxhdGUgPz8gREVGQVVMVF9GQUtFX1RFTVBMQVRFO1xuICAgIGZzLndyaXRlRmlsZVN5bmMocGF0aC5qb2luKGJ1aWxkZXIub3V0ZGlyLCB0ZW1wbGF0ZUZpbGUpLCBKU09OLnN0cmluZ2lmeSh0ZW1wbGF0ZSwgdW5kZWZpbmVkLCAyKSk7XG4gICAgYWRkTmVzdGVkU3RhY2tzKHRlbXBsYXRlRmlsZSwgYnVpbGRlci5vdXRkaXIsIHRlbXBsYXRlKTtcblxuICAgIC8vIHdlIGNhbGwgcGF0Y2hTdGFja1RhZ3MgaGVyZSB0byBzaW11bGF0ZSB0aGUgdGFncyBmb3JtYXR0ZXJcbiAgICAvLyB0aGF0IGlzIHVzZWQgd2hlbiBidWlsZGluZyByZWFsIG1hbmlmZXN0IGZpbGVzLlxuICAgIGNvbnN0IG1ldGFkYXRhOiB7IFtwYXRoOiBzdHJpbmddOiBjeHNjaGVtYS5NZXRhZGF0YUVudHJ5W10gfSA9IHBhdGNoU3RhY2tUYWdzKHsgLi4uc3RhY2subWV0YWRhdGEgfSk7XG4gICAgZm9yIChjb25zdCBhc3NldCBvZiBzdGFjay5hc3NldHMgfHwgW10pIHtcbiAgICAgIG1ldGFkYXRhW2Fzc2V0LmlkXSA9IFtcbiAgICAgICAgeyB0eXBlOiBjeHNjaGVtYS5BcnRpZmFjdE1ldGFkYXRhRW50cnlUeXBlLkFTU0VULCBkYXRhOiBhc3NldCB9LFxuICAgICAgXTtcbiAgICB9XG5cbiAgICBmb3IgKGNvbnN0IG1pc3Npbmcgb2YgYXNzZW1ibHkubWlzc2luZyB8fCBbXSkge1xuICAgICAgYnVpbGRlci5hZGRNaXNzaW5nKG1pc3NpbmcpO1xuICAgIH1cblxuICAgIGNvbnN0IGRlcGVuZGVuY2llcyA9IFsuLi5zdGFjay5kZXBlbmRzID8/IFtdXTtcblxuICAgIGlmIChzdGFjay5hc3NldE1hbmlmZXN0KSB7XG4gICAgICBjb25zdCBtYW5pZmVzdEZpbGUgPSBgJHtzdGFjay5zdGFja05hbWV9LmFzc2V0cy5qc29uYDtcbiAgICAgIGZzLndyaXRlRmlsZVN5bmMocGF0aC5qb2luKGJ1aWxkZXIub3V0ZGlyLCBtYW5pZmVzdEZpbGUpLCBKU09OLnN0cmluZ2lmeShzdGFjay5hc3NldE1hbmlmZXN0LCB1bmRlZmluZWQsIDIpKTtcbiAgICAgIGRlcGVuZGVuY2llcy5wdXNoKGAke3N0YWNrLnN0YWNrTmFtZX0uYXNzZXRzYCk7XG4gICAgICBidWlsZGVyLmFkZEFydGlmYWN0KGAke3N0YWNrLnN0YWNrTmFtZX0uYXNzZXRzYCwge1xuICAgICAgICB0eXBlOiBjeHNjaGVtYS5BcnRpZmFjdFR5cGUuQVNTRVRfTUFOSUZFU1QsXG4gICAgICAgIGVudmlyb25tZW50OiBzdGFjay5lbnYgfHwgJ2F3czovLzEyMzQ1Njc4OTAxMi9oZXJlJyxcbiAgICAgICAgcHJvcGVydGllczoge1xuICAgICAgICAgIGZpbGU6IG1hbmlmZXN0RmlsZSxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGJ1aWxkZXIuYWRkQXJ0aWZhY3Qoc3RhY2suc3RhY2tOYW1lLCB7XG4gICAgICB0eXBlOiBjeHNjaGVtYS5BcnRpZmFjdFR5cGUuQVdTX0NMT1VERk9STUFUSU9OX1NUQUNLLFxuICAgICAgZW52aXJvbm1lbnQ6IHN0YWNrLmVudiB8fCAnYXdzOi8vMTIzNDU2Nzg5MDEyL2hlcmUnLFxuXG4gICAgICBkZXBlbmRlbmNpZXMsXG4gICAgICBtZXRhZGF0YSxcbiAgICAgIHByb3BlcnRpZXM6IHtcbiAgICAgICAgLi4uc3RhY2sucHJvcGVydGllcyxcbiAgICAgICAgdGVtcGxhdGVGaWxlLFxuICAgICAgICB0ZXJtaW5hdGlvblByb3RlY3Rpb246IHN0YWNrLnRlcm1pbmF0aW9uUHJvdGVjdGlvbixcbiAgICAgIH0sXG4gICAgICBkaXNwbGF5TmFtZTogc3RhY2suZGlzcGxheU5hbWUsXG4gICAgfSk7XG5cbiAgfVxufVxuXG5mdW5jdGlvbiBhZGROZXN0ZWRTdGFja3ModGVtcGxhdGVQYXRoOiBzdHJpbmcsIG91dGRpcjogc3RyaW5nLCByb290U3RhY2tUZW1wbGF0ZT86IGFueSkge1xuICBsZXQgdGVtcGxhdGUgPSByb290U3RhY2tUZW1wbGF0ZTtcblxuICBpZiAoIXRlbXBsYXRlKSB7XG4gICAgY29uc3QgdGVtcGxhdGVQYXRoV2l0aERpciA9IHBhdGguam9pbignbmVzdGVkLXN0YWNrLXRlbXBsYXRlcycsIHRlbXBsYXRlUGF0aCk7XG4gICAgdGVtcGxhdGUgPSBKU09OLnBhcnNlKGZzLnJlYWRGaWxlU3luYyhwYXRoLmpvaW4oX19kaXJuYW1lLCB0ZW1wbGF0ZVBhdGhXaXRoRGlyKSkudG9TdHJpbmcoKSk7XG4gICAgZnMud3JpdGVGaWxlU3luYyhwYXRoLmpvaW4ob3V0ZGlyLCB0ZW1wbGF0ZVBhdGgpLCBKU09OLnN0cmluZ2lmeSh0ZW1wbGF0ZSwgdW5kZWZpbmVkLCAyKSk7XG4gIH1cblxuICBmb3IgKGNvbnN0IGxvZ2ljYWxJZCBpbiB0ZW1wbGF0ZS5SZXNvdXJjZXMpIHtcbiAgICBpZiAodGVtcGxhdGUuUmVzb3VyY2VzW2xvZ2ljYWxJZF0uVHlwZSA9PT0gJ0FXUzo6Q2xvdWRGb3JtYXRpb246OlN0YWNrJykge1xuICAgICAgaWYgKHRlbXBsYXRlLlJlc291cmNlc1tsb2dpY2FsSWRdLk1ldGFkYXRhICYmIHRlbXBsYXRlLlJlc291cmNlc1tsb2dpY2FsSWRdLk1ldGFkYXRhWydhd3M6YXNzZXQ6cGF0aCddKSB7XG4gICAgICAgIGNvbnN0IG5lc3RlZFRlbXBsYXRlUGF0aCA9IHRlbXBsYXRlLlJlc291cmNlc1tsb2dpY2FsSWRdLk1ldGFkYXRhWydhd3M6YXNzZXQ6cGF0aCddO1xuICAgICAgICBhZGROZXN0ZWRTdGFja3MobmVzdGVkVGVtcGxhdGVQYXRoLCBvdXRkaXIpO1xuICAgICAgfVxuICAgIH1cbiAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gdGVzdEFzc2VtYmx5KGFzc2VtYmx5OiBUZXN0QXNzZW1ibHkpOiBjeGFwaS5DbG91ZEFzc2VtYmx5IHtcbiAgY29uc3QgYnVpbGRlciA9IG5ldyBjeGFwaS5DbG91ZEFzc2VtYmx5QnVpbGRlcigpO1xuICBhZGRBdHRyaWJ1dGVzKGFzc2VtYmx5LCBidWlsZGVyKTtcblxuICBpZiAoYXNzZW1ibHkubmVzdGVkQXNzZW1ibGllcyAhPSBudWxsICYmIGFzc2VtYmx5Lm5lc3RlZEFzc2VtYmxpZXMubGVuZ3RoID4gMCkge1xuICAgIGFzc2VtYmx5Lm5lc3RlZEFzc2VtYmxpZXM/LmZvckVhY2goKG5lc3RlZEFzc2VtYmx5OiBUZXN0QXNzZW1ibHksIGk6IG51bWJlcikgPT4ge1xuICAgICAgY29uc3QgbmVzdGVkQXNzZW1ibHlCdWlsZGVyID0gYnVpbGRlci5jcmVhdGVOZXN0ZWRBc3NlbWJseShgbmVzdGVkJHtpfWAsIGBuZXN0ZWQke2l9YCk7XG4gICAgICBhZGRBdHRyaWJ1dGVzKG5lc3RlZEFzc2VtYmx5LCBuZXN0ZWRBc3NlbWJseUJ1aWxkZXIpO1xuICAgICAgbmVzdGVkQXNzZW1ibHlCdWlsZGVyLmJ1aWxkQXNzZW1ibHkoKTtcbiAgICB9KTtcbiAgfVxuXG4gIHJldHVybiBidWlsZGVyLmJ1aWxkQXNzZW1ibHkoKTtcbn1cblxuLyoqXG4gKiBUcmFuc2Zvcm0gc3RhY2sgdGFncyBmcm9tIGhvdyB0aGV5IGFyZSBkZWNhbHJlZCBpbiBzb3VyY2UgY29kZSAobG93ZXIgY2FzZWQpXG4gKiB0byBob3cgdGhleSBhcmUgc3RvcmVkIG9uIGRpc2sgKHVwcGVyIGNhc2VkKS4gSW4gcmVhbCBzeW50aGVzaXMgdGhpcyBpcyBkb25lXG4gKiBieSBhIHNwZWNpYWwgdGFncyBmb3JtYXR0ZXIuXG4gKlxuICogQHNlZSBhd3MtY2RrLWxpYi9saWIvc3RhY2sudHNcbiAqL1xuZnVuY3Rpb24gcGF0Y2hTdGFja1RhZ3MobWV0YWRhdGE6IHsgW3BhdGg6IHN0cmluZ106IGN4c2NoZW1hLk1ldGFkYXRhRW50cnlbXSB9KTogeyBbcGF0aDogc3RyaW5nXTogY3hzY2hlbWEuTWV0YWRhdGFFbnRyeVtdIH0ge1xuXG4gIGNvbnN0IGNsb25lZCA9IGNsb25lKG1ldGFkYXRhKSBhcyB7IFtwYXRoOiBzdHJpbmddOiBjeHNjaGVtYS5NZXRhZGF0YUVudHJ5W10gfTtcblxuICBmb3IgKGNvbnN0IG1ldGFkYXRhRW50cmllcyBvZiBPYmplY3QudmFsdWVzKGNsb25lZCkpIHtcbiAgICBmb3IgKGNvbnN0IG1ldGFkYXRhRW50cnkgb2YgbWV0YWRhdGFFbnRyaWVzKSB7XG4gICAgICBpZiAobWV0YWRhdGFFbnRyeS50eXBlID09PSBjeHNjaGVtYS5BcnRpZmFjdE1ldGFkYXRhRW50cnlUeXBlLlNUQUNLX1RBR1MgJiYgbWV0YWRhdGFFbnRyeS5kYXRhKSB7XG5cbiAgICAgICAgY29uc3QgbWV0YWRhdGFBbnkgPSBtZXRhZGF0YUVudHJ5IGFzIGFueTtcblxuICAgICAgICBtZXRhZGF0YUFueS5kYXRhID0gbWV0YWRhdGFBbnkuZGF0YS5tYXAoKHQ6IGFueSkgPT4ge1xuICAgICAgICAgIHJldHVybiB7IEtleTogdC5rZXksIFZhbHVlOiB0LnZhbHVlIH07XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH1cbiAgfVxuICByZXR1cm4gY2xvbmVkO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gdGVzdFN0YWNrKHN0YWNrOiBUZXN0U3RhY2tBcnRpZmFjdCk6IGN4YXBpLkNsb3VkRm9ybWF0aW9uU3RhY2tBcnRpZmFjdCB7XG4gIGNvbnN0IGFzc2VtYmx5ID0gdGVzdEFzc2VtYmx5KHsgc3RhY2tzOiBbc3RhY2tdIH0pO1xuICByZXR1cm4gYXNzZW1ibHkuZ2V0U3RhY2tCeU5hbWUoc3RhY2suc3RhY2tOYW1lKTtcbn1cblxuLyoqXG4gKiBSZXR1cm4gYSBtb2NrZWQgaW5zdGFuY2Ugb2YgYSBjbGFzcywgZ2l2ZW4gaXRzIGNvbnN0cnVjdG9yXG4gKlxuICogSSBkb24ndCB1bmRlcnN0YW5kIHdoeSBqZXN0IGRvZXNuJ3QgcHJvdmlkZSB0aGlzIGJ5IGRlZmF1bHQsXG4gKiBidXQgdGhlcmUgeW91IGdvLlxuICpcbiAqIEZJWE1FOiBDdXJyZW50bHkgdmVyeSBsaW1pdGVkLiBEb2Vzbid0IHN1cHBvcnQgaW5oZXJpdGFuY2UsIGdldHRlcnMgb3JcbiAqIGF1dG9tYXRpYyBkZXRlY3Rpb24gb2YgcHJvcGVydGllcyAoYXMgdGhvc2UgZXhpc3Qgb24gaW5zdGFuY2VzLCBub3RcbiAqIGNsYXNzZXMpLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaW5zdGFuY2VNb2NrRnJvbTxBPihjdHI6IG5ldyAoLi4uYXJnczogYW55W10pID0+IEEpOiBqZXN0Lk1vY2tlZDxBPiB7XG4gIGNvbnN0IHJldDogYW55ID0ge307XG4gIGZvciAoY29uc3QgbWV0aG9kTmFtZSBvZiBPYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyhjdHIucHJvdG90eXBlKSkge1xuICAgIHJldFttZXRob2ROYW1lXSA9IGplc3QuZm4oKTtcbiAgfVxuICByZXR1cm4gcmV0O1xufVxuXG4vKipcbiAqIFJ1biBhbiBhc3luYyBibG9jayB3aXRoIGEgY2xhc3MgKGNvbnN0cnVjdG9yKSByZXBsYWNlZCB3aXRoIGEgbW9ja1xuICpcbiAqIFRoZSBjbGFzcyBjb25zdHJ1Y3RvciB3aWxsIGJlIHJlcGxhY2VkIHdpdGggYSBjb25zdHJ1Y3RvciB0aGF0IHJldHVybnNcbiAqIGEgc2luZ2xldG9uLCBhbmQgdGhlIHNpbmdsZXRvbiB3aWxsIGJlIHBhc3NlZCB0byB0aGUgYmxvY2sgc28gdGhhdCBpdHNcbiAqIG1ldGhvZHMgY2FuIGJlIG1vY2tlZCBpbmRpdmlkdWFsbHkuXG4gKlxuICogVXNlcyBgaW5zdGFuY2VNb2NrRnJvbWAgc28gaXMgc3ViamVjdCB0byB0aGUgc2FtZSBsaW1pdGF0aW9ucyB0aGF0IGhvbGRcbiAqIGZvciB0aGF0IGZ1bmN0aW9uLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gd2l0aE1vY2tlZENsYXNzU2luZ2xldG9uPEEgZXh0ZW5kcyBvYmplY3QsIEsgZXh0ZW5kcyBrZXlvZiBBLCBCPihcbiAgb2JqOiBBLFxuICBrZXk6IEssXG4gIGNiOiAobW9jazogQVtLXSBleHRlbmRzIGplc3QuQ29uc3RydWN0YWJsZSA/IGplc3QuTW9ja2VkPEluc3RhbmNlVHlwZTxBW0tdPj4gOiBuZXZlcikgPT4gUHJvbWlzZTxCPixcbik6IFByb21pc2U8Qj4ge1xuXG4gIGNvbnN0IG9yaWdpbmFsID0gb2JqW2tleV07XG4gIHRyeSB7XG4gICAgY29uc3QgbW9jayA9IGluc3RhbmNlTW9ja0Zyb20ob3JpZ2luYWwgYXMgYW55KTtcbiAgICBvYmpba2V5XSA9IGplc3QuZm4oKS5tb2NrUmV0dXJuVmFsdWUobW9jaykgYXMgYW55O1xuICAgIGNvbnN0IHJldCA9IGF3YWl0IGNiKG1vY2sgYXMgYW55KTtcbiAgICByZXR1cm4gcmV0O1xuICB9IGZpbmFsbHkge1xuICAgIG9ialtrZXldID0gb3JpZ2luYWw7XG4gIH1cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHdpdGhNb2NrZWQ8QSBleHRlbmRzIG9iamVjdCwgSyBleHRlbmRzIGtleW9mIEEsIEI+KG9iajogQSwga2V5OiBLLCBibG9jazogKGZuOiBqZXN0Lk1vY2tlZDxBPltLXSkgPT4gQik6IEIge1xuICBjb25zdCBvcmlnaW5hbCA9IG9ialtrZXldO1xuICBjb25zdCBtb2NrRm4gPSBqZXN0LmZuKCk7XG4gIChvYmogYXMgYW55KVtrZXldID0gbW9ja0ZuO1xuXG4gIGxldCBhc3luY0ZpbmFsbHk6IGJvb2xlYW4gPSBmYWxzZTtcbiAgdHJ5IHtcbiAgICBjb25zdCByZXQgPSBibG9jayhtb2NrRm4gYXMgYW55KTtcbiAgICBpZiAoIWlzUHJvbWlzZShyZXQpKSB7IHJldHVybiByZXQ7IH1cblxuICAgIGFzeW5jRmluYWxseSA9IHRydWU7XG4gICAgcmV0dXJuIHJldC5maW5hbGx5KCgpID0+IHsgb2JqW2tleV0gPSBvcmlnaW5hbDsgfSkgYXMgYW55O1xuICB9IGZpbmFsbHkge1xuICAgIGlmICghYXN5bmNGaW5hbGx5KSB7XG4gICAgICBvYmpba2V5XSA9IG9yaWdpbmFsO1xuICAgIH1cbiAgfVxufVxuXG5mdW5jdGlvbiBpc1Byb21pc2U8QT4ob2JqZWN0OiBhbnkpOiBvYmplY3QgaXMgUHJvbWlzZTxBPiB7XG4gIHJldHVybiBQcm9taXNlLnJlc29sdmUob2JqZWN0KSA9PT0gb2JqZWN0O1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc2xlZXAobXM6IG51bWJlcikge1xuICByZXR1cm4gbmV3IFByb21pc2Uob2sgPT4gc2V0VGltZW91dChvaywgbXMpKTtcbn1cbiJdfQ==