@aws-cdk/core
Version:
AWS Cloud Development Kit Core Library
689 lines • 104 kB
JavaScript
"use strict";
const cxapi = require("@aws-cdk/cx-api");
const lib_1 = require("../lib");
const intrinsic_1 = require("../lib/private/intrinsic");
const util_1 = require("../lib/util");
const util_2 = require("./util");
class StackWithPostProcessor extends lib_1.Stack {
// ...
_toCloudFormation() {
const template = super._toCloudFormation();
// manipulate template (e.g. rename "Key" to "key")
template.Resources.myResource.Properties.Environment.key =
template.Resources.myResource.Properties.Environment.Key;
delete template.Resources.myResource.Properties.Environment.Key;
return template;
}
}
module.exports = {
'a stack can be serialized into a CloudFormation template, initially it\'s empty'(test) {
const stack = new lib_1.Stack();
test.deepEqual(util_2.toCloudFormation(stack), {});
test.done();
},
'stack objects have some template-level propeties, such as Description, Version, Transform'(test) {
const stack = new lib_1.Stack();
stack.templateOptions.templateFormatVersion = 'MyTemplateVersion';
stack.templateOptions.description = 'This is my description';
stack.templateOptions.transforms = ['SAMy'];
test.deepEqual(util_2.toCloudFormation(stack), {
Description: 'This is my description',
AWSTemplateFormatVersion: 'MyTemplateVersion',
Transform: 'SAMy'
});
test.done();
},
'Stack.isStack indicates that a construct is a stack'(test) {
const stack = new lib_1.Stack();
const c = new lib_1.Construct(stack, 'Construct');
test.ok(lib_1.Stack.isStack(stack));
test.ok(!lib_1.Stack.isStack(c));
test.done();
},
'stack.id is not included in the logical identities of resources within it'(test) {
const stack = new lib_1.Stack(undefined, 'MyStack');
new lib_1.CfnResource(stack, 'MyResource', { type: 'MyResourceType' });
test.deepEqual(util_2.toCloudFormation(stack), { Resources: { MyResource: { Type: 'MyResourceType' } } });
test.done();
},
'stack.templateOptions can be used to set template-level options'(test) {
const stack = new lib_1.Stack();
stack.templateOptions.description = 'StackDescription';
stack.templateOptions.templateFormatVersion = 'TemplateVersion';
stack.templateOptions.transform = 'DeprecatedField';
stack.templateOptions.transforms = ['Transform'];
stack.templateOptions.metadata = {
MetadataKey: 'MetadataValue'
};
test.deepEqual(util_2.toCloudFormation(stack), {
Description: 'StackDescription',
Transform: ['Transform', 'DeprecatedField'],
AWSTemplateFormatVersion: 'TemplateVersion',
Metadata: { MetadataKey: 'MetadataValue' }
});
test.done();
},
'stack.templateOptions.transforms removes duplicate values'(test) {
const stack = new lib_1.Stack();
stack.templateOptions.transforms = ['A', 'B', 'C', 'A'];
test.deepEqual(util_2.toCloudFormation(stack), {
Transform: ['A', 'B', 'C']
});
test.done();
},
'stack.addTransform() adds a transform'(test) {
const stack = new lib_1.Stack();
stack.addTransform('A');
stack.addTransform('B');
stack.addTransform('C');
test.deepEqual(util_2.toCloudFormation(stack), {
Transform: ['A', 'B', 'C']
});
test.done();
},
// This approach will only apply to TypeScript code, but at least it's a temporary
// workaround for people running into issues caused by SDK-3003.
// We should come up with a proper solution that involved jsii callbacks (when they exist)
// so this can be implemented by jsii languages as well.
'Overriding `Stack._toCloudFormation` allows arbitrary post-processing of the generated template during synthesis'(test) {
const stack = new StackWithPostProcessor();
new lib_1.CfnResource(stack, 'myResource', {
type: 'AWS::MyResource',
properties: {
MyProp1: 'hello',
MyProp2: 'howdy',
Environment: {
Key: 'value'
}
}
});
test.deepEqual(stack._toCloudFormation(), { Resources: { myResource: { Type: 'AWS::MyResource',
Properties: { MyProp1: 'hello',
MyProp2: 'howdy',
Environment: { key: 'value' } } } } });
test.done();
},
'Stack.getByPath can be used to find any CloudFormation element (Parameter, Output, etc)'(test) {
const stack = new lib_1.Stack();
const p = new lib_1.CfnParameter(stack, 'MyParam', { type: 'String' });
const o = new lib_1.CfnOutput(stack, 'MyOutput', { value: 'boom' });
const c = new lib_1.CfnCondition(stack, 'MyCondition');
test.equal(stack.node.findChild(p.node.path), p);
test.equal(stack.node.findChild(o.node.path), o);
test.equal(stack.node.findChild(c.node.path), c);
test.done();
},
'Stack names can have hyphens in them'(test) {
const root = new lib_1.App();
new lib_1.Stack(root, 'Hello-World');
// Did not throw
test.done();
},
'Stacks can have a description given to them'(test) {
const stack = new lib_1.Stack(new lib_1.App(), 'MyStack', { description: 'My stack, hands off!' });
const output = util_2.toCloudFormation(stack);
test.equal(output.Description, 'My stack, hands off!');
test.done();
},
'Stack descriptions have a limited length'(test) {
const desc = `Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua. Consequat interdum varius sit amet mattis vulputate
enim nulla aliquet. At imperdiet dui accumsan sit amet nulla facilisi morbi. Eget lorem dolor sed
viverra ipsum. Diam volutpat commodo sed egestas egestas. Sit amet porttitor eget dolor morbi non.
Lorem dolor sed viverra ipsum. Id porta nibh venenatis cras sed felis. Augue interdum velit euismod
in pellentesque. Suscipit adipiscing bibendum est ultricies integer quis. Condimentum id venenatis a
condimentum vitae sapien pellentesque habitant morbi. Congue mauris rhoncus aenean vel elit scelerisque
mauris pellentesque pulvinar.
Faucibus purus in massa tempor nec. Risus viverra adipiscing at in. Integer feugiat scelerisque varius
morbi. Malesuada nunc vel risus commodo viverra maecenas accumsan lacus. Vulputate sapien nec sagittis
aliquam malesuada bibendum arcu vitae. Augue neque gravida in fermentum et sollicitudin ac orci phasellus.
Ultrices tincidunt arcu non sodales neque sodales.`;
test.throws(() => new lib_1.Stack(new lib_1.App(), 'MyStack', { description: desc }));
test.done();
},
'Include should support non-hash top-level template elements like "Description"'(test) {
const stack = new lib_1.Stack();
const template = {
Description: 'hello, world'
};
new lib_1.CfnInclude(stack, 'Include', { template });
const output = util_2.toCloudFormation(stack);
test.equal(typeof output.Description, 'string');
test.done();
},
'Pseudo values attached to one stack can be referenced in another stack'(test) {
// GIVEN
const app = new lib_1.App();
const stack1 = new lib_1.Stack(app, 'Stack1');
const account1 = new lib_1.ScopedAws(stack1).accountId;
const stack2 = new lib_1.Stack(app, 'Stack2');
// WHEN - used in another stack
new lib_1.CfnParameter(stack2, 'SomeParameter', { type: 'String', default: account1 });
// THEN
const assembly = app.synth();
const template1 = assembly.getStackByName(stack1.stackName).template;
const template2 = assembly.getStackByName(stack2.stackName).template;
test.deepEqual(template1, {
Outputs: {
ExportsOutputRefAWSAccountIdAD568057: {
Value: { Ref: 'AWS::AccountId' },
Export: { Name: 'Stack1:ExportsOutputRefAWSAccountIdAD568057' }
}
}
});
test.deepEqual(template2, {
Parameters: {
SomeParameter: {
Type: 'String',
Default: { 'Fn::ImportValue': 'Stack1:ExportsOutputRefAWSAccountIdAD568057' }
}
}
});
test.done();
},
'Cross-stack references are detected in resource properties'(test) {
// GIVEN
const app = new lib_1.App();
const stack1 = new lib_1.Stack(app, 'Stack1');
const resource1 = new lib_1.CfnResource(stack1, 'Resource', { type: 'BLA' });
const stack2 = new lib_1.Stack(app, 'Stack2');
// WHEN - used in another resource
new lib_1.CfnResource(stack2, 'SomeResource', { type: 'AWS::Some::Resource', properties: {
someProperty: new intrinsic_1.Intrinsic(resource1.ref),
} });
// THEN
const assembly = app.synth();
const template2 = assembly.getStackByName(stack2.stackName).template;
test.deepEqual(template2, {
Resources: {
SomeResource: {
Type: 'AWS::Some::Resource',
Properties: {
someProperty: { 'Fn::ImportValue': 'Stack1:ExportsOutputRefResource1D5D905A' }
}
}
}
});
test.done();
},
'cross-stack references in lazy tokens work'(test) {
// GIVEN
const app = new lib_1.App();
const stack1 = new lib_1.Stack(app, 'Stack1');
const account1 = new lib_1.ScopedAws(stack1).accountId;
const stack2 = new lib_1.Stack(app, 'Stack2');
// WHEN - used in another stack
new lib_1.CfnParameter(stack2, 'SomeParameter', { type: 'String', default: lib_1.Lazy.stringValue({ produce: () => account1 }) });
const assembly = app.synth();
const template1 = assembly.getStackByName(stack1.stackName).template;
const template2 = assembly.getStackByName(stack2.stackName).template;
// THEN
test.deepEqual(template1, {
Outputs: {
ExportsOutputRefAWSAccountIdAD568057: {
Value: { Ref: 'AWS::AccountId' },
Export: { Name: 'Stack1:ExportsOutputRefAWSAccountIdAD568057' }
}
}
});
test.deepEqual(template2, {
Parameters: {
SomeParameter: {
Type: 'String',
Default: { 'Fn::ImportValue': 'Stack1:ExportsOutputRefAWSAccountIdAD568057' }
}
}
});
test.done();
},
'Cross-stack use of Region and account returns nonscoped intrinsic because the two stacks must be in the same region anyway'(test) {
// GIVEN
const app = new lib_1.App();
const stack1 = new lib_1.Stack(app, 'Stack1');
const stack2 = new lib_1.Stack(app, 'Stack2');
// WHEN - used in another stack
new lib_1.CfnOutput(stack2, 'DemOutput', { value: stack1.region });
new lib_1.CfnOutput(stack2, 'DemAccount', { value: stack1.account });
// THEN
const assembly = app.synth();
const template2 = assembly.getStackByName(stack2.stackName).template;
test.deepEqual(template2, {
Outputs: {
DemOutput: {
Value: { Ref: 'AWS::Region' },
},
DemAccount: {
Value: { Ref: 'AWS::AccountId' },
}
}
});
test.done();
},
'cross-stack references in strings work'(test) {
// GIVEN
const app = new lib_1.App();
const stack1 = new lib_1.Stack(app, 'Stack1');
const account1 = new lib_1.ScopedAws(stack1).accountId;
const stack2 = new lib_1.Stack(app, 'Stack2');
// WHEN - used in another stack
new lib_1.CfnParameter(stack2, 'SomeParameter', { type: 'String', default: `TheAccountIs${account1}` });
const assembly = app.synth();
const template2 = assembly.getStackByName(stack2.stackName).template;
// THEN
test.deepEqual(template2, {
Parameters: {
SomeParameter: {
Type: 'String',
Default: { 'Fn::Join': ['', ['TheAccountIs', { 'Fn::ImportValue': 'Stack1:ExportsOutputRefAWSAccountIdAD568057' }]] }
}
}
});
test.done();
},
'cross stack references and dependencies work within child stacks (non-nested)'(test) {
// GIVEN
const app = new lib_1.App();
const parent = new lib_1.Stack(app, 'Parent');
const child1 = new lib_1.Stack(parent, 'Child1');
const child2 = new lib_1.Stack(parent, 'Child2');
const resourceA = new lib_1.CfnResource(child1, 'ResourceA', { type: 'RA' });
const resourceB = new lib_1.CfnResource(child1, 'ResourceB', { type: 'RB' });
// WHEN
const resource2 = new lib_1.CfnResource(child2, 'Resource1', {
type: 'R2',
properties: {
RefToResource1: resourceA.ref
}
});
resource2.addDependsOn(resourceB);
// THEN
const assembly = app.synth();
const parentTemplate = assembly.getStackArtifact(parent.artifactId).template;
const child1Template = assembly.getStackArtifact(child1.artifactId).template;
const child2Template = assembly.getStackArtifact(child2.artifactId).template;
test.deepEqual(parentTemplate, {});
test.deepEqual(child1Template, {
Resources: {
ResourceA: { Type: 'RA' },
ResourceB: { Type: 'RB' }
},
Outputs: {
ExportsOutputRefResourceA461B4EF9: {
Value: { Ref: 'ResourceA' },
Export: { Name: 'ParentChild18FAEF419:Child1ExportsOutputRefResourceA7BF20B37' }
}
}
});
test.deepEqual(child2Template, {
Resources: {
Resource1: {
Type: 'R2',
Properties: {
RefToResource1: { 'Fn::ImportValue': 'ParentChild18FAEF419:Child1ExportsOutputRefResourceA7BF20B37' }
}
}
}
});
test.deepEqual(assembly.getStackArtifact(child1.artifactId).dependencies.map(x => x.id), []);
test.deepEqual(assembly.getStackArtifact(child2.artifactId).dependencies.map(x => x.id), ['ParentChild18FAEF419']);
test.done();
},
'CfnSynthesisError is ignored when preparing cross references'(test) {
// GIVEN
const app = new lib_1.App();
const stack = new lib_1.Stack(app, 'my-stack');
// WHEN
class CfnTest extends lib_1.CfnResource {
_toCloudFormation() {
return new util_1.PostResolveToken({
xoo: 1234
}, props => {
lib_1.validateString(props).assertSuccess();
});
}
}
new CfnTest(stack, 'MyThing', { type: 'AWS::Type' });
// THEN
lib_1.ConstructNode.prepare(stack.node);
test.done();
},
'Stacks can be children of other stacks (substack) and they will be synthesized separately'(test) {
// GIVEN
const app = new lib_1.App();
// WHEN
const parentStack = new lib_1.Stack(app, 'parent');
const childStack = new lib_1.Stack(parentStack, 'child');
new lib_1.CfnResource(parentStack, 'MyParentResource', { type: 'Resource::Parent' });
new lib_1.CfnResource(childStack, 'MyChildResource', { type: 'Resource::Child' });
// THEN
const assembly = app.synth();
test.deepEqual(assembly.getStackByName(parentStack.stackName).template, { Resources: { MyParentResource: { Type: 'Resource::Parent' } } });
test.deepEqual(assembly.getStackByName(childStack.stackName).template, { Resources: { MyChildResource: { Type: 'Resource::Child' } } });
test.done();
},
'cross-stack reference (substack references parent stack)'(test) {
// GIVEN
const app = new lib_1.App();
const parentStack = new lib_1.Stack(app, 'parent');
const childStack = new lib_1.Stack(parentStack, 'child');
// WHEN (a resource from the child stack references a resource from the parent stack)
const parentResource = new lib_1.CfnResource(parentStack, 'MyParentResource', { type: 'Resource::Parent' });
new lib_1.CfnResource(childStack, 'MyChildResource', {
type: 'Resource::Child',
properties: {
ChildProp: parentResource.getAtt('AttOfParentResource')
}
});
// THEN
const assembly = app.synth();
test.deepEqual(assembly.getStackByName(parentStack.stackName).template, {
Resources: { MyParentResource: { Type: 'Resource::Parent' } },
Outputs: { ExportsOutputFnGetAttMyParentResourceAttOfParentResourceC2D0BB9E: {
Value: { 'Fn::GetAtt': ['MyParentResource', 'AttOfParentResource'] },
Export: { Name: 'parent:ExportsOutputFnGetAttMyParentResourceAttOfParentResourceC2D0BB9E' }
}
}
});
test.deepEqual(assembly.getStackByName(childStack.stackName).template, {
Resources: {
MyChildResource: {
Type: 'Resource::Child',
Properties: {
ChildProp: {
'Fn::ImportValue': 'parent:ExportsOutputFnGetAttMyParentResourceAttOfParentResourceC2D0BB9E'
}
}
}
}
});
test.done();
},
'cross-stack reference (parent stack references substack)'(test) {
// GIVEN
const app = new lib_1.App();
const parentStack = new lib_1.Stack(app, 'parent');
const childStack = new lib_1.Stack(parentStack, 'child');
// WHEN (a resource from the child stack references a resource from the parent stack)
const childResource = new lib_1.CfnResource(childStack, 'MyChildResource', { type: 'Resource::Child' });
new lib_1.CfnResource(parentStack, 'MyParentResource', {
type: 'Resource::Parent',
properties: {
ParentProp: childResource.getAtt('AttributeOfChildResource')
}
});
// THEN
const assembly = app.synth();
test.deepEqual(assembly.getStackByName(parentStack.stackName).template, {
Resources: {
MyParentResource: {
Type: 'Resource::Parent',
Properties: {
ParentProp: { 'Fn::ImportValue': 'parentchild13F9359B:childExportsOutputFnGetAttMyChildResourceAttributeOfChildResource420052FC' }
}
}
}
});
test.deepEqual(assembly.getStackByName(childStack.stackName).template, {
Resources: {
MyChildResource: { Type: 'Resource::Child' }
},
Outputs: {
ExportsOutputFnGetAttMyChildResourceAttributeOfChildResource52813264: {
Value: { 'Fn::GetAtt': ['MyChildResource', 'AttributeOfChildResource'] },
Export: { Name: 'parentchild13F9359B:childExportsOutputFnGetAttMyChildResourceAttributeOfChildResource420052FC' }
}
}
});
test.done();
},
'cannot create cyclic reference between stacks'(test) {
// GIVEN
const app = new lib_1.App();
const stack1 = new lib_1.Stack(app, 'Stack1');
const account1 = new lib_1.ScopedAws(stack1).accountId;
const stack2 = new lib_1.Stack(app, 'Stack2');
const account2 = new lib_1.ScopedAws(stack2).accountId;
// WHEN
new lib_1.CfnParameter(stack2, 'SomeParameter', { type: 'String', default: account1 });
new lib_1.CfnParameter(stack1, 'SomeParameter', { type: 'String', default: account2 });
test.throws(() => {
lib_1.ConstructNode.prepare(app.node);
// tslint:disable-next-line:max-line-length
}, "'Stack2' depends on 'Stack1' (Stack2/SomeParameter -> Stack1.AWS::AccountId). Adding this dependency (Stack1/SomeParameter -> Stack2.AWS::AccountId) would create a cyclic reference.");
test.done();
},
'stacks know about their dependencies'(test) {
// GIVEN
const app = new lib_1.App();
const stack1 = new lib_1.Stack(app, 'Stack1');
const account1 = new lib_1.ScopedAws(stack1).accountId;
const stack2 = new lib_1.Stack(app, 'Stack2');
// WHEN
new lib_1.CfnParameter(stack2, 'SomeParameter', { type: 'String', default: account1 });
lib_1.ConstructNode.prepare(app.node);
// THEN
test.deepEqual(stack2.dependencies.map(s => s.node.id), ['Stack1']);
test.done();
},
'cannot create references to stacks in other regions/accounts'(test) {
// GIVEN
const app = new lib_1.App();
const stack1 = new lib_1.Stack(app, 'Stack1', { env: { account: '123456789012', region: 'es-norst-1' } });
const account1 = new lib_1.ScopedAws(stack1).accountId;
const stack2 = new lib_1.Stack(app, 'Stack2', { env: { account: '123456789012', region: 'es-norst-2' } });
// WHEN
new lib_1.CfnParameter(stack2, 'SomeParameter', { type: 'String', default: account1 });
test.throws(() => {
lib_1.ConstructNode.prepare(app.node);
}, /Stack "Stack2" cannot consume a cross reference from stack "Stack1"/);
test.done();
},
'urlSuffix does not imply a stack dependency'(test) {
// GIVEN
const app = new lib_1.App();
const first = new lib_1.Stack(app, 'First');
const second = new lib_1.Stack(app, 'Second');
// WHEN
new lib_1.CfnOutput(second, 'Output', {
value: first.urlSuffix
});
// THEN
app.synth();
test.equal(second.dependencies.length, 0);
test.done();
},
'stack with region supplied via props returns literal value'(test) {
// GIVEN
const app = new lib_1.App();
const stack = new lib_1.Stack(app, 'Stack1', { env: { account: '123456789012', region: 'es-norst-1' } });
// THEN
test.equal(stack.resolve(stack.region), 'es-norst-1');
test.done();
},
'overrideLogicalId(id) can be used to override the logical ID of a resource'(test) {
// GIVEN
const stack = new lib_1.Stack();
const bonjour = new lib_1.CfnResource(stack, 'BonjourResource', { type: 'Resource::Type' });
// { Ref } and { GetAtt }
new lib_1.CfnResource(stack, 'RefToBonjour', { type: 'Other::Resource', properties: {
RefToBonjour: bonjour.ref,
GetAttBonjour: bonjour.getAtt('TheAtt').toString()
} });
bonjour.overrideLogicalId('BOOM');
// THEN
test.deepEqual(util_2.toCloudFormation(stack), { Resources: { BOOM: { Type: 'Resource::Type' },
RefToBonjour: { Type: 'Other::Resource',
Properties: { RefToBonjour: { Ref: 'BOOM' },
GetAttBonjour: { 'Fn::GetAtt': ['BOOM', 'TheAtt'] } } } } });
test.done();
},
'Stack name can be overridden via properties'(test) {
// WHEN
const stack = new lib_1.Stack(undefined, 'Stack', { stackName: 'otherName' });
// THEN
test.deepEqual(stack.stackName, 'otherName');
test.done();
},
'Stack name is inherited from App name if available'(test) {
// WHEN
const root = new lib_1.App();
const app = new lib_1.Construct(root, 'Prod');
const stack = new lib_1.Stack(app, 'Stack');
// THEN
test.deepEqual(stack.stackName, 'ProdStackD5279B22');
test.done();
},
'stack construct id does not go through stack name validation if there is an explicit stack name'(test) {
// GIVEN
const app = new lib_1.App();
// WHEN
const stack = new lib_1.Stack(app, 'invalid as : stack name, but thats fine', {
stackName: 'valid-stack-name'
});
// THEN
const session = app.synth();
test.deepEqual(stack.stackName, 'valid-stack-name');
test.ok(session.tryGetArtifact(stack.artifactId));
test.done();
},
'stack validation is performed on explicit stack name'(test) {
// GIVEN
const app = new lib_1.App();
// THEN
test.throws(() => new lib_1.Stack(app, 'boom', { stackName: 'invalid:stack:name' }), /Stack name must match the regular expression/);
test.done();
},
'Stack.of(stack) returns the correct stack'(test) {
const stack = new lib_1.Stack();
test.same(lib_1.Stack.of(stack), stack);
const parent = new lib_1.Construct(stack, 'Parent');
const construct = new lib_1.Construct(parent, 'Construct');
test.same(lib_1.Stack.of(construct), stack);
test.done();
},
'Stack.of() throws when there is no parent Stack'(test) {
const root = new lib_1.Construct(undefined, 'Root');
const construct = new lib_1.Construct(root, 'Construct');
test.throws(() => lib_1.Stack.of(construct), /No stack could be identified for the construct at path/);
test.done();
},
'Stack.of() works for substacks'(test) {
// GIVEN
const app = new lib_1.App();
// WHEN
const parentStack = new lib_1.Stack(app, 'ParentStack');
const parentResource = new lib_1.CfnResource(parentStack, 'ParentResource', { type: 'parent::resource' });
// we will define a substack under the /resource/... just for giggles.
const childStack = new lib_1.Stack(parentResource, 'ChildStack');
const childResource = new lib_1.CfnResource(childStack, 'ChildResource', { type: 'child::resource' });
// THEN
test.same(lib_1.Stack.of(parentStack), parentStack);
test.same(lib_1.Stack.of(parentResource), parentStack);
test.same(lib_1.Stack.of(childStack), childStack);
test.same(lib_1.Stack.of(childResource), childStack);
test.done();
},
'stack.availabilityZones falls back to Fn::GetAZ[0],[2] if region is not specified'(test) {
// GIVEN
const app = new lib_1.App();
const stack = new lib_1.Stack(app, 'MyStack');
// WHEN
const azs = stack.availabilityZones;
// THEN
test.deepEqual(stack.resolve(azs), [
{ "Fn::Select": [0, { "Fn::GetAZs": "" }] },
{ "Fn::Select": [1, { "Fn::GetAZs": "" }] }
]);
test.done();
},
'stack.templateFile is the name of the template file emitted to the cloud assembly (default is to use the stack name)'(test) {
// GIVEN
const app = new lib_1.App();
// WHEN
const stack1 = new lib_1.Stack(app, 'MyStack1');
const stack2 = new lib_1.Stack(app, 'MyStack2', { stackName: 'MyRealStack2' });
// THEN
test.deepEqual(stack1.templateFile, 'MyStack1.template.json');
test.deepEqual(stack2.templateFile, 'MyRealStack2.template.json');
test.done();
},
'when feature flag is enabled we will use the artifact id as the template name'(test) {
// GIVEN
const app = new lib_1.App({
context: {
[cxapi.ENABLE_STACK_NAME_DUPLICATES_CONTEXT]: 'true'
}
});
// WHEN
const stack1 = new lib_1.Stack(app, 'MyStack1');
const stack2 = new lib_1.Stack(app, 'MyStack2', { stackName: 'MyRealStack2' });
// THEN
test.deepEqual(stack1.templateFile, 'MyStack1.template.json');
test.deepEqual(stack2.templateFile, 'MyStack2.template.json');
test.done();
},
'@aws-cdk/core:enableStackNameDuplicates': {
'disabled (default)': {
'artifactId and templateFile use the stack name'(test) {
// GIVEN
const app = new lib_1.App();
// WHEN
const stack1 = new lib_1.Stack(app, 'MyStack1', { stackName: 'thestack' });
const assembly = app.synth();
// THEN
test.deepEqual(stack1.artifactId, 'thestack');
test.deepEqual(stack1.templateFile, 'thestack.template.json');
test.deepEqual(assembly.getStackArtifact(stack1.artifactId).templateFile, 'thestack.template.json');
test.done();
}
},
'enabled': {
'allows using the same stack name for two stacks (i.e. in different regions)'(test) {
// GIVEN
const app = new lib_1.App({ context: { [cxapi.ENABLE_STACK_NAME_DUPLICATES_CONTEXT]: 'true' } });
// WHEN
const stack1 = new lib_1.Stack(app, 'MyStack1', { stackName: 'thestack' });
const stack2 = new lib_1.Stack(app, 'MyStack2', { stackName: 'thestack' });
const assembly = app.synth();
// THEN
test.deepEqual(assembly.getStackArtifact(stack1.artifactId).templateFile, 'MyStack1.template.json');
test.deepEqual(assembly.getStackArtifact(stack2.artifactId).templateFile, 'MyStack2.template.json');
test.deepEqual(stack1.templateFile, 'MyStack1.template.json');
test.deepEqual(stack2.templateFile, 'MyStack2.template.json');
test.done();
},
'artifactId and templateFile use the unique id and not the stack name'(test) {
// GIVEN
const app = new lib_1.App({ context: { [cxapi.ENABLE_STACK_NAME_DUPLICATES_CONTEXT]: 'true' } });
// WHEN
const stack1 = new lib_1.Stack(app, 'MyStack1', { stackName: 'thestack' });
const assembly = app.synth();
// THEN
test.deepEqual(stack1.artifactId, 'MyStack1');
test.deepEqual(stack1.templateFile, 'MyStack1.template.json');
test.deepEqual(assembly.getStackArtifact(stack1.artifactId).templateFile, 'MyStack1.template.json');
test.done();
}
}
},
'metadata is collected at the stack boundary'(test) {
// GIVEN
const app = new lib_1.App({
context: {
[cxapi.DISABLE_METADATA_STACK_TRACE]: 'true'
}
});
const parent = new lib_1.Stack(app, 'parent');
const child = new lib_1.Stack(parent, 'child');
// WHEN
child.node.addMetadata('foo', 'bar');
// THEN
const asm = app.synth();
test.deepEqual(asm.getStackByName(parent.stackName).findMetadataByType('foo'), []);
test.deepEqual(asm.getStackByName(child.stackName).findMetadataByType('foo'), [
{ path: '/parent/child', type: 'foo', data: 'bar' }
]);
test.done();
}
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdC5zdGFjay5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInRlc3Quc3RhY2sudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLHlDQUF5QztBQUV6QyxnQ0FBK0o7QUFDL0osd0RBQXFEO0FBQ3JELHNDQUErQztBQUMvQyxpQ0FBMEM7QUEyekIxQyxNQUFNLHNCQUF1QixTQUFRLFdBQUs7SUFFeEMsTUFBTTtJQUVDLGlCQUFpQjtRQUN0QixNQUFNLFFBQVEsR0FBRyxLQUFLLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztRQUUzQyxtREFBbUQ7UUFDbkQsUUFBUSxDQUFDLFNBQVMsQ0FBQyxVQUFVLENBQUMsVUFBVSxDQUFDLFdBQVcsQ0FBQyxHQUFHO1lBQ3RELFFBQVEsQ0FBQyxTQUFTLENBQUMsVUFBVSxDQUFDLFVBQVUsQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDO1FBQzNELE9BQU8sUUFBUSxDQUFDLFNBQVMsQ0FBQyxVQUFVLENBQUMsVUFBVSxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUM7UUFFaEUsT0FBTyxRQUFRLENBQUM7SUFDbEIsQ0FBQztDQUNGO0FBdjBCRCxpQkFBUztJQUNQLGlGQUFpRixDQUFDLElBQVU7UUFDMUYsTUFBTSxLQUFLLEdBQUcsSUFBSSxXQUFLLEVBQUUsQ0FBQztRQUMxQixJQUFJLENBQUMsU0FBUyxDQUFDLHVCQUFnQixDQUFDLEtBQUssQ0FBQyxFQUFFLEVBQUcsQ0FBQyxDQUFDO1FBQzdDLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUNkLENBQUM7SUFFRCwyRkFBMkYsQ0FBQyxJQUFVO1FBQ3BHLE1BQU0sS0FBSyxHQUFHLElBQUksV0FBSyxFQUFFLENBQUM7UUFDMUIsS0FBSyxDQUFDLGVBQWUsQ0FBQyxxQkFBcUIsR0FBRyxtQkFBbUIsQ0FBQztRQUNsRSxLQUFLLENBQUMsZUFBZSxDQUFDLFdBQVcsR0FBRyx3QkFBd0IsQ0FBQztRQUM3RCxLQUFLLENBQUMsZUFBZSxDQUFDLFVBQVUsR0FBRyxD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