UNPKG

11.2 kBJavaScriptView Raw
1'use strict';
2
3const test = require('tape');
4const cloudfriend = require('..');
5const path = require('path');
6
7const expectedTemplate = require('./fixtures/static.json');
8const fixtures = path.resolve(__dirname, 'fixtures');
9
10test('intrinsic functions', (assert) => {
11 assert.deepEqual(cloudfriend.base64('secret'), { 'Fn::Base64': 'secret' }, 'base64');
12 assert.deepEqual(cloudfriend.findInMap('mapping', 'key', 'value'), { 'Fn::FindInMap': ['mapping', 'key', 'value'] }, 'lookup');
13 assert.deepEqual(cloudfriend.getAtt('obj', 'key'), { 'Fn::GetAtt': ['obj', 'key'] }, 'attr');
14 assert.deepEqual(cloudfriend.getAzs(), { 'Fn::GetAZs': '' }, 'azs (no value specified)');
15 assert.deepEqual(cloudfriend.getAzs('us-east-1'), { 'Fn::GetAZs': 'us-east-1' }, 'azs (value specified)');
16 assert.deepEqual(cloudfriend.join(['abra', 'cadabra']), { 'Fn::Join': ['', ['abra', 'cadabra']] }, 'join (no delimeter specified)');
17 assert.deepEqual(cloudfriend.join('-', ['abra', 'cadabra']), { 'Fn::Join': ['-', ['abra', 'cadabra']] }, 'join (delimeter specified)');
18 assert.deepEqual(cloudfriend.select(1, ['abra', 'cadabra']), { 'Fn::Select': ['1', ['abra', 'cadabra']] }, '');
19 assert.deepEqual(cloudfriend.ref('something'), { Ref: 'something' }, 'ref');
20 assert.deepEqual(cloudfriend.split(',', 'a,b,c,d'), { 'Fn::Split': [',', 'a,b,c,d'] }, 'split');
21 assert.deepEqual(cloudfriend.split(',', cloudfriend.ref('Id')), { 'Fn::Split': [',', { Ref: 'Id' }] }, 'split');
22 assert.deepEqual(cloudfriend.userData(['#!/usr/bin/env bash', 'set -e']), { 'Fn::Base64': { 'Fn::Join': ['\n', ['#!/usr/bin/env bash', 'set -e']] } }, 'userData');
23 assert.deepEqual(cloudfriend.sub('my ${thing}'), { 'Fn::Sub': 'my ${thing}' }, 'sub without variables');
24 assert.deepEqual(cloudfriend.sub('my ${thing}', { thing: 'stuff' }), { 'Fn::Sub': ['my ${thing}', { thing: 'stuff' }] }, 'sub with variables');
25 assert.deepEqual(cloudfriend.importValue('id'), { 'Fn::ImportValue': 'id' }, 'import value with string');
26 assert.deepEqual(cloudfriend.importValue(cloudfriend.ref('Id')), { 'Fn::ImportValue': cloudfriend.ref('Id') }, 'import value with string');
27 assert.deepEqual(cloudfriend.arn('s3', 'my-bucket/*'), { 'Fn::Sub': ['arn:${AWS::Partition}:${service}:::${suffix}', { service: 's3', suffix: 'my-bucket/*' }] }, 's3 arn');
28 assert.deepEqual(cloudfriend.arn('cloudformation', 'stack/my-stack/*'), { 'Fn::Sub': ['arn:${AWS::Partition}:${service}:${AWS::Region}:${AWS::AccountId}:${suffix}', { service: 'cloudformation', suffix: 'stack/my-stack/*' }] }, 'non-s3 arn');
29 assert.end();
30});
31
32test('conditions', (assert) => {
33 assert.deepEqual(cloudfriend.and(['a', 'b']), { 'Fn::And': ['a', 'b'] }, 'and');
34 assert.deepEqual(cloudfriend.equals('a', 'b'), { 'Fn::Equals': ['a', 'b'] }, 'equal');
35 assert.deepEqual(cloudfriend.if('condition', 'a', 'b'), { 'Fn::If': ['condition', 'a', 'b'] }, 'if');
36 assert.deepEqual(cloudfriend.not('condition'), { 'Fn::Not': ['condition'] }, 'not');
37 assert.deepEqual(cloudfriend.or(['a', 'b']), { 'Fn::Or': ['a', 'b'] }, 'or');
38 assert.deepEqual(cloudfriend.notEquals('a', 'b'), { 'Fn::Not': [{ 'Fn::Equals': ['a', 'b'] }] }, 'notEqual');
39 assert.end();
40});
41
42test('pseudo', (assert) => {
43 assert.deepEqual(cloudfriend.accountId, { Ref: 'AWS::AccountId' }, 'account');
44 assert.deepEqual(cloudfriend.notificationArns, { Ref: 'AWS::NotificationARNs' }, 'notificationArns');
45 assert.deepEqual(cloudfriend.noValue, { Ref: 'AWS::NoValue' }, 'noValue');
46 assert.deepEqual(cloudfriend.region, { Ref: 'AWS::Region' }, 'region');
47 assert.deepEqual(cloudfriend.stackId, { Ref: 'AWS::StackId' }, 'stackId');
48 assert.deepEqual(cloudfriend.stackName, { Ref: 'AWS::StackName' }, 'stack');
49 assert.deepEqual(cloudfriend.partition, { Ref: 'AWS::Partition' }, 'stack');
50 assert.deepEqual(cloudfriend.urlSuffix, { Ref: 'AWS::URLSuffix' }, 'stack');
51 assert.end();
52});
53
54test('build', (assert) => {
55 assert.plan(8);
56
57 cloudfriend.build(path.join(fixtures, 'static.json'))
58 .then((template) => {
59 assert.deepEqual(template, expectedTemplate, 'static.json');
60 return cloudfriend.build(path.join(fixtures, 'static.js'));
61 })
62 .then((template) => {
63 assert.deepEqual(template, expectedTemplate, 'static.js');
64 return cloudfriend.build(path.join(fixtures, 'sync.js'));
65 })
66 .then((template) => {
67 assert.deepEqual(template, expectedTemplate, 'sync.js');
68 return cloudfriend.build(path.join(fixtures, 'async.js'));
69 })
70 .then((template) => {
71 assert.deepEqual(template, expectedTemplate, 'async.js (success)');
72 return cloudfriend.build(path.join(fixtures, 'async-error.js'))
73 .catch((err) => {
74 assert.ok(err, 'async.js (error)');
75 });
76 })
77 .then(() => {
78 return cloudfriend.build(path.join(fixtures, 'sync-args.js'), { some: 'options' });
79 })
80 .then((template) => {
81 assert.deepEqual(template, { some: 'options' }, 'passes args (sync)');
82 return cloudfriend.build(path.join(fixtures, 'async-args.js'), { some: 'options' });
83 })
84 .then((template) => {
85 assert.deepEqual(template, { some: 'options' }, 'passes args (async)');
86 return cloudfriend.build(path.join(fixtures, 'malformed.json'))
87 .catch((err) => {
88 assert.ok(err, 'malformed JSON (error)');
89 });
90 });
91});
92
93test('validate', (assert) => {
94 assert.plan(2);
95
96 cloudfriend.validate(path.join(fixtures, 'static.json'))
97 .then(() => {
98 assert.ok(true, 'valid');
99 return cloudfriend.validate(path.join(fixtures, 'invalid.json'));
100 })
101 .catch((err) => {
102 assert.ok(/Template format error: Unrecognized resource type/.test(err.message), 'invalid');
103 });
104});
105
106test('merge', (assert) => {
107 const a = {
108 Metadata: { Instances: { Description: 'Information about the instances' } },
109 Parameters: { InstanceCount: { Type: 'Number' } },
110 Mappings: { Region: { 'us-east-1': { AMI: 'ami-123456' } } },
111 Conditions: { WouldYouLikeBaconWithThat: cloudfriend.equals(cloudfriend.ref('InstanceCount'), 999) },
112 Resources: { Instance: { Type: 'AWS::EC2::Instance', Properties: { ImageId: cloudfriend.findInMap('Region', cloudfriend.region, 'AMI') } } },
113 Outputs: { Breakfast: { Condition: 'WouldYouLikeBaconWithThat', Value: cloudfriend.ref('Instance') } }
114 };
115
116 let b = {
117 Metadata: { Databases: { Description: 'Information about the databases' } },
118 Parameters: { DatabasePrefix: { Type: 'String' } },
119 Mappings: { Prefix: { eggs: { Name: 'bananas' } } },
120 Conditions: { TooMuch: cloudfriend.equals(cloudfriend.ref('DatabasePrefix'), 'bacon') },
121 Resources: { Database: { Type: 'AWS::DynamoDB::Table', Properties: { Name: cloudfriend.findInMap('Prefix', cloudfriend.ref('DatabasePrefix'), 'Name') } } },
122 Outputs: { GoSomewhereElse: { Condition: 'TooMuch', Value: cloudfriend.ref('Database') } }
123 };
124
125 const c = {
126 Parameters: { NoConsequence: { Type: 'String' } }
127 };
128
129 assert.deepEqual(cloudfriend.merge(a, b, c), {
130 AWSTemplateFormatVersion: '2010-09-09',
131 Metadata: {
132 Instances: { Description: 'Information about the instances' },
133 Databases: { Description: 'Information about the databases' }
134 },
135 Parameters: {
136 InstanceCount: { Type: 'Number' },
137 DatabasePrefix: { Type: 'String' },
138 NoConsequence: { Type: 'String' }
139 },
140 Mappings: {
141 Region: { 'us-east-1': { AMI: 'ami-123456' } },
142 Prefix: { eggs: { Name: 'bananas' } }
143 },
144 Conditions: {
145 WouldYouLikeBaconWithThat: cloudfriend.equals(cloudfriend.ref('InstanceCount'), 999),
146 TooMuch: cloudfriend.equals(cloudfriend.ref('DatabasePrefix'), 'bacon')
147 },
148 Resources: {
149 Instance: { Type: 'AWS::EC2::Instance', Properties: { ImageId: cloudfriend.findInMap('Region', cloudfriend.region, 'AMI') } },
150 Database: { Type: 'AWS::DynamoDB::Table', Properties: { Name: cloudfriend.findInMap('Prefix', cloudfriend.ref('DatabasePrefix'), 'Name') } }
151 },
152 Outputs: {
153 Breakfast: { Condition: 'WouldYouLikeBaconWithThat', Value: cloudfriend.ref('Instance') },
154 GoSomewhereElse: { Condition: 'TooMuch', Value: cloudfriend.ref('Database') }
155 }
156 }, 'merge without overlap');
157
158 assert.throws(() => {
159 b = { Metadata: { Instances: { Description: 'Information about the instances different' } } };
160 cloudfriend.merge(a, b);
161 }, /Metadata name used more than once: Instances/, 'throws on .Metadata overlap');
162
163 assert.doesNotThrow(() => {
164 b = { Metadata: { Instances: { Description: 'Information about the instances' } } };
165 cloudfriend.merge(a, b);
166 }, 'allows identical .Metadata overlap');
167
168 assert.throws(() => {
169 b = { Parameters: { InstanceCount: { Type: 'Number', Description: 'Different' } } };
170 cloudfriend.merge(a, b);
171 }, /Parameters name used more than once: InstanceCount/, 'throws on .Parameters overlap');
172
173 assert.doesNotThrow(() => {
174 b = { Parameters: { InstanceCount: { Type: 'Number' } } };
175 cloudfriend.merge(a, b);
176 }, 'allows identical .Parameters overlap');
177
178 assert.throws(() => {
179 b = { Mappings: { Region: { 'us-east-1': { AMI: 'ami-123456' }, 'us-east-4': { AMI: 'ami-123456' } } } };
180 cloudfriend.merge(a, b);
181 }, /Mappings name used more than once: Region/, 'throws on .Mappings overlap');
182
183 assert.doesNotThrow(() => {
184 b = { Mappings: { Region: { 'us-east-1': { AMI: 'ami-123456' } } } };
185 cloudfriend.merge(a, b);
186 }, 'allows identical .Mappings overlap');
187
188 assert.throws(() => {
189 b = { Conditions: { WouldYouLikeBaconWithThat: cloudfriend.equals(cloudfriend.ref('InstanceCount'), 998) } };
190 cloudfriend.merge(a, b);
191 }, /Conditions name used more than once: WouldYouLikeBaconWithThat/, 'throws on .Conditions overlap');
192
193 assert.doesNotThrow(() => {
194 b = { Conditions: { WouldYouLikeBaconWithThat: cloudfriend.equals(cloudfriend.ref('InstanceCount'), 999) } };
195 cloudfriend.merge(a, b);
196 }, 'allows identical .Conditions overlap');
197
198 assert.throws(() => {
199 b = { Resources: { Instance: { Type: 'AWS::EC2::Instance', Properties: { ImageId: cloudfriend.findInMap('Region', cloudfriend.region, 'AMIz') } } } };
200 cloudfriend.merge(a, b);
201 }, /Resources name used more than once: Instance/, 'throws on .Resources overlap');
202
203 assert.doesNotThrow(() => {
204 b = { Resources: { Instance: { Type: 'AWS::EC2::Instance', Properties: { ImageId: cloudfriend.findInMap('Region', cloudfriend.region, 'AMI') } } } };
205 cloudfriend.merge(a, b);
206 }, 'allows identical .Resources overlap');
207
208 assert.throws(() => {
209 b = { Outputs: { Breakfast: { Condition: 'WouldYouLikeBaconWithThat', Value: cloudfriend.ref('Instancez') } } };
210 cloudfriend.merge(a, b);
211 }, /Outputs name used more than once: Breakfast/, 'throws on .Outputs overlap');
212
213 assert.doesNotThrow(() => {
214 b = { Outputs: { Breakfast: { Condition: 'WouldYouLikeBaconWithThat', Value: cloudfriend.ref('Instance') } } };
215 cloudfriend.merge(a, b);
216 }, 'allows identical .Outputs overlap');
217
218 assert.doesNotThrow(() => {
219 b = { Mappings: { Instance: { 'us-east-1': { AMI: 'ami-123456' } } } };
220 cloudfriend.merge(a, b);
221 }, 'does not throw on cross-property name overlap');
222
223 assert.end();
224});