aws-cdk
Version:
CDK Toolkit, the command line tool for CDK apps
766 lines • 97.1 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const client_lambda_1 = require("@aws-sdk/client-lambda");
const setup = require("./hotswap-test-setup");
const common_1 = require("../../../lib/api/hotswap/common");
const s3_bucket_deployments_1 = require("../../../lib/api/hotswap/s3-bucket-deployments");
const mock_sdk_1 = require("../../util/mock-sdk");
const silent_1 = require("../../util/silent");
let hotswapMockSdkProvider;
const payloadWithoutCustomResProps = {
RequestType: 'Update',
ResponseURL: s3_bucket_deployments_1.REQUIRED_BY_CFN,
PhysicalResourceId: s3_bucket_deployments_1.REQUIRED_BY_CFN,
StackId: s3_bucket_deployments_1.REQUIRED_BY_CFN,
RequestId: s3_bucket_deployments_1.REQUIRED_BY_CFN,
LogicalResourceId: s3_bucket_deployments_1.REQUIRED_BY_CFN,
};
beforeEach(() => {
hotswapMockSdkProvider = setup.setupHotswapTests();
});
describe.each([common_1.HotswapMode.FALL_BACK, common_1.HotswapMode.HOTSWAP_ONLY])('%p mode', (hotswapMode) => {
(0, silent_1.silentTest)('calls the lambdaInvoke() API when it receives only an asset difference in an S3 bucket deployment and evaluates CFN expressions in S3 Deployment Properties', async () => {
// GIVEN
setup.setCurrentCfnStackTemplate({
Resources: {
S3Deployment: {
Type: 'Custom::CDKBucketDeployment',
Properties: {
ServiceToken: 'a-lambda-arn',
SourceBucketNames: ['src-bucket'],
SourceObjectKeys: ['src-key-old'],
DestinationBucketName: 'dest-bucket',
DestinationBucketKeyPrefix: 'my-key/some-old-prefix',
},
},
},
});
const cdkStackArtifact = setup.cdkStackArtifactOf({
template: {
Resources: {
S3Deployment: {
Type: 'Custom::CDKBucketDeployment',
Properties: {
ServiceToken: 'a-lambda-arn',
SourceBucketNames: ['src-bucket'],
SourceObjectKeys: {
'Fn::Split': ['-', 'key1-key2-key3'],
},
DestinationBucketName: 'dest-bucket',
DestinationBucketKeyPrefix: 'my-key/some-new-prefix',
},
},
},
},
});
// WHEN
const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(hotswapMode, cdkStackArtifact);
// THEN
expect(deployStackResult).not.toBeUndefined();
expect(mock_sdk_1.mockLambdaClient).toHaveReceivedCommandWith(client_lambda_1.InvokeCommand, {
FunctionName: 'a-lambda-arn',
Payload: JSON.stringify({
...payloadWithoutCustomResProps,
ResourceProperties: {
SourceBucketNames: ['src-bucket'],
SourceObjectKeys: ['key1', 'key2', 'key3'],
DestinationBucketName: 'dest-bucket',
DestinationBucketKeyPrefix: 'my-key/some-new-prefix',
},
}),
});
});
(0, silent_1.silentTest)('does not call the invoke() API when a resource with type that is not Custom::CDKBucketDeployment but has the same properties is changed', async () => {
// GIVEN
setup.setCurrentCfnStackTemplate({
Resources: {
S3Deployment: {
Type: 'Custom::NotCDKBucketDeployment',
Properties: {
SourceObjectKeys: ['src-key-old'],
},
},
},
});
const cdkStackArtifact = setup.cdkStackArtifactOf({
template: {
Resources: {
S3Deployment: {
Type: 'Custom::NotCDKBucketDeployment',
Properties: {
SourceObjectKeys: ['src-key-new'],
},
},
},
},
});
if (hotswapMode === common_1.HotswapMode.FALL_BACK) {
// WHEN
const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(hotswapMode, cdkStackArtifact);
// THEN
expect(deployStackResult).toBeUndefined();
expect(mock_sdk_1.mockLambdaClient).not.toHaveReceivedCommand(client_lambda_1.InvokeCommand);
}
else if (hotswapMode === common_1.HotswapMode.HOTSWAP_ONLY) {
// WHEN
const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(hotswapMode, cdkStackArtifact);
// THEN
expect(deployStackResult).not.toBeUndefined();
expect(deployStackResult?.noOp).toEqual(true);
expect(mock_sdk_1.mockLambdaClient).not.toHaveReceivedCommand(client_lambda_1.InvokeCommand);
}
});
(0, silent_1.silentTest)('does not call the invokeLambda() api if the updated Policy has no Roles in CLASSIC mode but does in HOTSWAP_ONLY mode', async () => {
// GIVEN
setup.setCurrentCfnStackTemplate({
Parameters: {
WebsiteBucketParamOld: { Type: 'String' },
WebsiteBucketParamNew: { Type: 'String' },
},
Resources: {
S3Deployment: {
Type: 'Custom::CDKBucketDeployment',
Properties: {
ServiceToken: 'a-lambda-arn',
SourceObjectKeys: ['src-key-old'],
SourceBucketNames: ['src-bucket'],
DestinationBucketName: 'dest-bucket',
},
},
Policy: {
Type: 'AWS::IAM::Policy',
Properties: {
PolicyName: 'my-policy',
PolicyDocument: {
Statement: [
{
Action: ['s3:GetObject*'],
Effect: 'Allow',
Resource: {
Ref: 'WebsiteBucketParamOld',
},
},
],
},
},
},
},
});
const cdkStackArtifact = setup.cdkStackArtifactOf({
template: {
Parameters: {
WebsiteBucketParamOld: { Type: 'String' },
WebsiteBucketParamNew: { Type: 'String' },
},
Resources: {
S3Deployment: {
Type: 'Custom::CDKBucketDeployment',
Properties: {
ServiceToken: 'a-lambda-arn',
SourceObjectKeys: ['src-key-new'],
SourceBucketNames: ['src-bucket'],
DestinationBucketName: 'dest-bucket',
},
},
Policy: {
Type: 'AWS::IAM::Policy',
Properties: {
PolicyName: 'my-policy',
PolicyDocument: {
Statement: [
{
Action: ['s3:GetObject*'],
Effect: 'Allow',
Resource: {
Ref: 'WebsiteBucketParamNew',
},
},
],
},
},
},
},
},
});
if (hotswapMode === common_1.HotswapMode.FALL_BACK) {
// WHEN
const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(hotswapMode, cdkStackArtifact);
// THEN
expect(deployStackResult).toBeUndefined();
expect(mock_sdk_1.mockLambdaClient).not.toHaveReceivedCommand(client_lambda_1.InvokeCommand);
}
else if (hotswapMode === common_1.HotswapMode.HOTSWAP_ONLY) {
// WHEN
const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(hotswapMode, cdkStackArtifact);
// THEN
expect(deployStackResult).not.toBeUndefined();
expect(mock_sdk_1.mockLambdaClient).toHaveReceivedCommandWith(client_lambda_1.InvokeCommand, {
FunctionName: 'a-lambda-arn',
Payload: JSON.stringify({
...payloadWithoutCustomResProps,
ResourceProperties: {
SourceObjectKeys: ['src-key-new'],
SourceBucketNames: ['src-bucket'],
DestinationBucketName: 'dest-bucket',
},
}),
});
}
});
(0, silent_1.silentTest)('throws an error when the serviceToken fails evaluation in the template', async () => {
// GIVEN
setup.setCurrentCfnStackTemplate({
Resources: {
S3Deployment: {
Type: 'Custom::CDKBucketDeployment',
Properties: {
ServiceToken: {
Ref: 'BadLamba',
},
SourceBucketNames: ['src-bucket'],
SourceObjectKeys: ['src-key-old'],
DestinationBucketName: 'dest-bucket',
},
},
},
});
const cdkStackArtifact = setup.cdkStackArtifactOf({
template: {
Resources: {
S3Deployment: {
Type: 'Custom::CDKBucketDeployment',
Properties: {
ServiceToken: {
Ref: 'BadLamba',
},
SourceBucketNames: ['src-bucket'],
SourceObjectKeys: ['src-key-new'],
DestinationBucketName: 'dest-bucket',
},
},
},
},
});
// WHEN
await expect(() => hotswapMockSdkProvider.tryHotswapDeployment(hotswapMode, cdkStackArtifact)).rejects.toThrow(/Parameter or resource 'BadLamba' could not be found for evaluation/);
expect(mock_sdk_1.mockLambdaClient).not.toHaveReceivedCommand(client_lambda_1.InvokeCommand);
});
describe('old-style synthesis', () => {
const parameters = {
WebsiteBucketParamOld: { Type: 'String' },
WebsiteBucketParamNew: { Type: 'String' },
DifferentBucketParamNew: { Type: 'String' },
};
const serviceRole = {
Type: 'AWS::IAM::Role',
Properties: {
AssumeRolePolicyDocument: {
Statement: [
{
Action: 'sts:AssumeRole',
Effect: 'Allow',
Principal: {
Service: 'lambda.amazonaws.com',
},
},
],
Version: '2012-10-17',
},
},
};
const policyOld = {
Type: 'AWS::IAM::Policy',
Properties: {
PolicyName: 'my-policy-old',
Roles: [{ Ref: 'ServiceRole' }],
PolicyDocument: {
Statement: [
{
Action: ['s3:GetObject*'],
Effect: 'Allow',
Resource: {
Ref: 'WebsiteBucketParamOld',
},
},
],
},
},
};
const policyNew = {
Type: 'AWS::IAM::Policy',
Properties: {
PolicyName: 'my-policy-new',
Roles: [{ Ref: 'ServiceRole' }],
PolicyDocument: {
Statement: [
{
Action: ['s3:GetObject*'],
Effect: 'Allow',
Resource: {
Ref: 'WebsiteBucketParamNew',
},
},
],
},
},
};
const policy2Old = {
Type: 'AWS::IAM::Policy',
Properties: {
PolicyName: 'my-policy-old-2',
Roles: [{ Ref: 'ServiceRole' }],
PolicyDocument: {
Statement: [
{
Action: ['s3:GetObject*'],
Effect: 'Allow',
Resource: {
Ref: 'WebsiteBucketParamOld',
},
},
],
},
},
};
const policy2New = {
Type: 'AWS::IAM::Policy',
Properties: {
PolicyName: 'my-policy-new-2',
Roles: [{ Ref: 'ServiceRole2' }],
PolicyDocument: {
Statement: [
{
Action: ['s3:GetObject*'],
Effect: 'Allow',
Resource: {
Ref: 'DifferentBucketParamOld',
},
},
],
},
},
};
const deploymentLambda = {
Type: 'AWS::Lambda::Function',
Role: {
'Fn::GetAtt': ['ServiceRole', 'Arn'],
},
};
const s3DeploymentOld = {
Type: 'Custom::CDKBucketDeployment',
Properties: {
ServiceToken: {
'Fn::GetAtt': ['S3DeploymentLambda', 'Arn'],
},
SourceBucketNames: ['src-bucket-old'],
SourceObjectKeys: ['src-key-old'],
DestinationBucketName: 'WebsiteBucketOld',
},
};
const s3DeploymentNew = {
Type: 'Custom::CDKBucketDeployment',
Properties: {
ServiceToken: {
'Fn::GetAtt': ['S3DeploymentLambda', 'Arn'],
},
SourceBucketNames: ['src-bucket-new'],
SourceObjectKeys: ['src-key-new'],
DestinationBucketName: 'WebsiteBucketNew',
},
};
beforeEach(() => {
setup.pushStackResourceSummaries(setup.stackSummaryOf('S3DeploymentLambda', 'AWS::Lambda::Function', 'my-deployment-lambda'), setup.stackSummaryOf('ServiceRole', 'AWS::IAM::Role', 'my-service-role'));
});
(0, silent_1.silentTest)('calls the lambdaInvoke() API when it receives an asset difference in an S3 bucket deployment and an IAM Policy difference using old-style synthesis', async () => {
// GIVEN
setup.setCurrentCfnStackTemplate({
Resources: {
Parameters: parameters,
ServiceRole: serviceRole,
Policy: policyOld,
S3DeploymentLambda: deploymentLambda,
S3Deployment: s3DeploymentOld,
},
});
const cdkStackArtifact = setup.cdkStackArtifactOf({
template: {
Resources: {
Parameters: parameters,
ServiceRole: serviceRole,
Policy: policyNew,
S3DeploymentLambda: deploymentLambda,
S3Deployment: s3DeploymentNew,
},
},
});
// WHEN
const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(hotswapMode, cdkStackArtifact, {
WebsiteBucketParamOld: 'WebsiteBucketOld',
WebsiteBucketParamNew: 'WebsiteBucketNew',
});
// THEN
expect(deployStackResult).not.toBeUndefined();
expect(mock_sdk_1.mockLambdaClient).toHaveReceivedCommandWith(client_lambda_1.InvokeCommand, {
FunctionName: 'arn:swa:lambda:here:123456789012:function:my-deployment-lambda',
Payload: JSON.stringify({
...payloadWithoutCustomResProps,
ResourceProperties: {
SourceBucketNames: ['src-bucket-new'],
SourceObjectKeys: ['src-key-new'],
DestinationBucketName: 'WebsiteBucketNew',
},
}),
});
});
(0, silent_1.silentTest)(`does not call the lambdaInvoke() API when the difference in the S3 deployment is referred to in one IAM policy change but not another
in CLASSIC mode but does in HOTSWAP_ONLY`, async () => {
// GIVEN
setup.setCurrentCfnStackTemplate({
Resources: {
ServiceRole: serviceRole,
Policy1: policyOld,
Policy2: policy2Old,
S3DeploymentLambda: deploymentLambda,
S3Deployment: s3DeploymentOld,
},
});
const cdkStackArtifact = setup.cdkStackArtifactOf({
template: {
Resources: {
ServiceRole: serviceRole,
Policy1: policyNew,
Policy2: {
Properties: {
Roles: [{ Ref: 'ServiceRole' }, 'different-role'],
PolicyDocument: {
Statement: [
{
Action: ['s3:GetObject*'],
Effect: 'Allow',
Resource: {
'Fn::GetAtt': ['DifferentBucketNew', 'Arn'],
},
},
],
},
},
},
S3DeploymentLambda: deploymentLambda,
S3Deployment: s3DeploymentNew,
},
},
});
if (hotswapMode === common_1.HotswapMode.FALL_BACK) {
// WHEN
const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(hotswapMode, cdkStackArtifact);
// THEN
expect(deployStackResult).toBeUndefined();
expect(mock_sdk_1.mockLambdaClient).not.toHaveReceivedCommand(client_lambda_1.InvokeCommand);
}
else if (hotswapMode === common_1.HotswapMode.HOTSWAP_ONLY) {
// WHEN
const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(hotswapMode, cdkStackArtifact);
// THEN
expect(deployStackResult).not.toBeUndefined();
expect(mock_sdk_1.mockLambdaClient).toHaveReceivedCommandWith(client_lambda_1.InvokeCommand, {
FunctionName: 'arn:swa:lambda:here:123456789012:function:my-deployment-lambda',
Payload: JSON.stringify({
...payloadWithoutCustomResProps,
ResourceProperties: {
SourceBucketNames: ['src-bucket-new'],
SourceObjectKeys: ['src-key-new'],
DestinationBucketName: 'WebsiteBucketNew',
},
}),
});
}
});
(0, silent_1.silentTest)(`does not call the lambdaInvoke() API when the lambda that references the role is referred to by something other than an S3 deployment
in CLASSIC mode but does in HOTSWAP_ONLY mode`, async () => {
// GIVEN
setup.setCurrentCfnStackTemplate({
Resources: {
ServiceRole: serviceRole,
Policy: policyOld,
S3DeploymentLambda: deploymentLambda,
S3Deployment: s3DeploymentOld,
Endpoint: {
Type: 'AWS::Lambda::Permission',
Properties: {
Action: 'lambda:InvokeFunction',
FunctionName: {
'Fn::GetAtt': ['S3DeploymentLambda', 'Arn'],
},
Principal: 'apigateway.amazonaws.com',
},
},
},
});
const cdkStackArtifact = setup.cdkStackArtifactOf({
template: {
Resources: {
ServiceRole: serviceRole,
Policy: policyNew,
S3DeploymentLambda: deploymentLambda,
S3Deployment: s3DeploymentNew,
Endpoint: {
Type: 'AWS::Lambda::Permission',
Properties: {
Action: 'lambda:InvokeFunction',
FunctionName: {
'Fn::GetAtt': ['S3DeploymentLambda', 'Arn'],
},
Principal: 'apigateway.amazonaws.com',
},
},
},
},
});
if (hotswapMode === common_1.HotswapMode.FALL_BACK) {
// WHEN
const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(hotswapMode, cdkStackArtifact);
// THEN
expect(deployStackResult).toBeUndefined();
expect(mock_sdk_1.mockLambdaClient).not.toHaveReceivedCommand(client_lambda_1.InvokeCommand);
}
else if (hotswapMode === common_1.HotswapMode.HOTSWAP_ONLY) {
// WHEN
const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(hotswapMode, cdkStackArtifact);
// THEN
expect(deployStackResult).not.toBeUndefined();
expect(mock_sdk_1.mockLambdaClient).toHaveReceivedCommandWith(client_lambda_1.InvokeCommand, {
FunctionName: 'arn:swa:lambda:here:123456789012:function:my-deployment-lambda',
Payload: JSON.stringify({
...payloadWithoutCustomResProps,
ResourceProperties: {
SourceBucketNames: ['src-bucket-new'],
SourceObjectKeys: ['src-key-new'],
DestinationBucketName: 'WebsiteBucketNew',
},
}),
});
}
});
(0, silent_1.silentTest)('calls the lambdaInvoke() API when it receives an asset difference in two S3 bucket deployments and IAM Policy differences using old-style synthesis', async () => {
// GIVEN
const deploymentLambda2Old = {
Type: 'AWS::Lambda::Function',
Role: {
'Fn::GetAtt': ['ServiceRole', 'Arn'],
},
};
const deploymentLambda2New = {
Type: 'AWS::Lambda::Function',
Role: {
'Fn::GetAtt': ['ServiceRole2', 'Arn'],
},
};
const s3Deployment2Old = {
Type: 'Custom::CDKBucketDeployment',
Properties: {
ServiceToken: {
'Fn::GetAtt': ['S3DeploymentLambda2', 'Arn'],
},
SourceBucketNames: ['src-bucket-old'],
SourceObjectKeys: ['src-key-old'],
DestinationBucketName: 'DifferentBucketOld',
},
};
const s3Deployment2New = {
Type: 'Custom::CDKBucketDeployment',
Properties: {
ServiceToken: {
'Fn::GetAtt': ['S3DeploymentLambda2', 'Arn'],
},
SourceBucketNames: ['src-bucket-new'],
SourceObjectKeys: ['src-key-new'],
DestinationBucketName: 'DifferentBucketNew',
},
};
setup.setCurrentCfnStackTemplate({
Resources: {
ServiceRole: serviceRole,
ServiceRole2: serviceRole,
Policy1: policyOld,
Policy2: policy2Old,
S3DeploymentLambda: deploymentLambda,
S3DeploymentLambda2: deploymentLambda2Old,
S3Deployment: s3DeploymentOld,
S3Deployment2: s3Deployment2Old,
},
});
const cdkStackArtifact = setup.cdkStackArtifactOf({
template: {
Resources: {
Parameters: parameters,
ServiceRole: serviceRole,
ServiceRole2: serviceRole,
Policy1: policyNew,
Policy2: policy2New,
S3DeploymentLambda: deploymentLambda,
S3DeploymentLambda2: deploymentLambda2New,
S3Deployment: s3DeploymentNew,
S3Deployment2: s3Deployment2New,
},
},
});
// WHEN
setup.pushStackResourceSummaries(setup.stackSummaryOf('S3DeploymentLambda2', 'AWS::Lambda::Function', 'my-deployment-lambda-2'), setup.stackSummaryOf('ServiceRole2', 'AWS::IAM::Role', 'my-service-role-2'));
const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(hotswapMode, cdkStackArtifact, {
WebsiteBucketParamOld: 'WebsiteBucketOld',
WebsiteBucketParamNew: 'WebsiteBucketNew',
DifferentBucketParamNew: 'WebsiteBucketNew',
});
// THEN
expect(deployStackResult).not.toBeUndefined();
expect(mock_sdk_1.mockLambdaClient).toHaveReceivedCommandWith(client_lambda_1.InvokeCommand, {
FunctionName: 'arn:swa:lambda:here:123456789012:function:my-deployment-lambda',
Payload: JSON.stringify({
...payloadWithoutCustomResProps,
ResourceProperties: {
SourceBucketNames: ['src-bucket-new'],
SourceObjectKeys: ['src-key-new'],
DestinationBucketName: 'WebsiteBucketNew',
},
}),
});
expect(mock_sdk_1.mockLambdaClient).toHaveReceivedCommandWith(client_lambda_1.InvokeCommand, {
FunctionName: 'arn:swa:lambda:here:123456789012:function:my-deployment-lambda-2',
Payload: JSON.stringify({
...payloadWithoutCustomResProps,
ResourceProperties: {
SourceBucketNames: ['src-bucket-new'],
SourceObjectKeys: ['src-key-new'],
DestinationBucketName: 'DifferentBucketNew',
},
}),
});
});
(0, silent_1.silentTest)(`does not call the lambdaInvoke() API when it receives an asset difference in an S3 bucket deployment that references two different policies
in CLASSIC mode but does in HOTSWAP_ONLY mode`, async () => {
// GIVEN
setup.setCurrentCfnStackTemplate({
Resources: {
ServiceRole: serviceRole,
Policy1: policyOld,
Policy2: policy2Old,
S3DeploymentLambda: deploymentLambda,
S3Deployment: s3DeploymentOld,
},
});
const cdkStackArtifact = setup.cdkStackArtifactOf({
template: {
Resources: {
ServiceRole: serviceRole,
Policy1: policyNew,
Policy2: {
Properties: {
Roles: [{ Ref: 'ServiceRole' }],
PolicyDocument: {
Statement: [
{
Action: ['s3:GetObject*'],
Effect: 'Allow',
Resource: {
'Fn::GetAtt': ['DifferentBucketNew', 'Arn'],
},
},
],
},
},
},
S3DeploymentLambda: deploymentLambda,
S3Deployment: s3DeploymentNew,
},
},
});
if (hotswapMode === common_1.HotswapMode.FALL_BACK) {
// WHEN
const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(hotswapMode, cdkStackArtifact);
// THEN
expect(deployStackResult).toBeUndefined();
expect(mock_sdk_1.mockLambdaClient).not.toHaveReceivedCommand(client_lambda_1.InvokeCommand);
}
else if (hotswapMode === common_1.HotswapMode.HOTSWAP_ONLY) {
// WHEN
const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(hotswapMode, cdkStackArtifact);
// THEN
expect(deployStackResult).not.toBeUndefined();
expect(mock_sdk_1.mockLambdaClient).toHaveReceivedCommandWith(client_lambda_1.InvokeCommand, {
FunctionName: 'arn:swa:lambda:here:123456789012:function:my-deployment-lambda',
Payload: JSON.stringify({
...payloadWithoutCustomResProps,
ResourceProperties: {
SourceBucketNames: ['src-bucket-new'],
SourceObjectKeys: ['src-key-new'],
DestinationBucketName: 'WebsiteBucketNew',
},
}),
});
}
});
(0, silent_1.silentTest)(`does not call the lambdaInvoke() API when a policy is referenced by a resource that is not an S3 deployment
in CLASSIC mode but does in HOTSWAP_ONLY mode`, async () => {
// GIVEN
setup.setCurrentCfnStackTemplate({
Resources: {
ServiceRole: serviceRole,
Policy1: policyOld,
S3DeploymentLambda: deploymentLambda,
S3Deployment: s3DeploymentOld,
NotADeployment: {
Type: 'AWS::Not::S3Deployment',
Properties: {
Prop: {
Ref: 'ServiceRole',
},
},
},
},
});
const cdkStackArtifact = setup.cdkStackArtifactOf({
template: {
Resources: {
ServiceRole: serviceRole,
Policy1: policyNew,
S3DeploymentLambda: deploymentLambda,
S3Deployment: s3DeploymentNew,
NotADeployment: {
Type: 'AWS::Not::S3Deployment',
Properties: {
Prop: {
Ref: 'ServiceRole',
},
},
},
},
},
});
if (hotswapMode === common_1.HotswapMode.FALL_BACK) {
// WHEN
const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(hotswapMode, cdkStackArtifact);
// THEN
expect(deployStackResult).toBeUndefined();
expect(mock_sdk_1.mockLambdaClient).not.toHaveReceivedCommand(client_lambda_1.InvokeCommand);
}
else if (hotswapMode === common_1.HotswapMode.HOTSWAP_ONLY) {
// WHEN
const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(hotswapMode, cdkStackArtifact);
// THEN
expect(deployStackResult).not.toBeUndefined();
expect(mock_sdk_1.mockLambdaClient).toHaveReceivedCommandWith(client_lambda_1.InvokeCommand, {
FunctionName: 'arn:swa:lambda:here:123456789012:function:my-deployment-lambda',
Payload: JSON.stringify({
...payloadWithoutCustomResProps,
ResourceProperties: {
SourceBucketNames: ['src-bucket-new'],
SourceObjectKeys: ['src-key-new'],
DestinationBucketName: 'WebsiteBucketNew',
},
}),
});
}
});
});
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiczMtYnVja2V0LWhvdHN3YXAtZGVwbG95bWVudHMudGVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInMzLWJ1Y2tldC1ob3Rzd2FwLWRlcGxveW1lbnRzLnRlc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSwwREFBdUQ7QUFDdkQsOENBQThDO0FBQzlDLDREQUE4RDtBQUM5RCwwRkFBaUY7QUFDakYsa0RBQXVEO0FBQ3ZELDhDQUErQztBQUUvQyxJQUFJLHNCQUFvRCxDQUFDO0FBRXpELE1BQU0sNEJBQTRCLEdBQUc7SUFDbkMsV0FBVyxFQUFFLFFBQVE7SUFDckIsV0FBVyxFQUFFLHVDQUFlO0lBQzVCLGtCQUFrQixFQUFFLHVDQUFlO0lBQ25DLE9BQU8sRUFBRSx1Q0FBZTtJQUN4QixTQUFTLEVBQUUsdUNBQWU7SUFDMUIsaUJBQWlCLEVBQUUsdUNBQWU7Q0FDbkMsQ0FBQztBQUVGLFVBQVUsQ0FBQyxHQUFHLEVBQUU7SUFDZCxzQkFBc0IsR0FBRyxLQUFLLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztBQUNyRCxDQUFDLENBQUMsQ0FBQztBQUVILFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQyxvQkFBVyxDQUFDLFNBQVMsRUFBRSxvQkFBVyxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUMsU0FBUyxFQUFFLENBQUMsV0FBVyxFQUFFLEVBQUU7SUFDMUYsSUFBQSxtQkFBVSxFQUNSLDZKQUE2SixFQUM3SixLQUFLLElBQUksRUFBRTtRQUNULFFBQVE7UUFDUixLQUFLLENBQUMsMEJBQTBCLENBQUM7WUFDL0IsU0FBUyxFQUFFO2dCQUNULFlBQVksRUFBRTtvQkFDWixJQUFJLEVBQUUsNkJBQTZCO29CQUNuQyxVQUFVLEVBQUU7d0JBQ1YsWUFBWSxFQUFFLGNBQWM7d0JBQzVCLGlCQUFpQixFQUFFLENBQUMsWUFBWSxDQUFDO3dCQUNqQyxnQkFBZ0IsRUFBRSxDQUFDLGFBQWEsQ0FBQzt3QkFDakMscUJBQXFCLEVBQUUsYUFBYTt3QkFD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