UNPKG

@aws-cdk/core

Version:

AWS Cloud Development Kit Core Library

539 lines 66.6 kB
"use strict"; const lib_1 = require("../lib"); const encoding_1 = require("../lib/private/encoding"); const intrinsic_1 = require("../lib/private/intrinsic"); const resolve_1 = require("../lib/private/resolve"); const evaluate_cfn_1 = require("./evaluate-cfn"); class Promise2 { constructor() { this.creationStack = []; } resolve() { return { Data: { stringProp: 'hello', numberProp: 1234, }, Recurse: new intrinsic_1.Intrinsic(42) }; } } class Promise1 { constructor() { this.creationStack = []; this.p2 = [new Promise2(), new Promise2()]; } resolve() { return this.p2; } } class BaseDataType { constructor(foo) { this.foo = foo; } } class DataType extends BaseDataType { constructor() { super(12); this.goo = 'hello'; } } /** * Return Tokens in both flavors that resolve to the given string */ function tokensThatResolveTo(value) { return [ new intrinsic_1.Intrinsic(value), lib_1.Lazy.anyValue({ produce: () => value }) ]; } /** * Wrapper for resolve that creates an throwaway Construct to call it on * * So I don't have to change all call sites in this file. */ function resolve(x) { return new lib_1.Stack().resolve(x); } module.exports = { 'resolve a plain old object should just return the object'(test) { const obj = { PlainOldObject: 123, Array: [1, 2, 3] }; test.deepEqual(resolve(obj), obj); test.done(); }, 'if a value is an object with a token value, it will be evaluated'(test) { const obj = { RegularValue: 'hello', LazyValue: new intrinsic_1.Intrinsic('World') }; test.deepEqual(resolve(obj), { RegularValue: 'hello', LazyValue: 'World' }); test.done(); }, 'tokens are evaluated anywhere in the object tree'(test) { const obj = new Promise1(); const actual = resolve({ Obj: obj }); test.deepEqual(actual, { Obj: [ { Data: { stringProp: "hello", numberProp: 1234 }, Recurse: 42 }, { Data: { stringProp: "hello", numberProp: 1234 }, Recurse: 42 } ] }); test.done(); }, 'tokens are evaluated recursively'(test) { const obj = new Promise1(); const actual = resolve(new intrinsic_1.Intrinsic({ Obj: obj })); test.deepEqual(actual, { Obj: [ { Data: { stringProp: "hello", numberProp: 1234 }, Recurse: 42 }, { Data: { stringProp: "hello", numberProp: 1234 }, Recurse: 42 } ] }); test.done(); }, 'empty arrays or objects are kept'(test) { test.deepEqual(resolve({}), {}); test.deepEqual(resolve([]), []); const obj = { Prop1: 1234, Prop2: {}, Prop3: [], Prop4: 'hello', Prop5: { PropA: {}, PropB: { PropC: [undefined, undefined], PropD: 'Yoohoo' } } }; test.deepEqual(resolve(obj), { Prop1: 1234, Prop2: {}, Prop3: [], Prop4: 'hello', Prop5: { PropA: {}, PropB: { PropC: [], PropD: 'Yoohoo' } } }); test.done(); }, 'if an object has a "resolve" property that is not a function, it is not considered a token'(test) { test.deepEqual(resolve({ a_token: { resolve: () => 78787 } }), { a_token: 78787 }); test.deepEqual(resolve({ not_a_token: { resolve: 12 } }), { not_a_token: { resolve: 12 } }); test.done(); }, // tslint:disable-next-line:max-line-length 'if a resolvable object inherits from a class that is also resolvable, the "constructor" function will not get in the way (uses Object.keys instead of "for in")'(test) { test.deepEqual(resolve({ prop: new DataType() }), { prop: { foo: 12, goo: 'hello' } }); test.done(); }, 'isToken(obj) can be used to determine if an object is a token'(test) { test.ok(lib_1.isResolvableObject({ resolve: () => 123 })); test.ok(lib_1.isResolvableObject({ a: 1, b: 2, resolve: () => 'hello' })); test.ok(!lib_1.isResolvableObject({ a: 1, b: 2, resolve: 3 })); test.done(); }, 'Token can be used to create tokens that contain a constant value'(test) { test.equal(resolve(new intrinsic_1.Intrinsic(12)), 12); test.equal(resolve(new intrinsic_1.Intrinsic('hello')), 'hello'); test.deepEqual(resolve(new intrinsic_1.Intrinsic(['hi', 'there'])), ['hi', 'there']); test.done(); }, 'resolving leaves a Date object in working order'(test) { const date = new Date('2000-01-01'); const resolved = resolve(date); test.equal(date.toString(), resolved.toString()); test.done(); }, 'tokens can be stringified and evaluated to conceptual value'(test) { // GIVEN const token = new intrinsic_1.Intrinsic('woof woof'); // WHEN const stringified = `The dog says: ${token}`; const resolved = resolve(stringified); // THEN test.deepEqual(evaluate_cfn_1.evaluateCFN(resolved), 'The dog says: woof woof'); test.done(); }, 'tokens stringification can be reversed'(test) { // GIVEN const token = new intrinsic_1.Intrinsic('woof woof'); // THEN test.equal(token, lib_1.Tokenization.reverseString(`${token}`).firstToken); test.done(); }, 'Tokens stringification and reversing of CloudFormation Tokens is implemented using Fn::Join'(test) { // GIVEN const token = new intrinsic_1.Intrinsic(({ woof: 'woof' })); // WHEN const stringified = `The dog says: ${token}`; const resolved = resolve(stringified); // THEN test.deepEqual(resolved, { 'Fn::Join': ['', ['The dog says: ', { woof: 'woof' }]] }); test.done(); }, 'Doubly nested strings evaluate correctly in scalar context'(test) { // GIVEN const token1 = new intrinsic_1.Intrinsic("world"); const token2 = new intrinsic_1.Intrinsic(`hello ${token1}`); // WHEN const resolved1 = resolve(token2.toString()); const resolved2 = resolve(token2); // THEN test.deepEqual(evaluate_cfn_1.evaluateCFN(resolved1), "hello world"); test.deepEqual(evaluate_cfn_1.evaluateCFN(resolved2), "hello world"); test.done(); }, 'integer Tokens can be stringified and evaluate to conceptual value'(test) { // GIVEN for (const token of tokensThatResolveTo(1)) { // WHEN const stringified = `the number is ${token}`; const resolved = resolve(stringified); // THEN test.deepEqual(evaluate_cfn_1.evaluateCFN(resolved), 'the number is 1'); } test.done(); }, 'intrinsic Tokens can be stringified and evaluate to conceptual value'(test) { // GIVEN for (const bucketName of tokensThatResolveTo({ Ref: 'MyBucket' })) { // WHEN const resolved = resolve(`my bucket is named ${bucketName}`); // THEN const context = { MyBucket: 'TheName' }; test.equal(evaluate_cfn_1.evaluateCFN(resolved, context), 'my bucket is named TheName'); } test.done(); }, 'tokens resolve properly in initial position'(test) { // GIVEN for (const token of tokensThatResolveTo('Hello')) { // WHEN const resolved = resolve(`${token} world`); // THEN test.equal(evaluate_cfn_1.evaluateCFN(resolved), 'Hello world'); } test.done(); }, 'side-by-side Tokens resolve correctly'(test) { // GIVEN for (const token1 of tokensThatResolveTo('Hello ')) { for (const token2 of tokensThatResolveTo('world')) { // WHEN const resolved = resolve(`${token1}${token2}`); // THEN test.equal(evaluate_cfn_1.evaluateCFN(resolved), 'Hello world'); } } test.done(); }, 'tokens can be used in hash keys but must resolve to a string'(test) { // GIVEN const token = new intrinsic_1.Intrinsic('I am a string'); // WHEN const s = { [token.toString()]: `boom ${token}` }; // THEN test.deepEqual(resolve(s), { 'I am a string': 'boom I am a string' }); test.done(); }, 'tokens can be nested in hash keys'(test) { // GIVEN const token = new intrinsic_1.Intrinsic(lib_1.Lazy.stringValue({ produce: () => lib_1.Lazy.stringValue({ produce: (() => 'I am a string') }) })); // WHEN const s = { [token.toString()]: `boom ${token}` }; // THEN test.deepEqual(resolve(s), { 'I am a string': 'boom I am a string' }); test.done(); }, 'tokens can be nested and concatenated in hash keys'(test) { // GIVEN const innerToken = new intrinsic_1.Intrinsic('toot'); const token = new intrinsic_1.Intrinsic(`${innerToken} the woot`); // WHEN const s = { [token.toString()]: `boom chicago` }; // THEN test.deepEqual(resolve(s), { 'toot the woot': 'boom chicago' }); test.done(); }, 'can find nested tokens in hash keys'(test) { // GIVEN const innerToken = new intrinsic_1.Intrinsic('toot'); const token = new intrinsic_1.Intrinsic(`${innerToken} the woot`); // WHEN const s = { [token.toString()]: `boom chicago` }; // THEN const tokens = resolve_1.findTokens(new lib_1.Stack(), () => s); test.ok(tokens.some(t => t === innerToken), 'Cannot find innerToken'); test.ok(tokens.some(t => t === token), 'Cannot find token'); test.done(); }, 'fails if token in a hash key resolves to a non-string'(test) { // GIVEN const token = new intrinsic_1.Intrinsic({ Ref: 'Other' }); // WHEN const s = { [token.toString()]: `boom ${token}` }; // THEN test.throws(() => resolve(s), 'The key "${Token[TOKEN.19]}" has been resolved to {"Ref":"Other"} but must be resolvable to a string'); test.done(); }, 'list encoding': { 'can encode Token to string and resolve the encoding'(test) { // GIVEN const token = new intrinsic_1.Intrinsic({ Ref: 'Other' }); // WHEN const struct = { XYZ: lib_1.Token.asList(token) }; // THEN test.deepEqual(resolve(struct), { XYZ: { Ref: 'Other' } }); test.done(); }, 'cannot add to encoded list'(test) { // GIVEN const token = new intrinsic_1.Intrinsic({ Ref: 'Other' }); // WHEN const encoded = lib_1.Token.asList(token); encoded.push('hello'); // THEN test.throws(() => { resolve(encoded); }, /Cannot add elements to list token/); test.done(); }, 'cannot add to strings in encoded list'(test) { // GIVEN const token = new intrinsic_1.Intrinsic({ Ref: 'Other' }); // WHEN const encoded = lib_1.Token.asList(token); encoded[0] += 'hello'; // THEN test.throws(() => { resolve(encoded); }, /concatenate strings in/); test.done(); }, 'can pass encoded lists to FnSelect'(test) { // GIVEN const encoded = lib_1.Token.asList(new intrinsic_1.Intrinsic({ Ref: 'Other' })); // WHEN const struct = lib_1.Fn.select(1, encoded); // THEN test.deepEqual(resolve(struct), { 'Fn::Select': [1, { Ref: 'Other' }] }); test.done(); }, 'can pass encoded lists to FnJoin'(test) { // GIVEN const encoded = lib_1.Token.asList(new intrinsic_1.Intrinsic({ Ref: 'Other' })); // WHEN const struct = lib_1.Fn.join('/', encoded); // THEN test.deepEqual(resolve(struct), { 'Fn::Join': ['/', { Ref: 'Other' }] }); test.done(); }, 'can pass encoded lists to FnJoin, even if join is stringified'(test) { // GIVEN const encoded = lib_1.Token.asList(new intrinsic_1.Intrinsic({ Ref: 'Other' })); // WHEN const struct = lib_1.Fn.join('/', encoded).toString(); // THEN test.deepEqual(resolve(struct), { 'Fn::Join': ['/', { Ref: 'Other' }] }); test.done(); }, }, 'number encoding': { 'basic integer encoding works'(test) { test.equal(16, encoding_1.extractTokenDouble(encoding_1.createTokenDouble(16))); test.done(); }, 'arbitrary integers can be encoded, stringified, and recovered'(test) { for (let i = 0; i < 100; i++) { // We can encode all numbers up to 2^48-1 const x = Math.floor(Math.random() * (Math.pow(2, 48) - 1)); const encoded = encoding_1.createTokenDouble(x); // Roundtrip through JSONification const roundtripped = JSON.parse(JSON.stringify({ theNumber: encoded })).theNumber; const decoded = encoding_1.extractTokenDouble(roundtripped); test.equal(decoded, x, `Fail roundtrip encoding of ${x}`); } test.done(); }, 'arbitrary numbers are correctly detected as not being tokens'(test) { test.equal(undefined, encoding_1.extractTokenDouble(0)); test.equal(undefined, encoding_1.extractTokenDouble(1243)); test.equal(undefined, encoding_1.extractTokenDouble(4835e+532)); test.done(); }, 'can number-encode and resolve Token objects'(test) { // GIVEN const x = new intrinsic_1.Intrinsic(123); // THEN const encoded = lib_1.Token.asNumber(x); test.equal(false, lib_1.isResolvableObject(encoded), 'encoded number does not test as token'); test.equal(true, lib_1.Token.isUnresolved(encoded), 'encoded number does not test as token'); // THEN const resolved = resolve({ value: encoded }); test.deepEqual(resolved, { value: 123 }); test.done(); }, }, 'stack trace is captured at token creation'(test) { function fn1() { function fn2() { class ExposeTrace extends intrinsic_1.Intrinsic { get creationTrace() { return this.creationStack; } } return new ExposeTrace('hello'); } return fn2(); } const token = fn1(); test.ok(token.creationTrace.find(x => x.includes('fn1'))); test.ok(token.creationTrace.find(x => x.includes('fn2'))); test.done(); }, 'newError returns an error with the creation stack trace'(test) { function fn1() { function fn2() { function fn3() { class ThrowingToken extends intrinsic_1.Intrinsic { throwError(message) { throw this.newError(message); } } return new ThrowingToken('boom'); } return fn3(); } return fn2(); } const token = fn1(); test.throws(() => token.throwError('message!'), /Token created:/); test.done(); }, 'type coercion': (() => { const tests = {}; const inputs = [ 'a string', 1234, { an_object: 1234 }, [1, 2, 3], false ]; for (const input of inputs) { // GIVEN const stringToken = lib_1.Token.asString(new intrinsic_1.Intrinsic(input)); const numberToken = lib_1.Token.asNumber(new intrinsic_1.Intrinsic(input)); const listToken = lib_1.Token.asList(new intrinsic_1.Intrinsic(input)); // THEN const expected = input; tests[`${input}<string>.toNumber()`] = (test) => { test.deepEqual(resolve(lib_1.Token.asNumber(new intrinsic_1.Intrinsic(stringToken))), expected); test.done(); }; tests[`${input}<list>.toNumber()`] = (test) => { test.deepEqual(resolve(lib_1.Token.asNumber(new intrinsic_1.Intrinsic(listToken))), expected); test.done(); }; tests[`${input}<number>.toNumber()`] = (test) => { test.deepEqual(resolve(lib_1.Token.asNumber(new intrinsic_1.Intrinsic(numberToken))), expected); test.done(); }; tests[`${input}<string>.toString()`] = (test) => { test.deepEqual(resolve(new intrinsic_1.Intrinsic(stringToken).toString()), expected); test.done(); }; tests[`${input}<list>.toString()`] = (test) => { test.deepEqual(resolve(new intrinsic_1.Intrinsic(listToken).toString()), expected); test.done(); }; tests[`${input}<number>.toString()`] = (test) => { test.deepEqual(resolve(new intrinsic_1.Intrinsic(numberToken).toString()), expected); test.done(); }; tests[`${input}<string>.toList()`] = (test) => { test.deepEqual(resolve(lib_1.Token.asList(new intrinsic_1.Intrinsic(stringToken))), expected); test.done(); }; tests[`${input}<list>.toList()`] = (test) => { test.deepEqual(resolve(lib_1.Token.asList(new intrinsic_1.Intrinsic(listToken))), expected); test.done(); }; tests[`${input}<number>.toList()`] = (test) => { test.deepEqual(resolve(lib_1.Token.asList(new intrinsic_1.Intrinsic(numberToken))), expected); test.done(); }; } return tests; })(), 'creation stack is attached to errors emitted during resolve'(test) { function showMeInTheStackTrace() { return lib_1.Lazy.stringValue({ produce: () => { throw new Error('fooError'); } }); } const x = showMeInTheStackTrace(); let message; try { resolve(x); } catch (e) { message = e.message; } test.ok(message && message.includes('showMeInTheStackTrace')); test.done(); } }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdC50b2tlbnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJ0ZXN0LnRva2Vucy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQ0EsZ0NBQWtGO0FBQ2xGLHNEQUFnRjtBQUNoRix3REFBcUQ7QUFDckQsb0RBQW9EO0FBRXBELGlEQUE2QztBQXFsQjdDLE1BQU0sUUFBUTtJQUFkO1FBQ2tCLGtCQUFhLEdBQUcsRUFBRSxDQUFDO0lBV3JDLENBQUM7SUFUUSxPQUFPO1FBQ1osT0FBTztZQUNMLElBQUksRUFBRTtnQkFDSixVQUFVLEVBQUUsT0FBTztnQkFDbkIsVUFBVSxFQUFFLElBQUk7YUFDakI7WUFDRCxPQUFPLEVBQUUsSUFBSSxxQkFBUyxDQUFFLEVBQUUsQ0FBQztTQUM1QixDQUFDO0lBQ0osQ0FBQztDQUNGO0FBRUQsTUFBTSxRQUFRO0lBQWQ7UUFDa0Isa0JBQWEsR0FBRyxFQUFFLENBQUM7UUFDNUIsT0FBRSxHQUFHLENBQUUsSUFBSSxRQUFRLEVBQUUsRUFBRSxJQUFJLFFBQVEsRUFBRSxDQUFFLENBQUM7SUFLakQsQ0FBQztJQUhRLE9BQU87UUFDWixPQUFPLElBQUksQ0FBQyxFQUFFLENBQUM7SUFDakIsQ0FBQztDQUNGO0FBRUQsTUFBTSxZQUFZO0lBQ2hCLFlBQXFCLEdBQVc7UUFBWCxRQUFHLEdBQUgsR0FBRyxDQUFRO0lBQ2hDLENBQUM7Q0FDRjtBQUVELE1BQU0sUUFBUyxTQUFRLFlBQVk7SUFHakM7UUFDRSxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUM7UUFITCxRQUFHLEdBQUcsT0FBTyxDQUFDO0lBSXJCLENBQUM7Q0FDRjtBQUVEOztHQUVHO0FBQ0gsU0FBUyxtQkFBbUIsQ0FBQyxLQUFVO0lBQ3JDLE9BQU87UUFDTCxJQUFJLHFCQUFTLENBQUMsS0FBSyxDQUFDO1FBQ3BCLFVBQUksQ0FBQyxRQUFRLENBQUMsRUFBRSxPQUFPLEVBQUUsR0FBRyxFQUFFLENBQUMsS0FBSyxFQUFFLENBQUM7S0FDeEMsQ0FBQztB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QUNyQjtRQUVELElBQUksQ0FBQyxFQUFFLENBQUMsT0FBTyxJQUFJLE9BQU8sQ0FBQyxRQUFRLENBQUMsdUJBQXVCLENBQUMsQ0FBQyxDQUFDO1FBQzlELElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUNkLENBQUM7Q0FDRixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgVGVzdCB9IGZyb20gJ25vZGV1bml0JztcbmltcG9ydCB7IEZuLCBpc1Jlc29sdmFibGVPYmplY3QsIExhenksIFN0YWNrLCBUb2tlbiwgVG9rZW5pemF0aW9uIH0gZnJvbSAnLi4vbGliJztcbmltcG9ydCB7IGNyZWF0ZVRva2VuRG91YmxlLCBleHRyYWN0VG9rZW5Eb3VibGUgfSBmcm9tICcuLi9saWIvcHJpdmF0ZS9lbmNvZGluZyc7XG5pbXBvcnQgeyBJbnRyaW5zaWMgfSBmcm9tICcuLi9saWIvcHJpdmF0ZS9pbnRyaW5zaWMnO1xuaW1wb3J0IHsgZmluZFRva2VucyB9IGZyb20gJy4uL2xpYi9wcml2YXRlL3Jlc29sdmUnO1xuaW1wb3J0IHsgSVJlc29sdmFibGUgfSBmcm9tICcuLi9saWIvcmVzb2x2YWJsZSc7XG5pbXBvcnQgeyBldmFsdWF0ZUNGTiB9IGZyb20gJy4vZXZhbHVhdGUtY2ZuJztcblxuZXhwb3J0ID0ge1xuICAncmVzb2x2ZSBhIHBsYWluIG9sZCBvYmplY3Qgc2hvdWxkIGp1c3QgcmV0dXJuIHRoZSBvYmplY3QnKHRlc3Q6IFRlc3QpIHtcbiAgICBjb25zdCBvYmogPSB7IFBsYWluT2xkT2JqZWN0OiAxMjMsIEFycmF5OiBbIDEsIDIsIDMgXSB9O1xuICAgIHRlc3QuZGVlcEVxdWFsKHJlc29sdmUob2JqKSwgb2JqKTtcbiAgICB0ZXN0LmRvbmUoKTtcbiAgfSxcblxuICAnaWYgYSB2YWx1ZSBpcyBhbiBvYmplY3Qgd2l0aCBhIHRva2VuIHZhbHVlLCBpdCB3aWxsIGJlIGV2YWx1YXRlZCcodGVzdDogVGVzdCkge1xuICAgIGNvbnN0IG9iaiA9IHtcbiAgICAgIFJlZ3VsYXJWYWx1ZTogJ2hlbGxvJyxcbiAgICAgIExhenlWYWx1ZTogbmV3IEludHJpbnNpYygnV29ybGQnKVxuICAgIH07XG5cbiAgICB0ZXN0LmRlZXBFcXVhbChyZXNvbHZlKG9iaiksIHtcbiAgICAgIFJlZ3VsYXJWYWx1ZTogJ2hlbGxvJyxcbiAgICAgIExhenlWYWx1ZTogJ1dvcmxkJ1xuICAgIH0pO1xuXG4gICAgdGVzdC5kb25lKCk7XG4gIH0sXG5cbiAgJ3Rva2VucyBhcmUgZXZhbHVhdGVkIGFueXdoZXJlIGluIHRoZSBvYmplY3QgdHJlZScodGVzdDogVGVzdCkge1xuICAgIGNvbnN0IG9iaiA9IG5ldyBQcm9taXNlMSgpO1xuICAgIGNvbnN0IGFjdHVhbCA9IHJlc29sdmUoeyBPYmo6IG9iaiB9KTtcblxuICAgIHRlc3QuZGVlcEVxdWFsKGFjdHVhbCwge1xuICAgICAgT2JqOiBbXG4gICAgICAgIHtcbiAgICAgICAgRGF0YToge1xuICAgICAgICAgIHN0cmluZ1Byb3A6IFwiaGVsbG9cIixcbiAgICAgICAgICBudW1iZXJQcm9wOiAxMjM0XG4gICAgICAgIH0sXG4gICAgICAgIFJlY3Vyc2U6IDQyXG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgRGF0YToge1xuICAgICAgICAgIHN0cmluZ1Byb3A6IFwiaGVsbG9cIixcbiAgICAgICAgICBudW1iZXJQcm9wOiAxMjM0XG4gICAgICAgIH0sXG4gICAgICAgIFJlY3Vyc2U6IDQyXG4gICAgICAgIH1cbiAgICAgIF1cbiAgICB9KTtcblxuICAgIHRlc3QuZG9uZSgpO1xuICB9LFxuXG4gICd0b2tlbnMgYXJlIGV2YWx1YXRlZCByZWN1cnNpdmVseScodGVzdDogVGVzdCkge1xuICAgIGNvbnN0IG9iaiA9IG5ldyBQcm9taXNlMSgpO1xuICAgIGNvbnN0IGFjdHVhbCA9IHJlc29sdmUobmV3IEludHJpbnNpYyh7IE9iajogb2JqIH0pKTtcblxuICAgIHRlc3QuZGVlcEVxdWFsKGFjdHVhbCwge1xuICAgICAgT2JqOiBbXG4gICAgICAgIHtcbiAgICAgICAgRGF0YToge1xuICAgICAgICAgIHN0cmluZ1Byb3A6IFwiaGVsbG9cIixcbiAgICAgICAgICBudW1iZXJQcm9wOiAxMjM0XG4gICAgICAgIH0sXG4gICAgICAgIFJlY3Vyc2U6IDQyXG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgRGF0YToge1xuICAgICAgICAgIHN0cmluZ1Byb3A6IFwiaGVsbG9cIixcbiAgICAgICAgICBudW1iZXJQcm9wOiAxMjM0XG4gICAgICAgIH0sXG4gICAgICAgIFJlY3Vyc2U6IDQyXG4gICAgICAgIH1cbiAgICAgIF1cbiAgICB9KTtcblxuICAgIHRlc3QuZG9uZSgpO1xuICB9LFxuXG4gICdlbXB0eSBhcnJheXMgb3Igb2JqZWN0cyBhcmUga2VwdCcodGVzdDogVGVzdCkge1xuICAgIHRlc3QuZGVlcEVxdWFsKHJlc29sdmUoeyB9KSwgeyB9KTtcbiAgICB0ZXN0LmRlZXBFcXVhbChyZXNvbHZlKFsgXSksIFsgXSk7XG5cbiAgICBjb25zdCBvYmogPSB7XG4gICAgICBQcm9wMTogMTIzNCxcbiAgICAgIFByb3AyOiB7IH0sXG4gICAgICBQcm9wMzogWyBdLFxuICAgICAgUHJvcDQ6ICdoZWxsbycsXG4gICAgICBQcm9wNToge1xuICAgICAgICBQcm9wQTogeyB9LFxuICAgICAgICBQcm9wQjoge1xuICAgICAgICAgIFByb3BDOiBbIHVuZGVmaW5lZCwgdW5kZWZpbmVkIF0sXG4gICAgICAgICAgUHJvcEQ6ICdZb29ob28nXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGVzdC5kZWVwRXF1YWwocmVzb2x2ZShvYmopLCB7XG4gICAgICBQcm9wMTogMTIzNCxcbiAgICAgIFByb3AyOiB7IH0sXG4gICAgICBQcm9wMzogWyBdLFxuICAgICAgUHJvcDQ6ICdoZWxsbycsXG4gICAgICBQcm9wNToge1xuICAgICAgICBQcm9wQTogeyB9LFxuICAgICAgICBQcm9wQjoge1xuICAgICAgICAgIFByb3BDOiBbIF0sXG4gICAgICAgICAgUHJvcEQ6ICdZb29ob28nXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHRlc3QuZG9uZSgpO1xuICB9LFxuXG4gICdpZiBhbiBvYmplY3QgaGFzIGEgXCJyZXNvbHZlXCIgcHJvcGVydHkgdGhhdCBpcyBub3QgYSBmdW5jdGlvbiwgaXQgaXMgbm90IGNvbnNpZGVyZWQgYSB0b2tlbicodGVzdDogVGVzdCkge1xuICAgIHRlc3QuZGVlcEVxdWFsKHJlc29sdmUoeyBhX3Rva2VuOiB7IHJlc29sdmU6ICgpID0+IDc4Nzg3IH19KSwgeyBhX3Rva2VuOiA3ODc4NyB9KTtcbiAgICB0ZXN0LmRlZXBFcXVhbChyZXNvbHZlKHsgbm90X2FfdG9rZW46IHsgcmVzb2x2ZTogMTIgfSB9KSwgICB7IG5vdF9hX3Rva2VuOiB7IHJlc29sdmU6IDEyIH0gfSk7XG4gICAgdGVzdC5kb25lKCk7XG4gIH0sXG5cbiAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lOm1heC1saW5lLWxlbmd0aFxuICAnaWYgYSByZXNvbHZhYmxlIG9iamVjdCBpbmhlcml0cyBmcm9tIGEgY2xhc3MgdGhhdCBpcyBhbHNvIHJlc29sdmFibGUsIHRoZSBcImNvbnN0cnVjdG9yXCIgZnVuY3Rpb24gd2lsbCBub3QgZ2V0IGluIHRoZSB3YXkgKHVzZXMgT2JqZWN0LmtleXMgaW5zdGVhZCBvZiBcImZvciBpblwiKScodGVzdDogVGVzdCkge1xuICAgIHRlc3QuZGVlcEVxdWFsKHJlc29sdmUoeyBwcm9wOiBuZXcgRGF0YVR5cGUoKSB9KSwgeyBwcm9wOiB7IGZvbzogMTIsIGdvbzogJ2hlbGxvJyB9IH0pO1xuICAgIHRlc3QuZG9uZSgpO1xuICB9LFxuXG4gICdpc1Rva2VuKG9iaikgY2FuIGJlIHVzZWQgdG8gZGV0ZXJtaW5lIGlmIGFuIG9iamVjdCBpcyBhIHRva2VuJyh0ZXN0OiBUZXN0KSB7XG4gICAgdGVzdC5vayhpc1Jlc29sdmFibGVPYmplY3QoeyByZXNvbHZlOiAoKSA9PiAxMjMgfSkpO1xuICAgIHRlc3Qub2soaXNSZXNvbHZhYmxlT2JqZWN0KHsgYTogMSwgYjogMiwgcmVzb2x2ZTogKCkgPT4gJ2hlbGxvJyB9KSk7XG4gICAgdGVzdC5vayghaXNSZXNvbHZhYmxlT2JqZWN0KHsgYTogMSwgYjogMiwgcmVzb2x2ZTogMyB9KSk7XG4gICAgdGVzdC5kb25lKCk7XG4gIH0sXG5cbiAgJ1Rva2VuIGNhbiBiZSB1c2VkIHRvIGNyZWF0ZSB0b2tlbnMgdGhhdCBjb250YWluIGEgY29uc3RhbnQgdmFsdWUnKHRlc3Q6IFRlc3QpIHtcbiAgICB0ZXN0LmVxdWFsKHJlc29sdmUobmV3IEludHJpbnNpYygxMikpLCAxMik7XG4gICAgdGVzdC5lcXVhbChyZXNvbHZlKG5ldyBJbnRyaW5zaWMoJ2hlbGxvJykpLCAnaGVsbG8nKTtcbiAgICB0ZXN0LmRlZXBFcXVhbChyZXNvbHZlKG5ldyBJbnRyaW5zaWMoWyAnaGknLCAndGhlcmUnIF0pKSwgWyAnaGknLCAndGhlcmUnIF0pO1xuICAgIHRlc3QuZG9uZSgpO1xuICB9LFxuXG4gICdyZXNvbHZpbmcgbGVhdmVzIGEgRGF0ZSBvYmplY3QgaW4gd29ya2luZyBvcmRlcicodGVzdDogVGVzdCkge1xuICAgIGNvbnN0IGRhdGUgPSBuZXcgRGF0ZSgnMjAwMC0wMS0wMScpO1xuICAgIGNvbnN0IHJlc29sdmVkID0gcmVzb2x2ZShkYXRlKTtcblxuICAgIHRlc3QuZXF1YWwoZGF0ZS50b1N0cmluZygpLCByZXNvbHZlZC50b1N0cmluZygpKTtcbiAgICB0ZXN0LmRvbmUoKTtcbiAgfSxcblxuICAndG9rZW5zIGNhbiBiZSBzdHJpbmdpZmllZCBhbmQgZXZhbHVhdGVkIHRvIGNvbmNlcHR1YWwgdmFsdWUnKHRlc3Q6IFRlc3QpIHtcbiAgICAvLyBHSVZFTlxuICAgIGNvbnN0IHRva2VuID0gbmV3IEludHJpbnNpYygnd29vZiB3b29mJyk7XG5cbiAgICAvLyBXSEVOXG4gICAgY29uc3Qgc3RyaW5naWZpZWQgPSBgVGhlIGRvZyBzYXlzOiAke3Rva2VufWA7XG4gICAgY29uc3QgcmVzb2x2ZWQgPSByZXNvbHZlKHN0cmluZ2lmaWVkKTtcblxuICAgIC8vIFRIRU5cbiAgICB0ZXN0LmRlZXBFcXVhbChldmFsdWF0ZUNGTihyZXNvbHZlZCksICdUaGUgZG9nIHNheXM6IHdvb2Ygd29vZicpO1xuICAgIHRlc3QuZG9uZSgpO1xuICB9LFxuXG4gICd0b2tlbnMgc3RyaW5naWZpY2F0aW9uIGNhbiBiZSByZXZlcnNlZCcodGVzdDogVGVzdCkge1xuICAgIC8vIEdJVkVOXG4gICAgY29uc3QgdG9rZW4gPSBuZXcgSW50cmluc2ljKCd3b29mIHdvb2YnKTtcblxuICAgIC8vIFRIRU5cbiAgICB0ZXN0LmVxdWFsKHRva2VuLCBUb2tlbml6YXRpb24ucmV2ZXJzZVN0cmluZyhgJHt0b2tlbn1gKS5maXJzdFRva2VuKTtcbiAgICB0ZXN0LmRvbmUoKTtcbiAgfSxcblxuICAnVG9rZW5zIHN0cmluZ2lmaWNhdGlvbiBhbmQgcmV2ZXJzaW5nIG9mIENsb3VkRm9ybWF0aW9uIFRva2VucyBpcyBpbXBsZW1lbnRlZCB1c2luZyBGbjo6Sm9pbicodGVzdDogVGVzdCkge1xuICAgIC8vIEdJVkVOXG4gICAgY29uc3QgdG9rZW4gPSBuZXcgSW50cmluc2ljKCAoeyB3b29mOiAnd29vZicgfSkpO1xuXG4gICAgLy8gV0hFTlxuICAgIGNvbnN0IHN0cmluZ2lmaWVkID0gYFRoZSBkb2cgc2F5czogJHt0b2tlbn1gO1xuICAgIGNvbnN0IHJlc29sdmVkID0gcmVzb2x2ZShzdHJpbmdpZmllZCk7XG5cbiAgICAvLyBUSEVOXG4gICAgdGVzdC5kZWVwRXF1YWwocmVzb2x2ZWQsIHtcbiAgICAgICdGbjo6Sm9pbic6IFsnJywgWydUaGUgZG9nIHNheXM6ICcsIHsgd29vZjogJ3dvb2YnIH1dXVxuICAgIH0pO1xuICAgIHRlc3QuZG9uZSgpO1xuICB9LFxuXG4gICdEb3VibHkgbmVzdGVkIHN0cmluZ3MgZXZhbHVhdGUgY29ycmVjdGx5IGluIHNjYWxhciBjb250ZXh0Jyh0ZXN0OiBUZXN0KSB7XG4gICAgLy8gR0lWRU5cbiAgICBjb25zdCB0b2tlbjEgPSBuZXc