UNPKG

@aws-solutions-constructs/aws-kinesisstreams-kinesisfirehose-s3

Version:

CDK constructs for defining an interaction between an Amazon Kinesis Data Stream (KDS), Amazon Kinesis Data Firehose (KDF) delivery stream and an Amazon S3 bucket.

243 lines 30.7 kB
"use strict"; /** * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * with the License. A copy of the License is located at * * http://www.apache.org/licenses/LICENSE-2.0 * * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * and limitations under the License. */ Object.defineProperty(exports, "__esModule", { value: true }); const lib_1 = require("../lib"); const cdk = require("aws-cdk-lib"); const assertions_1 = require("aws-cdk-lib/assertions"); const defaults = require("@aws-solutions-constructs/core"); const aws_iam_1 = require("aws-cdk-lib/aws-iam"); const s3 = require("aws-cdk-lib/aws-s3"); const kinesis = require("aws-cdk-lib/aws-kinesis"); function deploy(stack, props = {}) { return new lib_1.KinesisStreamsToKinesisFirehoseToS3(stack, 'test-stream-firehose-s3', props); } test('test kinesisFirehose override ', () => { const stack = new cdk.Stack(); deploy(stack, { kinesisFirehoseProps: { extendedS3DestinationConfiguration: { bufferingHints: { intervalInSeconds: 600, sizeInMBs: 55 }, } }, bucketProps: { removalPolicy: cdk.RemovalPolicy.DESTROY, } }); const template = assertions_1.Template.fromStack(stack); template.hasResourceProperties("AWS::KinesisFirehose::DeliveryStream", { ExtendedS3DestinationConfiguration: { BufferingHints: { IntervalInSeconds: 600, SizeInMBs: 55 } } }); }); test('test kinesisFirehose.deliveryStreamType override ', () => { const stack = new cdk.Stack(); deploy(stack, { kinesisFirehoseProps: { deliveryStreamType: 'DirectPut' } }); const template = assertions_1.Template.fromStack(stack); template.hasResourceProperties("AWS::KinesisFirehose::DeliveryStream", { DeliveryStreamType: 'KinesisStreamAsSource' }); }); test('test kinesisFirehose.kinesisStreamSourceConfiguration override ', () => { const stack = new cdk.Stack(); const kinesisStream = defaults.buildKinesisStream(stack, { existingStreamObj: undefined, kinesisStreamProps: undefined }); deploy(stack, { kinesisFirehoseProps: { kinesisStreamSourceConfiguration: { kinesisStreamArn: kinesisStream.streamArn, roleArn: new aws_iam_1.Role(stack, 'myRole', { assumedBy: new aws_iam_1.ServicePrincipal('firehose.amazonaws.com') }).roleArn } } }); const template = assertions_1.Template.fromStack(stack); template.hasResourceProperties("AWS::KinesisFirehose::DeliveryStream", { KinesisStreamSourceConfiguration: { KinesisStreamARN: { "Fn::GetAtt": [ "teststreamfirehoses3KinesisStream3165E68E", "Arn" ] }, RoleARN: { "Fn::GetAtt": [ "KinesisStreamsRole2BFD39A5", "Arn" ] } } }); }); test('test kinesisStreamProps override ', () => { const stack = new cdk.Stack(); deploy(stack, { kinesisStreamProps: { shardCount: 3 } }); const template = assertions_1.Template.fromStack(stack); template.hasResourceProperties("AWS::Kinesis::Stream", { ShardCount: 3 }); }); test('Test All properties', () => { const stack = new cdk.Stack(); const construct = deploy(stack); expect(construct.cloudwatchAlarms).not.toEqual(undefined); expect(construct.kinesisFirehose).not.toEqual(undefined); expect(construct.kinesisFirehoseRole).not.toEqual(undefined); expect(construct.kinesisFirehoseLogGroup).not.toEqual(undefined); expect(construct.kinesisStream).not.toEqual(undefined); expect(construct.kinesisStreamRole).not.toEqual(undefined); expect(construct.s3Bucket).not.toEqual(undefined); expect(construct.s3LoggingBucket).not.toEqual(undefined); }); test('Test properties with no CW Alarms', () => { const stack = new cdk.Stack(); const construct = deploy(stack, { createCloudWatchAlarms: false }); expect(construct.cloudwatchAlarms).toEqual(undefined); }); test('Test properties with existing S3 bucket', () => { const stack = new cdk.Stack(); const existingBucket = defaults.CreateScrapBucket(stack, "scrapBucket"); const mybucket = s3.Bucket.fromBucketName(stack, 'mybucket', existingBucket.bucketName); const construct = deploy(stack, { existingBucketObj: mybucket }); expect(construct.s3Bucket).toEqual(undefined); expect(construct.s3LoggingBucket).toEqual(undefined); }); test('Test properties with existing logging S3 bucket', () => { const stack = new cdk.Stack(); const existingBucket = defaults.CreateScrapBucket(stack, "scrapBucket"); const myLoggingBucket = s3.Bucket.fromBucketName(stack, 'myLoggingBucket', existingBucket.bucketName); const construct = deploy(stack, { existingLoggingBucketObj: myLoggingBucket }); expect(construct.s3Bucket).not.toEqual(undefined); expect(construct.s3LoggingBucket).toEqual(undefined); }); // -------------------------------------------------------------- // Test bad call with existingBucket and bucketProps // -------------------------------------------------------------- test("Test bad call with existingBucket and bucketProps", () => { // Stack const stack = new cdk.Stack(); const testBucket = new s3.Bucket(stack, 'test-bucket', {}); const app = () => { // Helper declaration new lib_1.KinesisStreamsToKinesisFirehoseToS3(stack, "bad-s3-args", { existingBucketObj: testBucket, bucketProps: { removalPolicy: cdk.RemovalPolicy.DESTROY }, }); }; // Assertion expect(app).toThrowError(); }); // -------------------------------------------------------------- // s3 bucket with bucket, loggingBucket, and auto delete objects // -------------------------------------------------------------- test('s3 bucket with bucket, loggingBucket, and auto delete objects', () => { const stack = new cdk.Stack(); new lib_1.KinesisStreamsToKinesisFirehoseToS3(stack, 'kinsisfirehose-s3', { kinesisFirehoseProps: { deliveryStreamType: 'KinesisStreamAsSource' }, bucketProps: { removalPolicy: cdk.RemovalPolicy.DESTROY, }, loggingBucketProps: { removalPolicy: cdk.RemovalPolicy.DESTROY, autoDeleteObjects: true } }); const template = assertions_1.Template.fromStack(stack); template.resourceCountIs("AWS::S3::Bucket", 2); template.hasResourceProperties("Custom::S3AutoDeleteObjects", { ServiceToken: { "Fn::GetAtt": [ "CustomS3AutoDeleteObjectsCustomResourceProviderHandler9D90184F", "Arn" ] }, BucketName: { Ref: "kinsisfirehoses3KinesisFirehoseToS3S3LoggingBucket1CC9C6B7" } }); }); // -------------------------------------------------------------- // s3 bucket with one content bucket and no logging bucket // -------------------------------------------------------------- test('s3 bucket with one content bucket and no logging bucket', () => { const stack = new cdk.Stack(); new lib_1.KinesisStreamsToKinesisFirehoseToS3(stack, 'kinsisfirehose-s3', { kinesisFirehoseProps: { deliveryStreamType: 'KinesisStreamAsSource' }, bucketProps: { removalPolicy: cdk.RemovalPolicy.DESTROY, }, logS3AccessLogs: false }); const template = assertions_1.Template.fromStack(stack); template.resourceCountIs("AWS::S3::Bucket", 1); }); test("Confirm that CheckS3Props is being called", () => { // Stack const stack = new cdk.Stack(); const testBucket = new s3.Bucket(stack, 'test-bucket', {}); const app = () => { // Helper declaration new lib_1.KinesisStreamsToKinesisFirehoseToS3(stack, "bad-s3-args", { existingBucketObj: testBucket, bucketProps: { removalPolicy: cdk.RemovalPolicy.DESTROY }, }); }; // Assertion expect(app).toThrowError("Error - Either provide bucketProps or existingBucketObj, but not both.\n"); }); test('Confirm call to CheckKinesisStreamProps', () => { // Initial Setup const stack = new cdk.Stack(); const props = { existingStreamObj: new kinesis.Stream(stack, 'test', {}), kinesisStreamProps: {} }; const app = () => { new lib_1.KinesisStreamsToKinesisFirehoseToS3(stack, 'test-construct', props); }; // Assertion expect(app).toThrowError('Error - Either provide existingStreamObj or kinesisStreamProps, but not both.\n'); }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoia2luZXNpc3N0cmVhbXMta2luZXNpc2ZpcmVob3NlLXMzLnRlc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJraW5lc2lzc3RyZWFtcy1raW5lc2lzZmlyZWhvc2UtczMudGVzdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7Ozs7Ozs7O0dBV0c7O0FBRUgsZ0NBQXVHO0FBQ3ZHLG1DQUFtQztBQUNuQyx1REFBa0Q7QUFDbEQsMkRBQTJEO0FBQzNELGlEQUE2RDtBQUM3RCx5Q0FBeUM7QUFDekMsbURBQW1EO0FBRW5ELFNBQVMsTUFBTSxDQUFDLEtBQWdCLEVBQUUsUUFBa0QsRUFBRTtJQUNwRixPQUFPLElBQUkseUNBQW1DLENBQUMsS0FBSyxFQUFFLHlCQUF5QixFQUFFLEtBQUssQ0FBQyxDQUFDO0FBQzFGLENBQUM7QUFFRCxJQUFJLENBQUMsZ0NBQWdDLEVBQUUsR0FBRyxFQUFFO0lBQzFDLE1BQU0sS0FBSyxHQUFHLElBQUksR0FBRyxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQzlCLE1BQU0sQ0FBQyxLQUFLLEVBQUU7UUFDWixvQkFBb0IsRUFBRTtZQUNwQixrQ0FBa0MsRUFBRTtnQkFDbEMsY0FBYyxFQUFFO29CQUNkLGlCQUFpQixFQUFFLEdBQUc7b0JBQ3RCLFNBQVMsRUFBRSxFQUFFO2lCQUNkO2FBQ0Y7U0FDRjtRQUNELFdBQVcsRUFBRTtZQUNYLGFBQWEsRUFBRSxHQUFHLENBQUMsYUFBYSxDQUFDLE9BQU87U0FDekM7S0FDRixDQUFDLENBQUM7SUFFSCxNQUFNLFFBQVEsR0FBRyxxQkFBUSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUMzQyxRQUFRLENBQUMscUJBQXFCLENBQUMsc0NBQXNDLEVBQUU7UUFDckUsa0NBQWtDLEVBQUU7WUFDbEMsY0FBYyxFQUFFO2dCQUNkLGlCQUFpQixFQUFFLEdBQUc7Z0JBQ3RCLFNBQVMsRUFBRSxFQUFFO2FBQ2Q7U0FDRjtLQUFDLENBQUMsQ0FBQztBQUNSLENB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O0lBQ0wsQ0FBQyxDQUFDO0lBQ0YsWUFBWTtJQUNaLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxZQUFZLENBQUMsMEVBQTBFLENBQUMsQ0FBQztBQUN2RyxDQUFDLENBQUMsQ0FBQztBQUVILElBQUksQ0FBQyx5Q0FBeUMsRUFBRSxHQUFHLEVBQUU7SUFDbkQsZ0JBQWdCO0lBQ2hCLE1BQU0sS0FBSyxHQUFHLElBQUksR0FBRyxDQUFDLEtBQUssRUFBRSxDQUFDO0lBRTlCLE1BQU0sS0FBSyxHQUE2QztRQUN0RCxpQkFBaUIsRUFBRSxJQUFJLE9BQU8sQ0FBQyxNQUFNLENBQUMsS0FBSyxFQUFFLE1BQU0sRUFBRSxFQUFFLENBQUM7UUFDeEQsa0JBQWtCLEVBQUUsRUFBRTtLQUN2QixDQUFDO0lBQ0YsTUFBTSxHQUFHLEdBQUcsR0FBRyxFQUFFO1FBQ2YsSUFBSSx5Q0FBbUMsQ0FBQyxLQUFLLEVBQUUsZ0JBQWdCLEVBQUUsS0FBSyxDQUFDLENBQUM7SUFDMUUsQ0FBQyxDQUFDO0lBQ0YsWUFBWTtJQUNaLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxZQUFZLENBQUMsaUZBQWlGLENBQUMsQ0FBQztBQUM5RyxDQUFDLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogIENvcHlyaWdodCBBbWF6b24uY29tLCBJbmMuIG9yIGl0cyBhZmZpbGlhdGVzLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICpcbiAqICBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgXCJMaWNlbnNlXCIpLiBZb3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlXG4gKiAgd2l0aCB0aGUgTGljZW5zZS4gQSBjb3B5IG9mIHRoZSBMaWNlbnNlIGlzIGxvY2F0ZWQgYXRcbiAqXG4gKiAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuICpcbiAqICBvciBpbiB0aGUgJ2xpY2Vuc2UnIGZpbGUgYWNjb21wYW55aW5nIHRoaXMgZmlsZS4gVGhpcyBmaWxlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuICdBUyBJUycgQkFTSVMsIFdJVEhPVVQgV0FSUkFOVElFU1xuICogIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGV4cHJlc3Mgb3IgaW1wbGllZC4gU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zXG4gKiAgYW5kIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLlxuICovXG5cbmltcG9ydCB7IEtpbmVzaXNTdHJlYW1zVG9LaW5lc2lzRmlyZWhvc2VUb1MzLCBLaW5lc2lzU3RyZWFtc1RvS2luZXNpc0ZpcmVob3NlVG9TM1Byb3BzIH0gZnJvbSAnLi4vbGliJztcbmltcG9ydCAqIGFzIGNkayBmcm9tICdhd3MtY2RrLWxpYic7XG5pbXBvcnQgeyBUZW1wbGF0ZSB9IGZyb20gJ2F3cy1jZGstbGliL2Fzc2VydGlvbnMnO1xuaW1wb3J0ICogYXMgZGVmYXVsdHMgZnJvbSAnQGF3cy1zb2x1dGlvbnMtY29uc3RydWN0cy9jb3JlJztcbmltcG9ydCB7IFJvbGUsIFNlcnZpY2VQcmluY2lwYWwgfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtaWFtJztcbmltcG9ydCAqIGFzIHMzIGZyb20gJ2F3cy1jZGstbGliL2F3cy1zMyc7XG5pbXBvcnQgKiBhcyBraW5lc2lzIGZyb20gJ2F3cy1jZGstbGliL2F3cy1raW5lc2lzJztcblxuZnVuY3Rpb24gZGVwbG95KHN0YWNrOiBjZGsuU3RhY2ssIHByb3BzOiBLaW5lc2lzU3RyZWFtc1RvS2luZXNpc0ZpcmVob3NlVG9TM1Byb3BzID0ge30pIHtcbiAgcmV0dXJuIG5ldyBLaW5lc2lzU3RyZWFtc1RvS2luZXNpc0ZpcmVob3NlVG9TMyhzdGFjaywgJ3Rlc3Qtc3RyZWFtLWZpcmVob3NlLXMzJywgcHJvcHMpO1xufVxuXG50ZXN0KCd0ZXN0IGtpbmVzaXNGaXJlaG9zZSBvdmVycmlkZSAnLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuICBkZXBsb3koc3RhY2ssIHtcbiAgICBraW5lc2lzRmlyZWhvc2VQcm9wczoge1xuICAgICAgZXh0ZW5kZWRTM0Rlc3RpbmF0aW9uQ29uZmlndXJhdGlvbjoge1xuICAgICAgICBidWZmZXJpbmdIaW50czoge1xuICAgICAgICAgIGludGVydmFsSW5TZWNvbmRzOiA2MDAsXG4gICAgICAgICAgc2l6ZUluTUJzOiA1NVxuICAgICAgICB9LFxuICAgICAgfVxuICAgIH0sXG4gICAgYnVja2V0UHJvcHM6IHtcbiAgICAgIHJlbW92YWxQb2xpY3k6IGNkay5SZW1vdmFsUG9saWN5LkRFU1RST1ksXG4gICAgfVxuICB9KTtcblxuICBjb25zdCB0ZW1wbGF0ZSA9IFRlbXBsYXRlLmZyb21TdGFjayhzdGFjayk7XG4gIHRlbXBsYXRlLmhhc1Jlc291cmNlUHJvcGVydGllcyhcIkFXUzo6S2luZXNpc0ZpcmVob3NlOjpEZWxpdmVyeVN0cmVhbVwiLCB7XG4gICAgRXh0ZW5kZWRTM0Rlc3RpbmF0aW9uQ29uZmlndXJhdGlvbjoge1xuICAgICAgQnVmZmVyaW5nSGludHM6IHtcbiAgICAgICAgSW50ZXJ2YWxJblNlY29uZHM6IDYwMCxcbiAgICAgICAgU2l6ZUluTUJzOiA1NVxuICAgICAgfVxuICAgIH19KTtcbn0pO1xuXG50ZXN0KCd0ZXN0IGtpbmVzaXNGaXJlaG9zZS5kZWxpdmVyeVN0cmVhbVR5cGUgb3ZlcnJpZGUgJywgKCkgPT4ge1xuICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcbiAgZGVwbG95KHN0YWNrLCB7XG4gICAga2luZXNpc0ZpcmVob3NlUHJvcHM6IHtcbiAgICAgIGRlbGl2ZXJ5U3RyZWFtVHlwZTogJ0RpcmVjdFB1dCdcbiAgICB9XG4gIH0pO1xuXG4gIGNvbnN0IHRlbXBsYXRlID0gVGVtcGxhdGUuZnJvbVN0YWNrKHN0YWNrKTtcbiAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKFwiQVdTOjpLaW5lc2lzRmlyZWhvc2U6OkRlbGl2ZXJ5U3RyZWFtXCIsIHtcbiAgICBEZWxpdmVyeVN0cmVhbVR5cGU6ICdLaW5lc2lzU3RyZWFtQXNTb3VyY2UnXG4gIH0pO1xufSk7XG5cbnRlc3QoJ3Rlc3Qga2luZXNpc0ZpcmVob3NlLmtpbmVzaXNTdHJlYW1Tb3VyY2VDb25maWd1cmF0aW9uIG92ZXJyaWRlICcsICgpID0+IHtcbiAgY29uc3Qgc3RhY2sgPSBuZXcgY2RrLlN0YWNrKCk7XG5cbiAgY29uc3Qga2luZXNpc1N0cmVhbSA9IGRlZmF1bHRzLmJ1aWxkS2luZXNpc1N0cmVhbShzdGFjaywge1xuICAgIGV4aXN0aW5nU3RyZWFtT2JqOiB1bmRlZmluZWQsXG4gICAga2luZXNpc1N0cmVhbVByb3BzOiB1bmRlZmluZWRcbiAgfSk7XG5cbiAgZGVwbG95KHN0YWNrLCB7XG4gICAga2luZXNpc0ZpcmVob3NlUHJvcHM6IHtcbiAgICAgIGtpbmVzaXNTdHJlYW1Tb3VyY2VDb25maWd1cmF0aW9uOiB7XG4gICAgICAgIGtpbmVzaXNTdHJlYW1Bcm46IGtpbmVzaXNTdHJlYW0uc3RyZWFtQXJuLFxuICAgICAgICByb2xlQXJuOiBuZXcgUm9sZShzdGFjaywgJ215Um9sZScsIHtcbiAgICAgICAgICBhc3N1bWVkQnk6IG5ldyBTZXJ2aWNlUHJpbmNpcGFsKCdmaXJlaG9zZS5hbWF6b25hd3MuY29tJylcbiAgICAgICAgfSkucm9sZUFyblxuICAgICAgfVxuICAgIH1cbiAgfSk7XG5cbiAgY29uc3QgdGVtcGxhdGUgPSBUZW1wbGF0ZS5mcm9tU3RhY2soc3RhY2spO1xuICB0ZW1wbGF0ZS5oYXNSZXNvdXJjZVByb3BlcnRpZXMoXCJBV1M6OktpbmVzaXNGaXJlaG9zZTo6RGVsaXZlcnlTdHJlYW1cIiwge1xuICAgIEtpbmVzaXNTdHJlYW1Tb3VyY2VDb25maWd1cmF0aW9uOiB7XG4gICAgICBLaW5lc2lzU3RyZWFtQVJOOiB7XG4gICAgICAgIFwiRm46OkdldEF0dFwiOiBbXG4gICAgICAgICAgXCJ0ZXN0c3RyZWFtZmlyZWhvc2VzM0tpbmVzaXNTdHJlYW0zMTY1RTY4RVwiLFxuICAgICAgICAgIFwiQXJuXCJcbiAgICAgICAgXVxuICAgICAgfSxcbiAgICAgIFJvbGVBUk46IHtcbiAgICAgICAgXCJGbjo6R2V0QXR0XCI6IFtcbiAgICAgICAgICBcIktpbmVzaXNTdHJlYW1zUm9sZTJCRkQzOUE1XCIsXG4gICAgICAgICAgXCJBcm5cIlxuICAgICAgICBdXG4gICAgICB9XG4gICAgfVxuICB9KTtcbn0pO1xuXG50ZXN0KCd0ZXN0IGtpbmVzaXNTdHJlYW1Qcm9wcyBvdmVycmlkZSAnLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuXG4gIGRlcGxveShzdGFjaywge1xuICAgIGtpbmVzaXNTdHJlYW1Qcm9wczoge1xuICAgICAgc2hhcmRDb3VudDogM1xuICAgIH1cbiAgfSk7XG5cbiAgY29uc3QgdGVtcGxhdGUgPSBUZW1wbGF0ZS5mcm9tU3RhY2soc3RhY2spO1xuICB0ZW1wbGF0ZS5oYXNSZXNvdXJjZVByb3BlcnRpZXMoXCJBV1M6OktpbmVzaXM6OlN0cmVhbVwiLCB7XG4gICAgU2hhcmRDb3VudDogM1xuICB9KTtcbn0pO1xuXG50ZXN0KCdUZXN0IEFsbCBwcm9wZXJ0aWVzJywgKCkgPT4ge1xuICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcbiAgY29uc3QgY29uc3RydWN0OiBLaW5lc2lzU3RyZWFtc1RvS2luZXNpc0ZpcmVob3NlVG9TMyA9IGRlcGxveShzdGFjayk7XG5cbiAgZXhwZWN0KGNvbnN0cnVjdC5jbG91ZHdhdGNoQWxhcm1zKS5ub3QudG9FcXVhbCh1bmRlZmluZWQpO1xuICBleHBlY3QoY29uc3RydWN0LmtpbmVzaXNGaXJlaG9zZSkubm90LnRvRXF1YWwodW5kZWZpbmVkKTtcbiAgZXhwZWN0KGNvbnN0cnVjdC5raW5lc2lzRmlyZWhvc2VSb2xlKS5ub3QudG9FcXVhbCh1bmRlZmluZWQpO1xuICBleHBlY3QoY29uc3RydWN0LmtpbmVzaXNGaXJlaG9zZUxvZ0dyb3VwKS5ub3QudG9FcXVhbCh1bmRlZmluZWQpO1xuICBleHBlY3QoY29uc3RydWN0LmtpbmVzaXNTdHJlYW0pLm5vdC50b0VxdWFsKHVuZGVmaW5lZCk7XG4gIGV4cGVjdChjb25zdHJ1Y3Qua2luZXNpc1N0cmVhbVJvbGUpLm5vdC50b0VxdWFsKHVuZGVmaW5lZCk7XG4gIGV4cGVjdChjb25zdHJ1Y3QuczNCdWNrZXQpLm5vdC50b0VxdWFsKHVuZGVmaW5lZCk7XG4gIGV4cGVjdChjb25zdHJ1Y3QuczNMb2dnaW5nQnVja2V0KS5ub3QudG9FcXVhbCh1bmRlZmluZWQpO1xufSk7XG5cbnRlc3QoJ1Rlc3QgcHJvcGVydGllcyB3aXRoIG5vIENXIEFsYXJtcycsICgpID0+IHtcbiAgY29uc3Qgc3RhY2sgPSBuZXcgY2RrLlN0YWNrKCk7XG4gIGNvbnN0IGNvbnN0cnVjdDogS2luZXNpc1N0cmVhbXNUb0tpbmVzaXNGaXJlaG9zZVRvUzMgID0gZGVwbG95KHN0YWNrLCB7XG4gICAgY3JlYXRlQ2xvdWRXYXRjaEFsYXJtczogZmFsc2VcbiAgfSk7XG5cbiAgZXhwZWN0KGNvbnN0cnVjdC5jbG91ZHdhdGNoQWxhcm1zKS50b0VxdWFsKHVuZGVmaW5lZCk7XG59KTtcblxudGVzdCgnVGVzdCBwcm9wZXJ0aWVzIHdpdGggZXhpc3RpbmcgUzMgYnVja2V0JywgKCkgPT4ge1xuICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcbiAgY29uc3QgZXhpc3RpbmdCdWNrZXQgPSBkZWZhdWx0cy5DcmVhdGVTY3JhcEJ1Y2tldChzdGFjaywgXCJzY3JhcEJ1Y2tldFwiKTtcbiAgY29uc3QgbXlidWNrZXQ6IHMzLklCdWNrZXQgPSBzMy5CdWNrZXQuZnJvbUJ1Y2tldE5hbWUoc3RhY2ssICdteWJ1Y2tldCcsIGV4aXN0aW5nQnVja2V0LmJ1Y2tldE5hbWUpO1xuICBjb25zdCBjb25zdHJ1Y3Q6IEtpbmVzaXNTdHJlYW1zVG9LaW5lc2lzRmlyZWhvc2VUb1MzID0gZGVwbG95KHN0YWNrLCB7XG4gICAgZXhpc3RpbmdCdWNrZXRPYmo6IG15YnVja2V0XG4gIH0pO1xuXG4gIGV4cGVjdChjb25zdHJ1Y3QuczNCdWNrZXQpLnRvRXF1YWwodW5kZWZpbmVkKTtcbiAgZXhwZWN0KGNvbnN0cnVjdC5zM0xvZ2dpbmdCdWNrZXQpLnRvRXF1YWwodW5kZWZpbmVkKTtcbn0pO1xuXG50ZXN0KCdUZXN0IHByb3BlcnRpZXMgd2l0aCBleGlzdGluZyBsb2dnaW5nIFMzIGJ1Y2tldCcsICgpID0+IHtcbiAgY29uc3Qgc3RhY2sgPSBuZXcgY2RrLlN0YWNrKCk7XG4gIGNvbnN0IGV4aXN0aW5nQnVja2V0ID0gZGVmYXVsdHMuQ3JlYXRlU2NyYXBCdWNrZXQoc3RhY2ssIFwic2NyYXBCdWNrZXRcIik7XG4gIGNvbnN0IG15TG9nZ2luZ0J1Y2tldDogczMuSUJ1Y2tldCA9IHMzLkJ1Y2tldC5mcm9tQnVja2V0TmFtZShzdGFjaywgJ215TG9nZ2luZ0J1Y2tldCcsIGV4aXN0aW5nQnVja2V0LmJ1Y2tldE5hbWUpO1xuICBjb25zdCBjb25zdHJ1Y3Q6IEtpbmVzaXNTdHJlYW1zVG9LaW5lc2lzRmlyZWhvc2VUb1MzICA9IGRlcGxveShzdGFjaywge1xuICAgIGV4aXN0aW5nTG9nZ2luZ0J1Y2tldE9iajogbXlMb2dnaW5nQnVja2V0XG4gIH0pO1xuXG4gIGV4cGVjdChjb25zdHJ1Y3QuczNCdWNrZXQpLm5vdC50b0VxdWFsKHVuZGVmaW5lZCk7XG4gIGV4cGVjdChjb25zdHJ1Y3QuczNMb2dnaW5nQnVja2V0KS50b0VxdWFsKHVuZGVmaW5lZCk7XG59KTtcblxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIFRlc3QgYmFkIGNhbGwgd2l0aCBleGlzdGluZ0J1Y2tldCBhbmQgYnVja2V0UHJvcHNcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG50ZXN0KFwiVGVzdCBiYWQgY2FsbCB3aXRoIGV4aXN0aW5nQnVja2V0IGFuZCBidWNrZXRQcm9wc1wiLCAoKSA9PiB7XG4gIC8vIFN0YWNrXG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuXG4gIGNvbnN0IHRlc3RCdWNrZXQgPSBuZXcgczMuQnVja2V0KHN0YWNrLCAndGVzdC1idWNrZXQnLCB7fSk7XG5cbiAgY29uc3QgYXBwID0gKCkgPT4ge1xuICAgIC8vIEhlbHBlciBkZWNsYXJhdGlvblxuICAgIG5ldyBLaW5lc2lzU3RyZWFtc1RvS2luZXNpc0ZpcmVob3NlVG9TMyhzdGFjaywgXCJiYWQtczMtYXJnc1wiLCB7XG4gICAgICBleGlzdGluZ0J1Y2tldE9iajogdGVzdEJ1Y2tldCxcbiAgICAgIGJ1Y2tldFByb3BzOiB7XG4gICAgICAgIHJlbW92YWxQb2xpY3k6IGNkay5SZW1vdmFsUG9saWN5LkRFU1RST1lcbiAgICAgIH0sXG4gICAgfSk7XG4gIH07XG4gIC8vIEFzc2VydGlvblxuICBleHBlY3QoYXBwKS50b1Rocm93RXJyb3IoKTtcbn0pO1xuXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuLy8gczMgYnVja2V0IHdpdGggYnVja2V0LCBsb2dnaW5nQnVja2V0LCBhbmQgYXV0byBkZWxldGUgb2JqZWN0c1xuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbnRlc3QoJ3MzIGJ1Y2tldCB3aXRoIGJ1Y2tldCwgbG9nZ2luZ0J1Y2tldCwgYW5kIGF1dG8gZGVsZXRlIG9iamVjdHMnLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuXG4gIG5ldyBLaW5lc2lzU3RyZWFtc1RvS2luZXNpc0ZpcmVob3NlVG9TMyhzdGFjaywgJ2tpbnNpc2ZpcmVob3NlLXMzJywge1xuICAgIGtpbmVzaXNGaXJlaG9zZVByb3BzOiB7XG4gICAgICBkZWxpdmVyeVN0cmVhbVR5cGU6ICdLaW5lc2lzU3RyZWFtQXNTb3VyY2UnXG4gICAgfSxcbiAgICBidWNrZXRQcm9wczoge1xuICAgICAgcmVtb3ZhbFBvbGljeTogY2RrLlJlbW92YWxQb2xpY3kuREVTVFJPWSxcbiAgICB9LFxuICAgIGxvZ2dpbmdCdWNrZXRQcm9wczoge1xuICAgICAgcmVtb3ZhbFBvbGljeTogY2RrLlJlbW92YWxQb2xpY3kuREVTVFJPWSxcbiAgICAgIGF1dG9EZWxldGVPYmplY3RzOiB0cnVlXG4gICAgfVxuICB9KTtcblxuICBjb25zdCB0ZW1wbGF0ZSA9IFRlbXBsYXRlLmZyb21TdGFjayhzdGFjayk7XG4gIHRlbXBsYXRlLnJlc291cmNlQ291bnRJcyhcIkFXUzo6UzM6OkJ1Y2tldFwiLCAyKTtcblxuICB0ZW1wbGF0ZS5oYXNSZXNvdXJjZVByb3BlcnRpZXMoXCJDdXN0b206OlMzQXV0b0RlbGV0ZU9iamVjdHNcIiwge1xuICAgIFNlcnZpY2VUb2tlbjoge1xuICAgICAgXCJGbjo6R2V0QXR0XCI6IFtcbiAgICAgICAgXCJDdXN0b21TM0F1dG9EZWxldGVPYmplY3RzQ3VzdG9tUmVzb3VyY2VQcm92aWRlckhhbmRsZXI5RDkwMTg0RlwiLFxuICAgICAgICBcIkFyblwiXG4gICAgICBdXG4gICAgfSxcbiAgICBCdWNrZXROYW1lOiB7XG4gICAgICBSZWY6IFwia2luc2lzZmlyZWhvc2VzM0tpbmVzaXNGaXJlaG9zZVRvUzNTM0xvZ2dpbmdCdWNrZXQxQ0M5QzZCN1wiXG4gICAgfVxuICB9KTtcbn0pO1xuXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuLy8gczMgYnVja2V0IHdpdGggb25lIGNvbnRlbnQgYnVja2V0IGFuZCBubyBsb2dnaW5nIGJ1Y2tldFxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbnRlc3QoJ3MzIGJ1Y2tldCB3aXRoIG9uZSBjb250ZW50IGJ1Y2tldCBhbmQgbm8gbG9nZ2luZyBidWNrZXQnLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuXG4gIG5ldyBLaW5lc2lzU3RyZWFtc1RvS2luZXNpc0ZpcmVob3NlVG9TMyhzdGFjaywgJ2tpbnNpc2ZpcmVob3NlLXMzJywge1xuICAgIGtpbmVzaXNGaXJlaG9zZVByb3BzOiB7XG4gICAgICBkZWxpdmVyeVN0cmVhbVR5cGU6ICdLaW5lc2lzU3RyZWFtQXNTb3VyY2UnXG4gICAgfSxcbiAgICBidWNrZXRQcm9wczoge1xuICAgICAgcmVtb3ZhbFBvbGljeTogY2RrLlJlbW92YWxQb2xpY3kuREVTVFJPWSxcbiAgICB9LFxuICAgIGxvZ1MzQWNjZXNzTG9nczogZmFsc2VcbiAgfSk7XG5cbiAgY29uc3QgdGVtcGxhdGUgPSBUZW1wbGF0ZS5mcm9tU3RhY2soc3RhY2spO1xuICB0ZW1wbGF0ZS5yZXNvdXJjZUNvdW50SXMoXCJBV1M6OlMzOjpCdWNrZXRcIiwgMSk7XG59KTtcblxudGVzdChcIkNvbmZpcm0gdGhhdCBDaGVja1MzUHJvcHMgaXMgYmVpbmcgY2FsbGVkXCIsICgpID0+IHtcbiAgLy8gU3RhY2tcbiAgY29uc3Qgc3RhY2sgPSBuZXcgY2RrLlN0YWNrKCk7XG5cbiAgY29uc3QgdGVzdEJ1Y2tldCA9IG5ldyBzMy5CdWNrZXQoc3RhY2ssICd0ZXN0LWJ1Y2tldCcsIHt9KTtcblxuICBjb25zdCBhcHAgPSAoKSA9PiB7XG4gICAgLy8gSGVscGVyIGRlY2xhcmF0aW9uXG4gICAgbmV3IEtpbmVzaXNTdHJlYW1zVG9LaW5lc2lzRmlyZWhvc2VUb1MzKHN0YWNrLCBcImJhZC1zMy1hcmdzXCIsIHtcbiAgICAgIGV4aXN0aW5nQnVja2V0T2JqOiB0ZXN0QnVja2V0LFxuICAgICAgYnVja2V0UHJvcHM6IHtcbiAgICAgICAgcmVtb3ZhbFBvbGljeTogY2RrLlJlbW92YWxQb2xpY3kuREVTVFJPWVxuICAgICAgfSxcbiAgICB9KTtcbiAgfTtcbiAgLy8gQXNzZXJ0aW9uXG4gIGV4cGVjdChhcHApLnRvVGhyb3dFcnJvcihcIkVycm9yIC0gRWl0aGVyIHByb3ZpZGUgYnVja2V0UHJvcHMgb3IgZXhpc3RpbmdCdWNrZXRPYmosIGJ1dCBub3QgYm90aC5cXG5cIik7XG59KTtcblxudGVzdCgnQ29uZmlybSBjYWxsIHRvIENoZWNrS2luZXNpc1N0cmVhbVByb3BzJywgKCkgPT4ge1xuICAvLyBJbml0aWFsIFNldHVwXG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuXG4gIGNvbnN0IHByb3BzOiBLaW5lc2lzU3RyZWFtc1RvS2luZXNpc0ZpcmVob3NlVG9TM1Byb3BzID0ge1xuICAgIGV4aXN0aW5nU3RyZWFtT2JqOiBuZXcga2luZXNpcy5TdHJlYW0oc3RhY2ssICd0ZXN0Jywge30pLFxuICAgIGtpbmVzaXNTdHJlYW1Qcm9wczoge31cbiAgfTtcbiAgY29uc3QgYXBwID0gKCkgPT4ge1xuICAgIG5ldyBLaW5lc2lzU3RyZWFtc1RvS2luZXNpc0ZpcmVob3NlVG9TMyhzdGFjaywgJ3Rlc3QtY29uc3RydWN0JywgcHJvcHMpO1xuICB9O1xuICAvLyBBc3NlcnRpb25cbiAgZXhwZWN0KGFwcCkudG9UaHJvd0Vycm9yKCdFcnJvciAtIEVpdGhlciBwcm92aWRlIGV4aXN0aW5nU3RyZWFtT2JqIG9yIGtpbmVzaXNTdHJlYW1Qcm9wcywgYnV0IG5vdCBib3RoLlxcbicpO1xufSk7XG4iXX0=