@aws-cdk/core
Version:
AWS Cloud Development Kit Core Library
539 lines • 66.6 kB
JavaScript
"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