UNPKG

@aws-cdk/core

Version:

AWS Cloud Development Kit Core Library

222 lines 33.2 kB
"use strict"; const lib_1 = require("../lib"); const util_1 = require("./util"); function generateString(chars) { let s = ''; for (let i = 0; i < chars; ++i) { s += randomAlpha(); } return s; function randomAlpha() { return String.fromCharCode('a'.charCodeAt(0) + Math.floor(Math.random() * 26)); } } function logicalForElementInPath(constructPath) { const stack = new lib_1.Stack(); let scope = stack; for (const component of constructPath) { scope = new lib_1.CfnResource(scope, component, { type: 'Foo' }); } return stack.resolve(scope.logicalId); } module.exports = { 'if the naming scheme uniquifies with a hash we can have the same concatenated identifier'(test) { // GIVEN const stack = new lib_1.Stack(undefined, 'TestStack'); const A = new lib_1.Construct(stack, 'A'); new lib_1.CfnResource(A, 'BC', { type: 'Resource' }); // WHEN const AB = new lib_1.Construct(stack, 'AB'); new lib_1.CfnResource(AB, 'C', { type: 'Resource' }); // THEN: no exception test.done(); }, 'special case: if the resource is top-level, a hash is not added'(test) { // GIVEN const stack = new lib_1.Stack(undefined, 'TestStack'); // WHEN const r = new lib_1.CfnResource(stack, 'MyAwesomeness', { type: 'Resource' }); const r2 = new lib_1.CfnResource(stack, 'x'.repeat(255), { type: 'Resource' }); // max length const r3 = new lib_1.CfnResource(stack, '*y-'.repeat(255), { type: 'Resource' }); // non-alpha are filtered out (yes, I know it might conflict) // THEN test.equal(stack.resolve(r.logicalId), 'MyAwesomeness'); test.equal(stack.resolve(r2.logicalId), 'x'.repeat(255)); test.equal(stack.resolve(r3.logicalId), 'y'.repeat(255)); test.done(); }, 'if resource is top-level and logical id is longer than allowed, it is trimmed with a hash'(test) { // GIVEN const stack = new lib_1.Stack(undefined, 'TestStack'); // WHEN const r = new lib_1.CfnResource(stack, 'x'.repeat(256), { type: 'Resource' }); // THEN test.equals(stack.resolve(r.logicalId), 'x'.repeat(240) + `C7A139A2`); test.done(); }, 'Logical IDs can be renamed at the stack level'(test) { // GIVEN const stack = new lib_1.Stack(); // WHEN const parent = new lib_1.Construct(stack, 'Parent'); new lib_1.CfnResource(parent, 'ThingResource', { type: 'AWS::TAAS::Thing' }); stack.renameLogicalId('ParentThingResource75D1D9CB', 'Renamed'); // THEN const template = util_1.toCloudFormation(stack); test.ok('Renamed' in template.Resources); test.done(); }, 'Renames for objects that don\'t exist fail'(test) { // GIVEN const stack = new lib_1.Stack(); new lib_1.Construct(stack, 'Parent'); // WHEN stack.renameLogicalId('DOESNOTEXIST', 'Renamed'); // THEN test.throws(() => util_1.toCloudFormation(stack)); test.done(); }, 'ID Renames that collide with existing IDs should fail'(test) { // GIVEN const stack = new lib_1.Stack(); stack.renameLogicalId('ParentThingResource1916E7808', 'ParentThingResource2F19948CB'); // WHEN const parent = new lib_1.Construct(stack, 'Parent'); new lib_1.CfnResource(parent, 'ThingResource1', { type: 'AWS::TAAS::Thing' }); new lib_1.CfnResource(parent, 'ThingResource2', { type: 'AWS::TAAS::Thing' }); // THEN test.throws(() => util_1.toCloudFormation(stack), /Two objects have been assigned the same Logical ID/); test.done(); }, 'hashed naming scheme filters constructs named "Resource" from the human portion'(test) { // GIVEN const stack = new lib_1.Stack(); // WHEN const parent = new lib_1.Construct(stack, 'Parent'); const child1 = new lib_1.Construct(parent, 'Child'); const child2 = new lib_1.Construct(child1, 'Resource'); new lib_1.CfnResource(child2, 'HeyThere', { type: 'AWS::TAAS::Thing' }); // THEN const template = util_1.toCloudFormation(stack); test.deepEqual(template, { Resources: { ParentChildHeyThere35220347: { Type: 'AWS::TAAS::Thing' } } }); test.done(); }, 'can transparently wrap constructs using "Default" id'(test) { // GIVEN const stack1 = new lib_1.Stack(); const parent1 = new lib_1.Construct(stack1, 'Parent'); new lib_1.CfnResource(parent1, 'HeyThere', { type: 'AWS::TAAS::Thing' }); const template1 = util_1.toCloudFormation(stack1); // AND const theId1 = Object.keys(template1.Resources)[0]; test.equal('AWS::TAAS::Thing', template1.Resources[theId1].Type); // WHEN const stack2 = new lib_1.Stack(); const parent2 = new lib_1.Construct(stack2, 'Parent'); const invisibleWrapper = new lib_1.Construct(parent2, 'Default'); new lib_1.CfnResource(invisibleWrapper, 'HeyThere', { type: 'AWS::TAAS::Thing' }); const template2 = util_1.toCloudFormation(stack1); const theId2 = Object.keys(template2.Resources)[0]; test.equal('AWS::TAAS::Thing', template2.Resources[theId2].Type); // THEN: same ID, same object test.equal(theId1, theId2); test.done(); }, 'non-alphanumeric characters are removed from the human part of the logical ID'(test) { const val1 = logicalForElementInPath(['Foo-bar', 'B00m', 'Hello_World', '&&Horray Horray.']); const val2 = logicalForElementInPath(['Foobar', 'B00m', 'HelloWorld', 'HorrayHorray']); // same human part, different hash test.deepEqual(val1, 'FoobarB00mHelloWorldHorrayHorray640E99FB'); test.deepEqual(val2, 'FoobarB00mHelloWorldHorrayHorray744334FD'); test.done(); }, 'non-alphanumeric characters are removed even if the ID has only one component'(test) { const val1 = logicalForElementInPath(['Foo-bar']); // same human part, different hash test.deepEqual(val1, 'Foobar'); test.done(); }, 'empty identifiers are not allowed'(test) { // GIVEN const stack = new lib_1.Stack(); // WHEN new lib_1.CfnResource(stack, '.', { type: 'R' }); // THEN test.throws(() => util_1.toCloudFormation(stack), /Logical ID must adhere to the regular expression/); test.done(); }, 'too large identifiers are truncated yet still remain unique'(test) { // GIVEN const stack = new lib_1.Stack(); const A = new lib_1.Construct(stack, generateString(100)); const B = new lib_1.Construct(A, generateString(100)); // WHEN const firstPart = generateString(60); // The shared part has now exceeded the maximum length of CloudFormation identifiers // so the identity generator will have to something smart const C1 = new lib_1.CfnResource(B, firstPart + generateString(40), { type: 'Resource' }); const C2 = new lib_1.CfnResource(B, firstPart + generateString(40), { type: 'Resource' }); // THEN test.ok(C1.logicalId.length <= 255); test.ok(C2.logicalId.length <= 255); test.notEqual(C1, C2); test.done(); }, 'Refs and dependencies will correctly reflect renames done at the stack level'(test) { // GIVEN const stack = new lib_1.Stack(); stack.renameLogicalId('OriginalName', 'NewName'); // WHEN const c1 = new lib_1.CfnResource(stack, 'OriginalName', { type: 'R1' }); const ref = c1.ref; const c2 = new lib_1.CfnResource(stack, 'Construct2', { type: 'R2', properties: { ReferenceToR1: ref } }); c2.node.addDependency(c1); // THEN test.deepEqual(util_1.toCloudFormation(stack), { Resources: { NewName: { Type: 'R1' }, Construct2: { Type: 'R2', Properties: { ReferenceToR1: { Ref: 'NewName' } }, DependsOn: ['NewName'] } } }); test.done(); }, 'customize logical id allocation behavior by overriding `Stack.allocateLogicalId`'(test) { class MyStack extends lib_1.Stack { allocateLogicalId(element) { if (element.node.id === 'A') { return 'LogicalIdOfA'; } if (element.node.id === 'B') { return 'LogicalIdOfB'; } throw new Error(`Invalid element ID`); } } const stack = new MyStack(); new lib_1.CfnResource(stack, 'A', { type: 'Type::Of::A' }); const group = new lib_1.Construct(stack, 'Group'); new lib_1.CfnResource(group, 'B', { type: 'Type::Of::B' }); // renames can also be applied on custom logical IDs. stack.renameLogicalId('LogicalIdOfB', 'BoomBoomB'); const c = new lib_1.CfnResource(stack, 'B', { type: 'Type::Of::C' }); c.overrideLogicalId('TheC'); test.deepEqual(util_1.toCloudFormation(stack), { Resources: { LogicalIdOfA: { Type: 'Type::Of::A' }, BoomBoomB: { Type: 'Type::Of::B' }, TheC: { Type: 'Type::Of::C' } } }); test.done(); } }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdC5sb2dpY2FsLWlkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsidGVzdC5sb2dpY2FsLWlkLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFDQSxnQ0FBbUU7QUFDbkUsaUNBQTBDO0FBaVExQyxTQUFTLGNBQWMsQ0FBQyxLQUFhO0lBQ25DLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztJQUNYLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxLQUFLLEVBQUUsRUFBRSxDQUFDLEVBQUU7UUFDOUIsQ0FBQyxJQUFJLFdBQVcsRUFBRSxDQUFDO0tBQ3BCO0lBQ0QsT0FBTyxDQUFDLENBQUM7SUFFVCxTQUFTLFdBQVc7UUFDbEIsT0FBTyxNQUFNLENBQUMsWUFBWSxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUNqRixDQUFDO0FBQ0gsQ0FBQztBQUVELFNBQVMsdUJBQXVCLENBQUMsYUFBdUI7SUFDdEQsTUFBTSxLQUFLLEdBQUcsSUFBSSxXQUFLLEVBQUUsQ0FBQztJQUMxQixJQUFJLEtBQUssR0FBYyxLQUFLLENBQUM7SUFDN0IsS0FBSyxNQUFNLFNBQVMsSUFBSSxhQUFhLEVBQUU7UUFDckMsS0FBSyxHQUFHLElBQUksaUJBQVcsQ0FBQyxLQUFLLEVBQUUsU0FBUyxFQUFFLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUM7S0FDNUQ7SUFFRCxPQUFPLEtBQUssQ0FBQyxPQUFPLENBQUUsS0FBcUIsQ0FBQyxTQUFTLENBQUMsQ0FBQztBQUN6RCxDQUFDO0FBaFJELGlCQUFTO0lBQ1AsMEZBQTBGLENBQUMsSUFBVTtRQUNuRyxRQUFRO1FBQ1IsTUFBTSxLQUFLLEdBQUcsSUFBSSxXQUFLLENBQUMsU0FBUyxFQUFFLFdBQVcsQ0FBQyxDQUFDO1FBRWhELE1B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QUFPLENBQUMsQ0FBQztRQUM1QyxJQUFJLGlCQUFXLENBQUMsS0FBSyxFQUFFLEdBQUcsRUFBRSxFQUFFLElBQUksRUFBRSxhQUFhLEVBQUUsQ0FBQyxDQUFDO1FBRXJELHFEQUFxRDtRQUNyRCxLQUFLLENBQUMsZUFBZSxDQUFDLGNBQWMsRUFBRSxXQUFXLENBQUMsQ0FBQztRQUVuRCxNQUFNLENBQUMsR0FBRyxJQUFJLGlCQUFXLENBQUMsS0FBSyxFQUFFLEdBQUcsRUFBRSxFQUFFLElBQUksRUFBRSxhQUFhLEVBQUUsQ0FBQyxDQUFDO1FBQy9ELENBQUMsQ0FBQyxpQkFBaUIsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUU1QixJQUFJLENBQUMsU0FBUyxDQUFDLHVCQUFnQixDQUFDLEtBQUssQ0FBQyxFQUFFO1lBQ3RDLFNBQVMsRUFBRTtnQkFDVCxZQUFZLEVBQUUsRUFBRSxJQUFJLEVBQUUsYUFBYSxFQUFFO2dCQUNyQyxTQUFTLEVBQUUsRUFBRSxJQUFJLEVBQUUsYUFBYSxFQUFFO2dCQUNsQyxJQUFJLEVBQUUsRUFBRSxJQUFJLEVBQUUsYUFBYSxFQUFFO2FBQzlCO1NBQ0YsQ0FBQyxDQUFDO1FBQ0gsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO0lBQ2QsQ0FBQztDQUNGLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBUZXN0IH0gZnJvbSAnbm9kZXVuaXQnO1xuaW1wb3J0IHsgQ2ZuRWxlbWVudCwgQ2ZuUmVzb3VyY2UsIENvbnN0cnVjdCwgU3RhY2sgfSBmcm9tICcuLi9saWInO1xuaW1wb3J0IHsgdG9DbG91ZEZvcm1hdGlvbiB9IGZyb20gJy4vdXRpbCc7XG5cbi8qKlxuICogVGhlc2UgdGVzdHMgYXJlIGV4ZWN1dGVkIG9uY2UgKGZvciBzcGVjaWZpYyBJRCBzY2hlbWVzKVxuICovXG5leHBvcnQgPSB7XG4gICdpZiB0aGUgbmFtaW5nIHNjaGVtZSB1bmlxdWlmaWVzIHdpdGggYSBoYXNoIHdlIGNhbiBoYXZlIHRoZSBzYW1lIGNvbmNhdGVuYXRlZCBpZGVudGlmaWVyJyh0ZXN0OiBUZXN0KSB7XG4gICAgLy8gR0lWRU5cbiAgICBjb25zdCBzdGFjayA9IG5ldyBTdGFjayh1bmRlZmluZWQsICdUZXN0U3RhY2snKTtcblxuICAgIGNvbnN0IEEgPSBuZXcgQ29uc3RydWN0KHN0YWNrLCAnQScpO1xuICAgIG5ldyBDZm5SZXNvdXJjZShBLCAnQkMnLCB7IHR5cGU6ICdSZXNvdXJjZScgfSk7XG5cbiAgICAvLyBXSEVOXG4gICAgY29uc3QgQUIgPSBuZXcgQ29uc3RydWN0KHN0YWNrLCAnQUInKTtcbiAgICBuZXcgQ2ZuUmVzb3VyY2UoQUIsICdDJywgeyB0eXBlOiAnUmVzb3VyY2UnIH0pO1xuXG4gICAgLy8gVEhFTjogbm8gZXhjZXB0aW9uXG5cbiAgICB0ZXN0LmRvbmUoKTtcbiAgfSxcblxuICAnc3BlY2lhbCBjYXNlOiBpZiB0aGUgcmVzb3VyY2UgaXMgdG9wLWxldmVsLCBhIGhhc2ggaXMgbm90IGFkZGVkJyh0ZXN0OiBUZXN0KSB7XG4gICAgLy8gR0lWRU5cbiAgICBjb25zdCBzdGFjayA9IG5ldyBTdGFjayh1bmRlZmluZWQsICdUZXN0U3RhY2snKTtcblxuICAgIC8vIFdIRU5cbiAgICBjb25zdCByID0gbmV3IENmblJlc291cmNlKHN0YWNrLCAnTXlBd2Vzb21lbmVzcycsIHsgdHlwZTogJ1Jlc291cmNlJyB9KTtcbiAgICBjb25zdCByMiA9IG5ldyBDZm5SZXNvdXJjZShzdGFjaywgJ3gnLnJlcGVhdCgyNTUpLCB7IHR5cGU6ICdSZXNvdXJjZScgfSk7IC8vIG1heCBsZW5ndGhcbiAgICBjb25zdCByMyA9IG5ldyBDZm5SZXNvdXJjZShzdGFjaywgJyp5LScucmVwZWF0KDI1NSksIHsgdHlwZTogJ1Jlc291cmNlJyB9KTsgLy8gbm9uLWFscGhhIGFyZSBmaWx0ZXJlZCBvdXQgKHllcywgSSBrbm93IGl0IG1pZ2h0IGNvbmZsaWN0KVxuXG4gICAgLy8gVEhFTlxuICAgIHRlc3QuZXF1YWwoc3RhY2sucmVzb2x2ZShyLmxvZ2ljYWxJZCksICdNeUF3ZXNvbWVuZXNzJyk7XG4gICAgdGVzdC5lcXVhbChzdGFjay5yZXNvbHZlKHIyLmxvZ2ljYWxJZCksICd4Jy5yZXBlYXQoMjU1KSk7XG4gICAgdGVzdC5lcXVhbChzdGFjay5yZXNvbHZlKHIzLmxvZ2ljYWxJZCksICd5Jy5yZXBlYXQoMjU1KSk7XG5cbiAgICB0ZXN0LmRvbmUoKTtcbiAgfSxcblxuICAnaWYgcmVzb3VyY2UgaXMgdG9wLWxldmVsIGFuZCBsb2dpY2FsIGlkIGlzIGxvbmdlciB0aGFuIGFsbG93ZWQsIGl0IGlzIHRyaW1tZWQgd2l0aCBhIGhhc2gnKHRlc3Q6IFRlc3QpIHtcbiAgICAvLyBHSVZFTlxuICAgIGNvbnN0IHN0YWNrID0gbmV3IFN0YWNrKHVuZGVmaW5lZCwgJ1Rlc3RTdGFjaycpO1xuXG4gICAgLy8gV0hFTlxuICAgIGNvbnN0IHIgPSBuZXcgQ2ZuUmVzb3VyY2Uoc3RhY2ssICd4Jy5yZXBlYXQoMjU2KSwgeyB0eXBlOiAnUmVzb3VyY2UnIH0pO1xuXG4gICAgLy8gVEhFTlxuICAgIHRlc3QuZXF1YWxzKHN0YWNrLnJlc29sdmUoci5sb2dpY2FsSWQpLCAneCcucmVwZWF0KDI0MCkgKyBgQzdBMTM5QTJgKTtcbiAgICB0ZXN0LmRvbmUoKTtcbiAgfSxcblxuICAnTG9naWNhbCBJRHMgY2FuIGJlIHJlbmFtZWQgYXQgdGhlIHN0YWNrIGxldmVsJyh0ZXN0OiBUZXN0KSB7XG4gICAgLy8gR0lWRU5cbiAgICBjb25zdCBzdGFjayA9IG5ldyBTdGFjaygpO1xuXG4gICAgLy8gV0hFTlxuICAgIGNvbnN0IHBhcmVudCA9IG5ldyBDb25zdHJ1Y3Qoc3RhY2ssICdQYXJlbnQnKTtcbiAgICBuZXcgQ2ZuUmVzb3VyY2UocGFyZW50LCAnVGhpbmdSZXNvdXJjZScsIHsgdHlwZTogJ0FXUzo6VEFBUzo6VGhpbmcnIH0pO1xuICAgIHN0YWNrLnJlbmFtZUxvZ2ljYWxJZCgnUGFyZW50VGhpbmdSZXNvdXJjZTc1RDFEOUNCJywgJ1JlbmFtZWQnKTtcblxuICAgIC8vIFRIRU5cbiAgICBjb25zdCB0ZW1wbGF0ZSA9IHRvQ2xvdWRGb3JtYXRpb24oc3RhY2spO1xuICAgIHRlc3Qub2soJ1JlbmFtZWQnIGluIHRlbXBsYXRlLlJlc291cmNlcyk7XG5cbiAgICB0ZXN0LmRvbmUoKTtcbiAgfSxcblxuICAnUmVuYW1lcyBmb3Igb2JqZWN0cyB0aGF0IGRvblxcJ3QgZXhpc3QgZmFpbCcodGVzdDogVGVzdCkge1xuICAgIC8vIEdJVkVOXG4gICAgY29uc3Qgc3RhY2sgPSBuZXcgU3RhY2soKTtcbiAgICBuZXcgQ29uc3RydWN0KHN0YWNrLCAnUGFyZW50Jyk7XG5cbiAgICAvLyBXSEVOXG4gICAgc3RhY2sucmVuYW1lTG9naWNhbElkKCdET0VTTk9URVhJU1QnLCAnUmVuYW1lZCcpO1xuXG4gICAgLy8gVEhFTlxuICAgIHRlc3QudGhyb3dzKCgpID0+IHRvQ2xvdWRGb3JtYXRpb24oc3RhY2spKTtcblxuICAgIHRlc3QuZG9uZSgpO1xuICB9LFxuXG4gICdJRCBSZW5hbWVzIHRoYXQgY29sbGlkZSB3aXRoIGV4aXN0aW5nIElEcyBzaG91bGQgZmFpbCcodGVzdDogVGVzdCkge1xuICAgIC8vIEdJVkVOXG4gICAgY29uc3Qgc3RhY2sgPSBuZXcgU3RhY2soKTtcbiAgICBzdGFjay5yZW5hbWVMb2dpY2FsSWQoJ1BhcmVudFRoaW5nUmVzb3VyY2UxOTE2RTc4MDgnLCAnUGFyZW50VGhpbmdSZXNvdXJjZTJGMTk5NDhDQicpO1xuXG4gICAgLy8gV0hFTlxuICAgIGNvbnN0IHBhcmVudCA9IG5ldyBDb25zdHJ1Y3Qoc3RhY2ssICdQYXJlbnQnKTtcbiAgICBuZXcgQ2ZuUmVzb3VyY2UocGFyZW50LCAnVGhpbmdSZXNvdXJjZTEnLCB7IHR5cGU6ICdBV1M6OlRBQVM6OlRoaW5nJyB9KTtcbiAgICBuZXcgQ2ZuUmVzb3VyY2UocGFyZW50LCAnVGhpbmdSZXNvdXJjZTInLCB7IHR5cGU6ICdBV1M6OlRBQVM6OlRoaW5nJyB9KTtcblxuICAgIC8vIFRIRU5cbiAgICB0ZXN0LnRocm93cygoKSA9PiB0b0Nsb3VkRm9ybWF0aW9uKHN0YWNrKSwgL1R3byBvYmplY3RzIGhhdmUgYmVlbiBhc3NpZ25lZCB0aGUgc2FtZSBMb2dpY2FsIElELyk7XG4gICAgdGVzdC5kb25lKCk7XG4gIH0sXG5cbiAgJ2hhc2hlZCBuYW1pbmcgc2NoZW1lIGZpbHRlcnMgY29uc3RydWN0cyBuYW1lZCBcIlJlc291cmNlXCIgZnJvbSB0aGUgaHVtYW4gcG9ydGlvbicodGVzdDogVGVzdCkge1xuICAgIC8vIEdJVkVOXG4gICAgY29uc3Qgc3RhY2sgPSBuZXcgU3RhY2soKTtcblxuICAgIC8vIFdIRU5cbiAgICBjb25zdCBwYXJlbnQgPSBuZXcgQ29uc3RydWN0KHN0YWNrLCAnUGFyZW50Jyk7XG4gICAgY29uc3QgY2hpbGQxID0gbmV3IENvbnN0cnVjdChwYXJlbnQsICdDaGlsZCcpO1xuICAgIGNvbnN0IGNoaWxkMiA9IG5ldyBDb25zdHJ1Y3QoY2hpbGQxLCAnUmVzb3VyY2UnKTtcblxuICAgIG5ldyBDZm5SZXNvdXJjZShjaGlsZDIsICdIZXlUaGVyZScsIHsgdHlwZTogJ0FXUzo6VEFBUzo6VGhpbmcnIH0pO1xuXG4gICAgLy8gVEhFTlxuICAgIGNvbnN0IHRlbXBsYXRlID0gdG9DbG91ZEZvcm1hdGlvbihzdGFjayk7XG4gICAgdGVzdC5kZWVwRXF1YWwodGVtcGxhdGUsIHtcbiAgICAgIFJlc291cmNlczoge1xuICAgICAgICBQYXJlbnRDaGlsZEhleVRoZXJlMzUyMjAzNDc6IHtcbiAgICAgICAgICBUeXBlOiAnQVdTOjpUQUFTOjpUaGluZydcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pO1xuXG4gICAgdGVzdC5kb25lKCk7XG4gIH0sXG5cbiAgJ2NhbiB0cmFuc3BhcmVudGx5IHdyYXAgY29uc3RydWN0cyB1c2luZyBcIkRlZmF1bHRcIiBpZCcodGVzdDogVGVzdCkge1xuICAgIC8vIEdJVkVOXG4gICAgY29uc3Qgc3RhY2sxID0gbmV3IFN0YWNrKCk7XG4gICAgY29uc3QgcGFyZW50MSA9IG5ldyBDb25zdHJ1Y3Qoc3RhY2sxLCAnUGFyZW50Jyk7XG4gICAgbmV3IENmblJlc291cmNlKHBhcmVudDEsICdIZXlUaGVyZScsIHsgdHlwZTogJ0FXUzo6VEFBUzo6VGhpbmcnIH0pO1xuICAgIGNvbnN0IHRlbXBsYXRlMSA9IHRvQ2xvdWRGb3JtYXRpb24oc3RhY2sxKTtcblxuICAgIC8vIEFORFxuICAgIGNvbnN0IHRoZUlkMSA9IE9iamVjdC5rZXlzKHRlbXBsYXRlMS5SZXNvdXJjZXMpWzBdO1xuICAgIHRlc3QuZXF1YWwoJ0FXUzo6VEFBUzo6VGhpbmcnLCB0ZW1wbGF0ZTEuUmVzb3VyY2VzW3RoZUlkMV0uVHlwZSk7XG5cbiAgICAvLyBXSEVOXG4gICAgY29uc3Qgc3RhY2syID0gbmV3IFN0YWNrKCk7XG4gICAgY29uc3QgcGFyZW50MiA9IG5ldyBDb25zdHJ1Y3Qoc3RhY2syLCAnUGFyZW50Jyk7XG4gICAgY29uc3QgaW52aXNpYmxlV3JhcHBlciA9IG5ldyBDb25zdHJ1Y3QocGFyZW50MiwgJ0RlZmF1bHQnKTtcbiAgICBuZXcgQ2ZuUmVzb3VyY2UoaW52aXNpYmxlV3JhcHBlciwgJ0hleVRoZXJlJywgeyB0eXBlOiAnQVdTOjpUQUFTOjpUaGluZycgfSk7XG4gICAgY29uc3QgdGVtcGxhdGUyID0gdG9DbG91ZEZvcm1hdGlvbihzdGFjazEpO1xuXG4gICAgY29uc3QgdGhlSWQyID0gT2JqZWN0LmtleXModGVtcGxhdGUyLlJlc291cmNlcylbMF07XG4gICAgdGVzdC5lcXVhbCgnQVdTOjpUQUFTOjpUaGluZycsIHRlbXBsYXRlMi5SZXNvdXJjZXNbdGhlSWQyXS5UeXBlKTtcblxuICAgIC8vIFRIRU46IHNhbWUgSUQsIHNhbWUgb2JqZWN0XG4gICAgdGVzdC5lcXVhbCh0aGVJZDEsIHRoZUlkMik7XG5cbiAgICB0ZXN0LmRvbmUoKTtcbiAgfSxcblxuICAnbm9uLWFscGhhbnVtZXJpYyBjaGFyYWN0ZXJzIGFyZSByZW1vdmVkIGZyb20gdGhlIGh1bWFuIHBhcnQgb2YgdGhlIGxvZ2ljYWwgSUQnKHRlc3Q6IFRlc3QpIHtcbiAgICBjb25zdCB2YWwxID0gbG9naWNhbEZvckVsZW1lbnRJblBhdGgoWyAnRm9vLWJhcicsICdCMDBtJywgJ0hlbGxvX1dvcmxkJywgJyYmSG9ycmF5IEhvcnJheS4nIF0pO1xuICAgIGNvbnN0IHZhbDIgPSBsb2dpY2FsRm9yRWxlbWVudEluUGF0aChbICdGb29iYXInLCAnQjAwbScsICdIZWxsb1dvcmxkJywgJ0hvcnJheUhvcnJheScgXSk7XG5cbiAgICAvLyBzYW1lIGh1bWFuIHBhcnQsIGRpZmZlcmVudCBoYXNoXG4gICAgdGVzdC5kZWVwRXF1YWwodmFsMSwgJ0Zvb2JhckIwMG1IZWxsb1dvcmxkSG9ycmF5SG9ycmF5NjQwRTk5RkInKTtcbiAgICB0ZXN0LmRlZXBFcXVhbCh2YWwyLCAnRm9vYmFyQjAwbUhlbGxvV29ybGRIb3JyYXlIb3JyYXk3NDQzMzRGRCcpO1xuICAgIHRlc3QuZG9uZSgpO1xuICB9LFxuXG4gICdub24tYWxwaGFudW1lcmljIGNoYXJhY3RlcnMgYXJlIHJlbW92ZWQgZXZlbiBpZiB0aGUgSUQgaGFzIG9ubHkgb25lIGNvbXBvbmVudCcodGVzdDogVGVzdCkge1xuICAgIGNvbnN0IHZhbDEgPSBsb2dpY2FsRm9yRWxlbWVudEluUGF0aChbICdGb28tYmFyJyBdKTtcblxuICAgIC8vIHNhbWUgaHVtYW4gcGFydCwgZGlmZmVyZW50IGhhc2hcbiAgICB0ZXN0LmRlZXBFcXVhbCh2YWwxLCAnRm9vYmFyJyk7XG4gICAgdGVzdC5kb25lKCk7XG4gIH0sXG5cbiAgJ2VtcHR5IGlkZW50aWZpZXJzIGFyZSBub3QgYWxsb3dlZCcodGVzdDogVGVzdCkge1xuICAgIC8vIEdJVkVOXG4gICAgY29uc3Qgc3RhY2sgPSBuZXcgU3RhY2soKTtcblxuICAgIC8vIFdIRU5cbiAgICBuZXcgQ2ZuUmVzb3VyY2Uoc3RhY2ssICcuJywgeyB0eXBlOiAnUicgfSk7XG5cbiAgICAvLyBUSEVOXG4gICAgdGVzdC50aHJvd3MoKCkgPT4gdG9DbG91ZEZvcm1hdGlvbihzdGFjayksIC9Mb2dpY2FsIElEIG11c3QgYWRoZXJlIHRvIHRoZSByZWd1bGFyIGV4cHJlc3Npb24vKTtcbiAgICB0ZXN0LmRvbmUoKTtcbiAgfSxcblxuICAndG9vIGxhcmdlIGlkZW50aWZpZXJzIGFyZSB0cnVuY2F0ZWQgeWV0IHN0aWxsIHJlbWFpbiB1bmlxdWUnKHRlc3Q6IFRlc3QpIHtcbiAgICAvLyBHSVZFTlxuICAgIGNvbnN0IHN0YWNrID0gbmV3IFN0YWNrKCk7XG4gICAgY29uc3QgQSA9IG5ldyBDb25zdHJ1Y3Qoc3RhY2ssIGdlbmVyYXRlU3RyaW5nKDEwMCkpO1xuICAgIGNvbnN0IEIgPSBuZXcgQ29uc3RydWN0KEEsIGdlbmVyYXRlU3RyaW5nKDEwMCkpO1xuXG4gICAgLy8gV0hFTlxuICAgIGNvbnN0IGZpcnN0UGFydCA9IGdlbmVyYXRlU3RyaW5nKDYwKTtcbiAgICAvLyBUaGUgc2hhcmVkIHBhcnQgaGFzIG5vdyBleGNlZWRlZCB0aGUgbWF4aW11bSBsZW5ndGggb2YgQ2xvdWRGb3JtYXRpb24gaWRlbnRpZmllcnNcbiAgICAvLyBzbyB0aGUgaWRlbnRpdHkgZ2VuZXJhdG9yIHdpbGwgaGF2ZSB0byBzb21ldGhpbmcgc21hcnRcblxuICAgIGNvbnN0IEMxID0gbmV3IENmblJlc291cmNlKEIsIGZpcnN0UGFydCArIGdlbmVyYXRlU3RyaW5nKDQwKSwgeyB0eXBlOiAnUmVzb3VyY2UnIH0pO1xuICAgIGNvbnN0IEMyID0gbmV3IENmblJlc291cmNlKEIsIGZpcnN0UGFydCArIGdlbmVyYXRlU3RyaW5nKDQwKSwgeyB0eXBlOiAnUmVzb3VyY2UnIH0pO1xuXG4gICAgLy8gVEhFTlxuICAgIHRlc3Qub2soQzEubG9naWNhbElkLmxlbmd0aCA8PSAyNTUpO1xuICAgIHRlc3Qub2soQzIubG9naWNhbElkLmxlbmd0aCA8PSAyNTUpO1xuICAgIHRlc3Qubm90RXF1YWwoQzEsIEMyKTtcblxuICAgIHRlc3QuZG9uZSgpO1xuICB9LFxuXG4gICdSZWZzIGFuZCBkZXBlbmRlbmNpZXMgd2lsbCBjb3JyZWN0bHkgcmVmbGVjdCByZW5hbWVzIGRvbmUgYXQgdGhlIHN0YWNrIGxldmVsJyh0ZXN0OiBUZXN0KSB7XG4gICAgLy8gR0lWRU5cbiAgICBjb25zdCBzdGFjayA9IG5ldyBTdGFjaygpO1xuICAgIHN0YWNrLnJlbmFtZUxvZ2ljYWxJZCgnT3JpZ2luYWxOYW1lJywgJ05ld05hbWUnKTtcblxuICAgIC8vIFdIRU5cbiAgICBjb25zdCBjMSA9IG5ldyBDZm5SZXNvdXJjZShzdGFjaywgJ09yaWdpbmFsTmFtZScsIHsgdHlwZTogJ1IxJyB9KTtcbiAgICBjb25zdCByZWYgPSBjMS5yZWY7XG5cbiAgICBjb25zdCBjMiA9IG5ldyBDZm5SZXNvdXJjZShzdGFjaywgJ0NvbnN0cnVjdDInLCB7IHR5cGU6ICdSMicsIHByb3BlcnRpZXM6IHsgUmVmZXJlbmNlVG9SMTogcmVmIH0gfSk7XG4gICAgYzIubm9kZS5hZGREZXBlbmRlbmN5KGMxKTtcblxuICAgIC8vIFRIRU5cbiAgICB0ZXN0LmRlZXBFcXVhbCh0b0Nsb3VkRm9ybWF0aW9uKHN0YWNrKSwge1xuICAgICAgUmVzb3VyY2VzOiB7XG4gICAgICAgIE5ld05hbWU6IHsgVHlwZTogJ1IxJyB9LFxuICAgICAgICBDb25zdHJ1Y3QyOiB7XG4gICAgICAgICAgVHlwZTogJ1IyJyxcbiAgICAgICAgICBQcm9wZXJ0aWVzOiB7IFJlZmVyZW5jZVRvUjE6IHsgUmVmOiAnTmV3TmFtZScgfSB9LFxuICAgICAgICAgIERlcGVuZHNPbjogWyAnTmV3TmFtZScgXVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICB0ZXN0LmRvbmUoKTtcbiAgfSxcblxuICAnY3VzdG9taXplIGxvZ2ljYWwgaWQgYWxsb2NhdGlvbiBiZWhhdmlvciBieSBvdmVycmlkaW5nIGBTdGFjay5hbGxvY2F0ZUxvZ2ljYWxJZGAnKHRlc3Q6IFRlc3QpIHtcbiAgICBjbGFzcyBNeVN0YWNrIGV4dGVuZHMgU3RhY2sge1xuICAgICAgcHJvdGVjdGVkIGFsbG9jYXRlTG9naWNhbElkKGVsZW1lbnQ6IENmbkVsZW1lbnQpOiBzdHJpbmcge1xuICAgICAgICBpZiAoZWxlbWVudC5ub2RlLmlkID09PSAnQScpIHsgcmV0dXJuICdMb2dpY2FsSWRPZkEnOyB9XG4gICAgICAgIGlmIChlbGVtZW50Lm5vZGUuaWQgPT09ICdCJykgeyByZXR1cm4gJ0xvZ2ljYWxJZE9mQic7IH1cbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIGVsZW1lbnQgSURgKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBjb25zdCBzdGFjayA9IG5ldyBNeVN0YWNrKCk7XG4gICAgbmV3IENmblJlc291cmNlKHN0YWNrLCAnQScsIHsgdHlwZTogJ1R5cGU6Ok9mOjpBJyB9KTtcbiAgICBjb25zdCBncm91cCA9IG5ldyBDb25zdHJ1Y3Qoc3RhY2ssICdHcm91cCcpO1xuICAgIG5ldyBDZm5SZXNvdXJjZShncm91cCwgJ0InLCB7IHR5cGU6ICdUeXBlOjpPZjo6QicgfSk7XG5cbiAgICAvLyByZW5hbWVzIGNhbiBhbHNvIGJlIGFwcGxpZWQgb24gY3VzdG9tIGxvZ2ljYWwgSURzLlxuICAgIHN0YWNrLnJlbmFtZUxvZ2ljYWxJZCgnTG9naWNhbElkT2ZCJywgJ0Jvb21Cb29tQicpO1xuXG4gICAgY29uc3QgYyA9IG5ldyBDZm5SZXNvdXJjZShzdGFjaywgJ0InLCB7IHR5cGU6ICdUeXBlOjpPZjo6QycgfSk7XG4gICAgYy5vdmVycmlkZUxvZ2ljYWxJZCgnVGhlQycpO1xuXG4gICAgdGVzdC5kZWVwRXF1YWwodG9DbG91ZEZvcm1hdGlvbihzdGFjayksIHtcbiAgICAgIFJlc291cmNlczoge1xuICAgICAgICBMb2dpY2FsSWRPZkE6IHsgVHlwZTogJ1R5cGU6Ok9mOjpBJyB9LFxuICAgICAgICBCb29tQm9vbUI6IHsgVHlwZTogJ1R5cGU6Ok9mOjpCJyB9LFxuICAgICAgICBUaGVDOiB7IFR5cGU6ICdUeXBlOjpPZjo6QycgfVxuICAgICAgfVxuICAgIH0pO1xuICAgIHRlc3QuZG9uZSgpO1xuICB9XG59O1xuXG5mdW5jdGlvbiBnZW5lcmF0ZVN0cmluZyhjaGFyczogbnVtYmVyKSB7XG4gIGxldCBzID0gJyc7XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgY2hhcnM7ICsraSkge1xuICAgIHMgKz0gcmFuZG9tQWxwaGEoKTtcbiAgfVxuICByZXR1cm4gcztcblxuICBmdW5jdGlvbiByYW5kb21BbHBoYSgpIHtcbiAgICByZXR1cm4gU3RyaW5nLmZyb21DaGFyQ29kZSgnYScuY2hhckNvZGVBdCgwKSArIE1hdGguZmxvb3IoTWF0aC5yYW5kb20oKSAqIDI2KSk7XG4gIH1cbn1cblxuZnVuY3Rpb24gbG9naWNhbEZvckVsZW1lbnRJblBhdGgoY29uc3RydWN0UGF0aDogc3RyaW5nW10pOiBzdHJpbmcge1xuICBjb25zdCBzdGFjayA9IG5ldyBTdGFjaygpO1xuICBsZXQgc2NvcGU6IENvbnN0cnVjdCA9IHN0YWNrO1xuICBmb3IgKGNvbnN0IGNvbXBvbmVudCBvZiBjb25zdHJ1Y3RQYXRoKSB7XG4gICAgc2NvcGUgPSBuZXcgQ2ZuUmVzb3VyY2Uoc2NvcGUsIGNvbXBvbmVudCwgeyB0eXBlOiAnRm9vJyB9KTtcbiAgfVxuXG4gIHJldHVybiBzdGFjay5yZXNvbHZlKChzY29wZSBhcyBDZm5SZXNvdXJjZSkubG9naWNhbElkKTtcbn0iXX0=