@aws-solutions-constructs/core
Version:
Core CDK Construct for patterns library
633 lines • 69.9 kB
JavaScript
"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 aws_cdk_lib_1 = require("aws-cdk-lib");
const dynamodb = require("aws-cdk-lib/aws-dynamodb");
const defaults = require("../index");
const utils_1 = require("../lib/utils");
const assertions_1 = require("aws-cdk-lib/assertions");
const dynamodb_table_helper_1 = require("../lib/dynamodb-table-helper");
test('test TableProps change billing mode', () => {
const stack = new aws_cdk_lib_1.Stack();
const defaultProps = defaults.GetDefaultTableProps({
partitionKey: {
name: 'donotuse',
type: dynamodb.AttributeType.BINARY
},
});
const inProps = {
billingMode: dynamodb.BillingMode.PROVISIONED,
readCapacity: 3,
writeCapacity: 3,
partitionKey: {
name: 'id',
type: dynamodb.AttributeType.STRING
}
};
const outProps = (0, utils_1.overrideProps)(defaultProps, inProps);
new dynamodb.Table(stack, 'test-dynamo-override', outProps);
const template = assertions_1.Template.fromStack(stack);
template.hasResourceProperties("AWS::DynamoDB::Table", {
KeySchema: [
{
AttributeName: "id",
KeyType: "HASH"
}
],
AttributeDefinitions: [
{
AttributeName: "id",
AttributeType: "S"
}
],
ProvisionedThroughput: {
ReadCapacityUnits: 3,
WriteCapacityUnits: 3
},
SSESpecification: {
SSEEnabled: true
}
});
});
test('test TableProps override add sort key', () => {
const stack = new aws_cdk_lib_1.Stack();
const defaultProps = defaults.GetDefaultTableProps({
partitionKey: {
name: 'donotuse',
type: dynamodb.AttributeType.BINARY
},
});
const inProps = {
partitionKey: {
name: 'id',
type: dynamodb.AttributeType.STRING
},
sortKey: {
name: 'sort_key',
type: dynamodb.AttributeType.STRING
}
};
const outProps = (0, utils_1.overrideProps)(defaultProps, inProps);
new dynamodb.Table(stack, 'test-dynamo-override', outProps);
const template = assertions_1.Template.fromStack(stack);
template.hasResourceProperties("AWS::DynamoDB::Table", {
KeySchema: [
{
AttributeName: "id",
KeyType: "HASH"
},
{
AttributeName: "sort_key",
KeyType: "RANGE"
}
],
AttributeDefinitions: [
{
AttributeName: "id",
AttributeType: "S"
},
{
AttributeName: "sort_key",
AttributeType: "S"
}
],
BillingMode: "PAY_PER_REQUEST",
SSESpecification: {
SSEEnabled: true
}
});
});
test('test TableWithStreamProps override stream view type', () => {
const stack = new aws_cdk_lib_1.Stack();
const defaultProps = defaults.GetDefaultTableWithStreamProps({
partitionKey: {
name: 'donotuse',
type: dynamodb.AttributeType.BINARY
},
});
const inProps = {
partitionKey: {
name: 'id',
type: dynamodb.AttributeType.STRING
},
stream: dynamodb.StreamViewType.NEW_IMAGE
};
const outProps = (0, utils_1.overrideProps)(defaultProps, inProps);
new dynamodb.Table(stack, 'test-dynamo-override', outProps);
const template = assertions_1.Template.fromStack(stack);
template.hasResourceProperties("AWS::DynamoDB::Table", {
KeySchema: [
{
AttributeName: "id",
KeyType: "HASH"
}
],
AttributeDefinitions: [
{
AttributeName: "id",
AttributeType: "S"
}
],
BillingMode: "PAY_PER_REQUEST",
SSESpecification: {
SSEEnabled: true
},
StreamSpecification: {
StreamViewType: "NEW_IMAGE"
}
});
});
test('test buildDynamoDBTable with existingTableObj', () => {
const stack = new aws_cdk_lib_1.Stack();
const tableProps = {
billingMode: dynamodb.BillingMode.PROVISIONED,
partitionKey: {
name: 'table_id',
type: dynamodb.AttributeType.STRING
}
};
const existingTableObj = new dynamodb.Table(stack, 'DynamoTable', tableProps);
const buildDynamoDBTableResponse = defaults.buildDynamoDBTable(stack, {
existingTableObj
});
expect(buildDynamoDBTableResponse.tableInterface).toBeDefined();
expect(buildDynamoDBTableResponse.tableObject).toBeDefined();
const template = assertions_1.Template.fromStack(stack);
template.hasResourceProperties('AWS::DynamoDB::Table', {
KeySchema: [
{
AttributeName: "table_id",
KeyType: "HASH"
}
]
});
template.hasResourceProperties('AWS::DynamoDB::Table', {
ProvisionedThroughput: {
ReadCapacityUnits: 5,
WriteCapacityUnits: 5
}
});
});
test('test buildDynamoDBTable without any arguments', () => {
const stack = new aws_cdk_lib_1.Stack();
const buildDynamoDBTableResponse = defaults.buildDynamoDBTable(stack, {});
expect(buildDynamoDBTableResponse.tableInterface).toBeDefined();
expect(buildDynamoDBTableResponse.tableObject).toBeDefined();
const template = assertions_1.Template.fromStack(stack);
template.hasResourceProperties('AWS::DynamoDB::Table', {
KeySchema: [
{
AttributeName: "id",
KeyType: "HASH"
}
]
});
template.hasResourceProperties('AWS::DynamoDB::Table', {
BillingMode: "PAY_PER_REQUEST"
});
template.hasResourceProperties('AWS::DynamoDB::Table', {
SSESpecification: {
SSEEnabled: true
}
});
});
test('test buildDynamoDBTable with TableProps', () => {
const stack = new aws_cdk_lib_1.Stack();
const dynamoTableProps = {
billingMode: dynamodb.BillingMode.PROVISIONED,
partitionKey: {
name: 'table_id',
type: dynamodb.AttributeType.STRING
}
};
const buildDynamoDBTableResponse = defaults.buildDynamoDBTable(stack, {
dynamoTableProps
});
expect(buildDynamoDBTableResponse.tableInterface).toBeDefined();
expect(buildDynamoDBTableResponse.tableObject).toBeDefined();
const template = assertions_1.Template.fromStack(stack);
template.hasResourceProperties('AWS::DynamoDB::Table', {
KeySchema: [
{
AttributeName: "table_id",
KeyType: "HASH"
}
]
});
template.hasResourceProperties('AWS::DynamoDB::Table', {
ProvisionedThroughput: {
ReadCapacityUnits: 5,
WriteCapacityUnits: 5
}
});
});
test('test buildDynamoDBTableWithStream with TableProps', () => {
const stack = new aws_cdk_lib_1.Stack();
const dynamoTableProps = {
partitionKey: {
name: 'table_id',
type: dynamodb.AttributeType.STRING
},
stream: dynamodb.StreamViewType.NEW_IMAGE
};
const response = defaults.buildDynamoDBTableWithStream(stack, {
dynamoTableProps
});
expect(response.tableInterface).toBeDefined();
expect(response.tableObject).toBeDefined();
const template = assertions_1.Template.fromStack(stack);
template.hasResourceProperties('AWS::DynamoDB::Table', {
KeySchema: [
{
AttributeName: "table_id",
KeyType: "HASH"
}
]
});
template.hasResourceProperties('AWS::DynamoDB::Table', {
StreamSpecification: {
StreamViewType: "NEW_IMAGE"
}
});
});
test('test buildDynamoDBTableWithStream without any arguments', () => {
const stack = new aws_cdk_lib_1.Stack();
const response = defaults.buildDynamoDBTableWithStream(stack, {});
expect(response.tableInterface).toBeDefined();
expect(response.tableObject).toBeDefined();
const template = assertions_1.Template.fromStack(stack);
template.hasResourceProperties('AWS::DynamoDB::Table', {
KeySchema: [
{
AttributeName: "id",
KeyType: "HASH"
}
]
});
template.hasResourceProperties('AWS::DynamoDB::Table', {
BillingMode: "PAY_PER_REQUEST"
});
template.hasResourceProperties('AWS::DynamoDB::Table', {
SSESpecification: {
SSEEnabled: true
}
});
template.hasResourceProperties('AWS::DynamoDB::Table', {
StreamSpecification: {
StreamViewType: "NEW_AND_OLD_IMAGES"
}
});
});
test('test buildDynamoDBTableWithStream with existingTableObj', () => {
const stack = new aws_cdk_lib_1.Stack();
const tableProps = {
partitionKey: {
name: 'table_id',
type: dynamodb.AttributeType.STRING
},
stream: dynamodb.StreamViewType.NEW_IMAGE
};
const existingTableInterface = new dynamodb.Table(stack, 'DynamoTable', tableProps);
const response = defaults.buildDynamoDBTableWithStream(stack, {
existingTableInterface
});
expect(response.tableInterface).toBeDefined();
expect(response.tableObject).not.toBeDefined();
const template = assertions_1.Template.fromStack(stack);
template.hasResourceProperties('AWS::DynamoDB::Table', {
KeySchema: [
{
AttributeName: "table_id",
KeyType: "HASH"
}
]
});
template.hasResourceProperties('AWS::DynamoDB::Table', {
StreamSpecification: {
StreamViewType: "NEW_IMAGE"
}
});
});
test('test buildDynamoDBTable with existingTableInterface', () => {
const stack = new aws_cdk_lib_1.Stack();
const tableProps = {
partitionKey: {
name: 'table_id',
type: dynamodb.AttributeType.STRING
},
stream: dynamodb.StreamViewType.NEW_IMAGE
};
const existingTableInterface = new dynamodb.Table(stack, 'DynamoTable', tableProps);
const buildDynamoDBTableResponse = defaults.buildDynamoDBTable(stack, {
existingTableInterface
});
expect(buildDynamoDBTableResponse.tableInterface).toBeDefined();
expect(buildDynamoDBTableResponse.tableObject).not.toBeDefined();
const template = assertions_1.Template.fromStack(stack);
template.hasResourceProperties('AWS::DynamoDB::Table', {
KeySchema: [
{
AttributeName: "table_id",
KeyType: "HASH"
}
]
});
template.hasResourceProperties('AWS::DynamoDB::Table', {
StreamSpecification: {
StreamViewType: "NEW_IMAGE"
}
});
});
test('test getPartitionKeyNameFromTable()', () => {
const partitionKeyName = 'testPartitionKey';
const stack = new aws_cdk_lib_1.Stack();
const defaultProps = defaults.GetDefaultTableProps({
partitionKey: {
name: 'donotuse',
type: dynamodb.AttributeType.BINARY
},
});
const inProps = {
partitionKey: {
name: partitionKeyName,
type: dynamodb.AttributeType.STRING
},
sortKey: {
name: 'sort_key',
type: dynamodb.AttributeType.STRING
}
};
const outProps = (0, utils_1.overrideProps)(defaultProps, inProps);
const newTable = new dynamodb.Table(stack, 'test-dynamo-override', outProps);
const testKeyName = (0, dynamodb_table_helper_1.getPartitionKeyNameFromTable)(newTable);
expect(testKeyName).toEqual(partitionKeyName);
});
test('Test that PointInTimeRecovery is not set when PointInTimeRecoverySpecification is provided', () => {
const defaultProps = defaults.GetDefaultTableProps({
partitionKey: {
name: 'donotuse',
type: dynamodb.AttributeType.BINARY
},
pointInTimeRecovery: true
});
expect(defaultProps.pointInTimeRecoverySpecification).toBeUndefined();
// Let's confirm the alternative as well
const moreDefaultProps = defaults.GetDefaultTableProps({
partitionKey: {
name: 'donotuse',
type: dynamodb.AttributeType.BINARY
}
});
expect(moreDefaultProps.pointInTimeRecoverySpecification).toBeDefined();
});
test('Test that PointInTimeRecovery is not set when PointInTimeRecoverySpecification is provided for table with stream', () => {
const defaultProps = defaults.GetDefaultTableWithStreamProps({
partitionKey: {
name: 'donotuse',
type: dynamodb.AttributeType.BINARY
},
pointInTimeRecovery: true
});
expect(defaultProps.pointInTimeRecoverySpecification).toBeUndefined();
// Let's confirm the alternative as well
const moreDefaultProps = defaults.GetDefaultTableWithStreamProps({
partitionKey: {
name: 'donotuse',
type: dynamodb.AttributeType.BINARY
}
});
expect(moreDefaultProps.pointInTimeRecoverySpecification).toBeDefined();
});
// ---------------------------
// Prop Tests
// ---------------------------
test('Test fail DynamoDB table check', () => {
const stack = new aws_cdk_lib_1.Stack();
const props = {
existingTableObj: new dynamodb.Table(stack, 'placeholder', defaults.GetDefaultTableProps({
partitionKey: {
name: 'donotuse',
type: dynamodb.AttributeType.BINARY
},
})),
dynamoTableProps: defaults.GetDefaultTableProps({
partitionKey: {
name: 'donotuse',
type: dynamodb.AttributeType.BINARY
},
}),
};
const app = () => {
defaults.CheckDynamoDBProps(props);
};
// Assertion
expect(app).toThrowError('Error - Either provide existingTableObj or dynamoTableProps, but not both.\n');
});
test('Test fail DynamoDB table check (for interface AND obj)', () => {
const stack = new aws_cdk_lib_1.Stack();
const props = {
existingTableInterface: new dynamodb.Table(stack, 'placeholder', defaults.GetDefaultTableProps({
partitionKey: {
name: 'donotuse',
type: dynamodb.AttributeType.BINARY
},
})),
existingTableObj: new dynamodb.Table(stack, 'placeholderobj', defaults.GetDefaultTableProps({
partitionKey: {
name: 'donotuse',
type: dynamodb.AttributeType.BINARY
},
})),
};
const app = () => {
defaults.CheckDynamoDBProps(props);
};
// Assertion
expect(app).toThrowError('Error - Either provide existingTableInterface or existingTableObj, but not both.\n');
});
test('Test fail DynamoDB pointInTimeRecoverySpecification and pointInTimeRecovery both specified', () => {
const props = {
pointInTimeRecovery: true,
pointInTimeRecoverySpecification: {
pointInTimeRecoveryEnabled: true
}
};
const app = () => {
defaults.CheckDynamoDBProps(props);
};
// Assertion
expect(app).toThrowError('Error - Either provide pointInTimeRecovery or pointInTimeRecoverySpecification, but not both.\n');
});
// ---------------------------
// New Tests
// ---------------------------
test('test pointInTimeRecoverySpecification default is set correctly', () => {
const stack = new aws_cdk_lib_1.Stack();
const dynamoTableProps = {
partitionKey: {
name: 'table_id',
type: dynamodb.AttributeType.STRING
},
};
defaults.buildDynamoDBTable(stack, {
dynamoTableProps
});
const template = assertions_1.Template.fromStack(stack);
template.hasResourceProperties('AWS::DynamoDB::Table', {
PointInTimeRecoverySpecification: {
PointInTimeRecoveryEnabled: true
}
});
});
test('test that a provided pointInTimeRecoverySpecification value is used', () => {
const stack = new aws_cdk_lib_1.Stack();
const dynamoTableProps = {
partitionKey: {
name: 'table_id',
type: dynamodb.AttributeType.STRING
},
pointInTimeRecoverySpecification: {
pointInTimeRecoveryEnabled: false
}
};
defaults.buildDynamoDBTable(stack, {
dynamoTableProps
});
const template = assertions_1.Template.fromStack(stack);
template.hasResourceProperties('AWS::DynamoDB::Table', {
PointInTimeRecoverySpecification: {
PointInTimeRecoveryEnabled: false
}
});
});
test('test that if client provides pointInTimeRecovery it is used', () => {
const stack = new aws_cdk_lib_1.Stack();
const dynamoTableProps = {
partitionKey: {
name: 'table_id',
type: dynamodb.AttributeType.STRING
},
pointInTimeRecovery: true
};
defaults.buildDynamoDBTable(stack, {
dynamoTableProps
});
const template = assertions_1.Template.fromStack(stack);
template.hasResourceProperties('AWS::DynamoDB::Table', {
// pointInTimeRecovery has no CFN equivalent, CDK converts it to PointInTimeRecoverySpecification
PointInTimeRecoverySpecification: {
PointInTimeRecoveryEnabled: true
}
});
});
test('test that if client provides pointInTimeRecovery: false will turn off feature', () => {
const stack = new aws_cdk_lib_1.Stack();
const dynamoTableProps = {
partitionKey: {
name: 'table_id',
type: dynamodb.AttributeType.STRING
},
pointInTimeRecovery: false
};
defaults.buildDynamoDBTable(stack, {
dynamoTableProps
});
const template = assertions_1.Template.fromStack(stack);
template.hasResourceProperties('AWS::DynamoDB::Table', {
// pointInTimeRecovery has no CFN equivalent, CDK converts it to PointInTimeRecoverySpecification
PointInTimeRecoverySpecification: {
PointInTimeRecoveryEnabled: false
}
});
});
test('test pointInTimeRecoverySpecification default is set correctly', () => {
const stack = new aws_cdk_lib_1.Stack();
const dynamoTableProps = {
partitionKey: {
name: 'table_id',
type: dynamodb.AttributeType.STRING
},
};
defaults.buildDynamoDBTableWithStream(stack, {
dynamoTableProps
});
const template = assertions_1.Template.fromStack(stack);
template.hasResourceProperties('AWS::DynamoDB::Table', {
PointInTimeRecoverySpecification: {
PointInTimeRecoveryEnabled: true
}
});
});
test('test that a provided pointInTimeRecoverySpecification value is used', () => {
const stack = new aws_cdk_lib_1.Stack();
const dynamoTableProps = {
partitionKey: {
name: 'table_id',
type: dynamodb.AttributeType.STRING
},
pointInTimeRecoverySpecification: {
pointInTimeRecoveryEnabled: false
}
};
defaults.buildDynamoDBTableWithStream(stack, {
dynamoTableProps
});
const template = assertions_1.Template.fromStack(stack);
template.hasResourceProperties('AWS::DynamoDB::Table', {
PointInTimeRecoverySpecification: {
PointInTimeRecoveryEnabled: false
}
});
});
test('test that if client provides pointInTimeRecovery it is used', () => {
const stack = new aws_cdk_lib_1.Stack();
const dynamoTableProps = {
partitionKey: {
name: 'table_id',
type: dynamodb.AttributeType.STRING
},
pointInTimeRecovery: true
};
defaults.buildDynamoDBTableWithStream(stack, {
dynamoTableProps
});
const template = assertions_1.Template.fromStack(stack);
template.hasResourceProperties('AWS::DynamoDB::Table', {
// pointInTimeRecovery has no CFN equivalent, CDK converts it to PointInTimeRecoverySpecification
PointInTimeRecoverySpecification: {
PointInTimeRecoveryEnabled: true
}
});
});
test('test that if client provides pointInTimeRecovery: false will turn off feature', () => {
const stack = new aws_cdk_lib_1.Stack();
const dynamoTableProps = {
partitionKey: {
name: 'table_id',
type: dynamodb.AttributeType.STRING
},
pointInTimeRecovery: false
};
defaults.buildDynamoDBTableWithStream(stack, {
dynamoTableProps
});
const template = assertions_1.Template.fromStack(stack);
template.hasResourceProperties('AWS::DynamoDB::Table', {
// pointInTimeRecovery has no CFN equivalent, CDK converts it to PointInTimeRecoverySpecification
PointInTimeRecoverySpecification: {
PointInTimeRecoveryEnabled: false
}
});
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZHluYW1vLXRhYmxlLnRlc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJkeW5hbW8tdGFibGUudGVzdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7Ozs7Ozs7O0dBV0c7O0FBRUgsNkNBQW9DO0FBQ3BDLHFEQUFxRDtBQUNyRCxxQ0FBcUM7QUFDckMsd0NBQTZDO0FBQzdDLHVEQUFrRDtBQUNsRCx3RUFBNEU7QUFFNUUsSUFBSSxDQUFDLHFDQUFxQyxFQUFFLEdBQUcsRUFBRTtJQUMvQyxNQUFNLEtBQUssR0FBRyxJQUFJLG1CQUFLLEVBQUUsQ0FBQztJQUUxQixNQUFNLFlBQVksR0FBd0IsUUFBUSxDQUFDLG9CQUFvQixDQUFDO1FBQ3RFLFlBQVksRUFBRTtZQUNaLElBQUksRUFBRSxVQUFVO1lBQ2hCLElBQUksRUFBRSxRQUFRLENBQUMsYUFBYSxDQUFDLE1BQU07U0FDcEM7S0FDRixDQUFDLENBQUM7SUFFSCxNQUFNLE9BQU8sR0FBd0I7UUFDbkMsV0FBVyxFQUFFLFFBQVEsQ0FBQyxXQUFXLENBQUMsV0FBVztRQUM3QyxZQUFZLEVBQUUsQ0FBQztRQUNmLGFBQWEsRUFBRSxDQUFDO1FBQ2hCLFlBQVksRUFBRTtZQUNaLElBQUksRUFBRSxJQUFJO1lBQ1YsSUFBSSxFQUFFLFFBQVEsQ0FBQyxhQUFhLENBQUMsTUFBTTtTQUNwQztLQUNGLENBQUM7SUFFRixNQUFNLFFBQVEsR0FBRyxJQUFBLHFCQUFhLEVBQUMsWUFBWSxFQUFFLE9BQU8sQ0FBQyxDQUFDO0lBQ3RELElBQUksUUFBUSxDQUFDLEtBQUssQ0FBQyxLQUFLLEVBQUUsc0JBQXNCLEVBQUUsUUFBUSxDQUFDLENBQUM7SUFFNUQsTUFBTSxRQUFRLEdBQUcscUJBQVEsQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDM0MsUUFBUSxDQUFDLHFCQUFxQixDQUFDLHNCQUFzQixFQUFFO1FBQ3JELFNBQVMsRUFBRTtZQUNUO2dCQUNFLGFBQWEsRUFBRSxJQUFJ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UUFDRCxtQkFBbUIsRUFBRSxLQUFLO0tBQzNCLENBQUM7SUFFRixRQUFRLENBQUMsNEJBQTRCLENBQUMsS0FBSyxFQUFFO1FBQzNDLGdCQUFnQjtLQUNqQixDQUFDLENBQUM7SUFFSCxNQUFNLFFBQVEsR0FBRyxxQkFBUSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUMzQyxRQUFRLENBQUMscUJBQXFCLENBQUMsc0JBQXNCLEVBQUU7UUFDckQsaUdBQWlHO1FBQ2pHLGdDQUFnQyxFQUFFO1lBQ2hDLDBCQUEwQixFQUFFLEtBQUs7U0FDbEM7S0FDRixDQUFDLENBQUM7QUFDTCxDQUFDLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogIENvcHlyaWdodCBBbWF6b24uY29tLCBJbmMuIG9yIGl0cyBhZmZpbGlhdGVzLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICpcbiAqICBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgXCJMaWNlbnNlXCIpLiBZb3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlXG4gKiAgd2l0aCB0aGUgTGljZW5zZS4gQSBjb3B5IG9mIHRoZSBMaWNlbnNlIGlzIGxvY2F0ZWQgYXRcbiAqXG4gKiAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuICpcbiAqICBvciBpbiB0aGUgJ2xpY2Vuc2UnIGZpbGUgYWNjb21wYW55aW5nIHRoaXMgZmlsZS4gVGhpcyBmaWxlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuICdBUyBJUycgQkFTSVMsIFdJVEhPVVQgV0FSUkFOVElFU1xuICogIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGV4cHJlc3Mgb3IgaW1wbGllZC4gU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zXG4gKiAgYW5kIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLlxuICovXG5cbmltcG9ydCB7IFN0YWNrIH0gZnJvbSAnYXdzLWNkay1saWInO1xuaW1wb3J0ICogYXMgZHluYW1vZGIgZnJvbSAnYXdzLWNkay1saWIvYXdzLWR5bmFtb2RiJztcbmltcG9ydCAqIGFzIGRlZmF1bHRzIGZyb20gJy4uL2luZGV4JztcbmltcG9ydCB7IG92ZXJyaWRlUHJvcHMgfSBmcm9tICcuLi9saWIvdXRpbHMnO1xuaW1wb3J0IHsgVGVtcGxhdGUgfSBmcm9tICdhd3MtY2RrLWxpYi9hc3NlcnRpb25zJztcbmltcG9ydCB7IGdldFBhcnRpdGlvbktleU5hbWVGcm9tVGFibGUgfSBmcm9tICcuLi9saWIvZHluYW1vZGItdGFibGUtaGVscGVyJztcblxudGVzdCgndGVzdCBUYWJsZVByb3BzIGNoYW5nZSBiaWxsaW5nIG1vZGUnLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IFN0YWNrKCk7XG5cbiAgY29uc3QgZGVmYXVsdFByb3BzOiBkeW5hbW9kYi5UYWJsZVByb3BzID0gZGVmYXVsdHMuR2V0RGVmYXVsdFRhYmxlUHJvcHMoe1xuICAgIHBhcnRpdGlvbktleToge1xuICAgICAgbmFtZTogJ2Rvbm90dXNlJyxcbiAgICAgIHR5cGU6IGR5bmFtb2RiLkF0dHJpYnV0ZVR5cGUuQklOQVJZXG4gICAgfSxcbiAgfSk7XG5cbiAgY29uc3QgaW5Qcm9wczogZHluYW1vZGIuVGFibGVQcm9wcyA9IHtcbiAgICBiaWxsaW5nTW9kZTogZHluYW1vZGIuQmlsbGluZ01vZGUuUFJPVklTSU9ORUQsXG4gICAgcmVhZENhcGFjaXR5OiAzLFxuICAgIHdyaXRlQ2FwYWNpdHk6IDMsXG4gICAgcGFydGl0aW9uS2V5OiB7XG4gICAgICBuYW1lOiAnaWQnLFxuICAgICAgdHlwZTogZHluYW1vZGIuQXR0cmlidXRlVHlwZS5TVFJJTkdcbiAgICB9XG4gIH07XG5cbiAgY29uc3Qgb3V0UHJvcHMgPSBvdmVycmlkZVByb3BzKGRlZmF1bHRQcm9wcywgaW5Qcm9wcyk7XG4gIG5ldyBkeW5hbW9kYi5UYWJsZShzdGFjaywgJ3Rlc3QtZHluYW1vLW92ZXJyaWRlJywgb3V0UHJvcHMpO1xuXG4gIGNvbnN0IHRlbXBsYXRlID0gVGVtcGxhdGUuZnJvbVN0YWNrKHN0YWNrKTtcbiAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKFwiQVdTOjpEeW5hbW9EQjo6VGFibGVcIiwge1xuICAgIEtleVNjaGVtYTogW1xuICAgICAge1xuICAgICAgICBBdHRyaWJ1dGVOYW1lOiBcImlkXCIsXG4gICAgICAgIEtleVR5cGU6IFwiSEFTSFwiXG4gICAgICB9XG4gICAgXSxcbiAgICBBdHRyaWJ1dGVEZWZpbml0aW9uczogW1xuICAgICAge1xuICAgICAgICBBdHRyaWJ1dGVOYW1lOiBcImlkXCIsXG4gICAgICAgIEF0dHJpYnV0ZVR5cGU6IFwiU1wiXG4gICAgICB9XG4gICAgXSxcbiAgICBQcm92aXNpb25lZFRocm91Z2hwdXQ6IHtcbiAgICAgIFJlYWRDYXBhY2l0eVVuaXRzOiAzLFxuICAgICAgV3JpdGVDYXBhY2l0eVVuaXRzOiAzXG4gICAgfSxcbiAgICBTU0VTcGVjaWZpY2F0aW9uOiB7XG4gICAgICBTU0VFbmFibGVkOiB0cnVlXG4gICAgfVxuICB9KTtcbn0pO1xuXG50ZXN0KCd0ZXN0IFRhYmxlUHJvcHMgb3ZlcnJpZGUgYWRkIHNvcnQga2V5JywgKCkgPT4ge1xuICBjb25zdCBzdGFjayA9IG5ldyBTdGFjaygpO1xuXG4gIGNvbnN0IGRlZmF1bHRQcm9wczogZHluYW1vZGIuVGFibGVQcm9wcyA9IGRlZmF1bHRzLkdldERlZmF1bHRUYWJsZVByb3BzKHtcbiAgICBwYXJ0aXRpb25LZXk6IHtcbiAgICAgIG5hbWU6ICdkb25vdHVzZScsXG4gICAgICB0eXBlOiBkeW5hbW9kYi5BdHRyaWJ1dGVUeXBlLkJJTkFSWVxuICAgIH0sXG4gIH0pO1xuXG4gIGNvbnN0IGluUHJvcHM6IGR5bmFtb2RiLlRhYmxlUHJvcHMgPSB7XG4gICAgcGFydGl0aW9uS2V5OiB7XG4gICAgICBuYW1lOiAnaWQnLFxuICAgICAgdHlwZTogZHluYW1vZGIuQXR0cmlidXRlVHlwZS5TVFJJTkdcbiAgICB9LFxuICAgIHNvcnRLZXk6IHtcbiAgICAgIG5hbWU6ICdzb3J0X2tleScsXG4gICAgICB0eXBlOiBkeW5hbW9kYi5BdHRyaWJ1dGVUeXBlLlNUUklOR1xuICAgIH1cbiAgfTtcblxuICBjb25zdCBvdXRQcm9wcyA9IG92ZXJyaWRlUHJvcHMoZGVmYXVsdFByb3BzLCBpblByb3BzKTtcbiAgbmV3IGR5bmFtb2RiLlRhYmxlKHN0YWNrLCAndGVzdC1keW5hbW8tb3ZlcnJpZGUnLCBvdXRQcm9wcyk7XG5cbiAgY29uc3QgdGVtcGxhdGUgPSBUZW1wbGF0ZS5mcm9tU3RhY2soc3RhY2spO1xuICB0ZW1wbGF0ZS5oYXNSZXNvdXJjZVByb3BlcnRpZXMoXCJBV1M6OkR5bmFtb0RCOjpUYWJsZVwiLCB7XG4gICAgS2V5U2NoZW1hOiBbXG4gICAgICB7XG4gICAgICAgIEF0dHJpYnV0ZU5hbWU6IFwiaWRcIixcbiAgICAgICAgS2V5VHlwZTogXCJIQVNIXCJcbiAgICAgIH0sXG4gICAgICB7XG4gICAgICAgIEF0dHJpYnV0ZU5hbWU6IFwic29ydF9rZXlcIixcbiAgICAgICAgS2V5VHlwZTogXCJSQU5HRVwiXG4gICAgICB9XG4gICAgXSxcbiAgICBBdHRyaWJ1dGVEZWZpbml0aW9uczogW1xuICAgICAge1xuICAgICAgICBBdHRyaWJ1dGVOYW1lOiBcImlkXCIsXG4gICAgICAgIEF0dHJpYnV0ZVR5cGU6IFwiU1wiXG4gICAgICB9LFxuICAgICAge1xuICAgICAgICBBdHRyaWJ1dGVOYW1lOiBcInNvcnRfa2V5XCIsXG4gICAgICAgIEF0dHJpYnV0ZVR5cGU6IFwiU1wiXG4gICAgICB9XG4gICAgXSxcbiAgICBCaWxsaW5nTW9kZTogXCJQQVlfUEVSX1JFUVVFU1RcIixcbiAgICBTU0VTcGVjaWZpY2F0aW9uOiB7XG4gICAgICBTU0VFbmFibGVkOiB0cnVlXG4gICAgfVxuICB9KTtcbn0pO1xuXG50ZXN0KCd0ZXN0IFRhYmxlV2l0aFN0cmVhbVByb3BzIG92ZXJyaWRlIHN0cmVhbSB2aWV3IHR5cGUnLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IFN0YWNrKCk7XG5cbiAgY29uc3QgZGVmYXVsdFByb3BzOiBkeW5hbW9kYi5UYWJsZVByb3BzID0gZGVmYXVsdHMuR2V0RGVmYXVsdFRhYmxlV2l0aFN0cmVhbVByb3BzKHtcbiAgICBwYXJ0aXRpb25LZXk6IHtcbiAgICAgIG5hbWU6ICdkb25vdHVzZScsXG4gICAgICB0eXBlOiBkeW5hbW9kYi5BdHRyaWJ1dGVUeXBlLkJJTkFSWVxuICAgIH0sXG4gIH0pO1xuXG4gIGNvbnN0IGluUHJvcHM6IGR5bmFtb2RiLlRhYmxlUHJvcHMgPSB7XG4gICAgcGFydGl0aW9uS2V5OiB7XG4gICAgICBuYW1lOiAnaWQnLFxuICAgICAgdHlwZTogZHluYW1vZGIuQXR0cmlidXRlVHlwZS5TVFJJTkdcbiAgICB9LFxuICAgIHN0cmVhbTogZHluYW1vZGIuU3RyZWFtVmlld1R5cGUuTkVXX0lNQUdFXG4gIH07XG5cbiAgY29uc3Qgb3V0UHJvcHMgPSBvdmVycmlkZVByb3BzKGRlZmF1bHRQcm9wcywgaW5Qcm9wcyk7XG4gIG5ldyBkeW5hbW9kYi5UYWJsZShzdGFjaywgJ3Rlc3QtZHluYW1vLW92ZXJyaWRlJywgb3V0UHJvcHMpO1xuXG4gIGNvbnN0IHRlbXBsYXRlID0gVGVtcGxhdGUuZnJvbVN0YWNrKHN0YWNrKTtcbiAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKFwiQVdTOjpEeW5hbW9EQjo6VGFibGVcIiwge1xuICAgIEtleVNjaGVtYTogW1xuICAgICAge1xuICAgICAgICBBdHRyaWJ1dGVOYW1lOiBcImlkXCIsXG4gICAgICAgIEtleVR5cGU6IFwiSEFTSFwiXG4gICAgICB9XG4gICAgXSxcbiAgICBBdHRyaWJ1dGVEZWZpbml0aW9uczogW1xuICAgICAge1xuICAgICAgICBBdHRyaWJ1dGVOYW1lOiBcImlkXCIsXG4gICAgICAgIEF0dHJpYnV0ZVR5cGU6IFwiU1wiXG4gICAgICB9XG4gICAgXSxcbiAgICBCaWxsaW5nTW9kZTogXCJQQVlfUEVSX1JFUVVFU1RcIixcbiAgICBTU0VTcGVjaWZpY2F0aW9uOiB7XG4gICAgICBTU0VFbmFibGVkOiB0cnVlXG4gICAgfSxcbiAgICBTdHJlYW1TcGVjaWZpY2F0aW9uOiB7XG4gICAgICBTdHJlYW1WaWV3VHlwZTogXCJORVdfSU1BR0VcIlxuICAgIH1cbiAgfSk7XG59KTtcblxudGVzdCgndGVzdCBidWlsZER5bmFtb0RCVGFibGUgd2l0aCBleGlzdGluZ1RhYmxlT2JqJywgKCkgPT4ge1xuICBjb25zdCBzdGFjayA9IG5ldyBTdGFjaygpO1xuXG4gIGNvbnN0IHRhYmxlUHJvcHM6IGR5bmFtb2RiLlRhYmxlUHJvcHMgPSB7XG4gICAgYmlsbGluZ01vZGU6IGR5bmFtb2RiLkJpbGxpbmdNb2RlLlBST1ZJU0lPTkVELFxuICAgIHBhcnRpdGlvbktleToge1xuICAgICAgbmFtZTogJ3RhYmxlX2lkJyxcbiAgICAgIHR5cGU6IGR5bmFtb2RiLkF0dHJpYnV0ZVR5cGUuU1RSSU5HXG4gICAgfVxuICB9O1xuXG4gIGNvbnN0IGV4aXN0aW5nVGFibGVPYmogPSBuZXcgZHluYW1vZGIuVGFibGUoc3RhY2ssICdEeW5hbW9UYWJsZScsIHRhYmxlUHJvcHMpO1xuXG4gIGNvbnN0IGJ1aWxkRHluYW1vREJUYWJsZVJlc3BvbnNlID0gZGVmYXVsdHMuYnVpbGREeW5hbW9EQlRhYmxlKHN0YWNrLCB7XG4gICAgZXhpc3RpbmdUYWJsZU9ialxuICB9KTtcblxuICBleHBlY3QoYnVpbGREeW5hbW9EQlRhYmxlUmVzcG9uc2UudGFibGVJbnRlcmZhY2UpLnRvQmVEZWZpbmVkKCk7XG4gIGV4cGVjdChidWlsZER5bmFtb0RCVGFibGVSZXNwb25zZS50YWJsZU9iamVjdCkudG9CZURlZmluZWQoKTtcblxuICBjb25zdCB0ZW1wbGF0ZSA9IFRlbXBsYXRlLmZyb21TdGFjayhzdGFjayk7XG4gIHRlbXBsYXRlLmhhc1Jlc291cmNlUHJvcGVydGllcygnQVdTOjpEeW5hbW9EQjo6VGFibGUnLCB7XG4gICAgS2V5U2NoZW1hOiBbXG4gICAgICB7XG4gICAgICAgIEF0dHJpYnV0ZU5hbWU6IFwidGFibGVfaWRcIixcbiAgICAgICAgS2V5VHlwZTogXCJIQVNIXCJcbiAgICAgIH1cbiAgICBdXG4gIH0pO1xuXG4gIHRlbXBsYXRlLmhhc1Jlc291cmNlUHJvcGVydGllcygnQVdTOjpEeW5hbW9EQjo6VGFibGUnLCB7XG4gICAgUHJvdmlzaW9uZWRUaHJvdWdocHV0OiB7XG4gICAgICBSZWFkQ2FwYWNpdHlVbml0czogNSxcbiAgICAgIFdyaXRlQ2FwYWNpdHlVbml0czogNVxuICAgIH1cbiAgfSk7XG59KTtcblxudGVzdCgndGVzdCBidWlsZER5bmFtb0RCVGFibGUgd2l0aG91dCBhbnkgYXJndW1lbnRzJywgKCkgPT4ge1xuICBjb25zdCBzdGFjayA9IG5ldyBTdGFjaygpO1xuXG4gIGNvbnN0IGJ1aWxkRHluYW1vREJUYWJsZV