@mapbox/cloudfriend 9.2.0 → 9.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +8 -0
- package/.idea/cloudfriend.iml +9 -0
- package/.idea/codeStyles/Project.xml +7 -0
- package/.idea/codeStyles/codeStyleConfig.xml +5 -0
- package/.idea/inspectionProfiles/Project_Default.xml +6 -0
- package/.idea/misc.xml +6 -0
- package/.idea/modules.xml +8 -0
- package/.idea/vcs.xml +6 -0
- package/.nyc_output/6686e513-03b6-415d-9b8b-0fcde7a4e430.json +1 -0
- package/.nyc_output/f58a557c-a1c0-4dcc-83c5-bbca4d01baf9.json +1 -0
- package/.nyc_output/processinfo/6686e513-03b6-415d-9b8b-0fcde7a4e430.json +1 -0
- package/.nyc_output/processinfo/f58a557c-a1c0-4dcc-83c5-bbca4d01baf9.json +1 -0
- package/.nyc_output/processinfo/index.json +1 -1
- package/cfniceberg_createtable.yaml +71 -0
- package/changelog.md +8 -0
- package/coverage/clover.xml +630 -0
- package/coverage/coverage-final.json +33 -0
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/cloudfriend/bin/build-template.js.html +130 -0
- package/coverage/lcov-report/cloudfriend/bin/index.html +131 -0
- package/coverage/lcov-report/cloudfriend/bin/validate-template.js.html +142 -0
- package/coverage/lcov-report/cloudfriend/index.html +116 -0
- package/coverage/lcov-report/cloudfriend/index.js.html +307 -0
- package/coverage/lcov-report/cloudfriend/lib/build.js.html +217 -0
- package/coverage/lcov-report/cloudfriend/lib/conditions.js.html +430 -0
- package/coverage/lcov-report/cloudfriend/lib/index.html +206 -0
- package/coverage/lcov-report/cloudfriend/lib/intrinsic.js.html +979 -0
- package/coverage/lcov-report/cloudfriend/lib/merge.js.html +478 -0
- package/coverage/lcov-report/cloudfriend/lib/pseudo.js.html +370 -0
- package/coverage/lcov-report/cloudfriend/lib/rules.js.html +349 -0
- package/coverage/lcov-report/cloudfriend/lib/shortcuts/cross-account-role.js.html +244 -0
- package/coverage/lcov-report/cloudfriend/lib/shortcuts/event-lambda.js.html +367 -0
- package/coverage/lcov-report/cloudfriend/lib/shortcuts/glue-database.js.html +286 -0
- package/coverage/lcov-report/cloudfriend/lib/shortcuts/glue-iceberg-table.js.html +646 -0
- package/coverage/lcov-report/cloudfriend/lib/shortcuts/glue-json-table.js.html +235 -0
- package/coverage/lcov-report/cloudfriend/lib/shortcuts/glue-orc-table.js.html +226 -0
- package/coverage/lcov-report/cloudfriend/lib/shortcuts/glue-parquet-table.js.html +268 -0
- package/coverage/lcov-report/cloudfriend/lib/shortcuts/glue-presto-view.js.html +358 -0
- package/coverage/lcov-report/cloudfriend/lib/shortcuts/glue-spark-view.js.html +241 -0
- package/coverage/lcov-report/cloudfriend/lib/shortcuts/glue-table.js.html +481 -0
- package/coverage/lcov-report/cloudfriend/lib/shortcuts/hookshot.js.html +1504 -0
- package/coverage/lcov-report/cloudfriend/lib/shortcuts/index.html +431 -0
- package/coverage/lcov-report/cloudfriend/lib/shortcuts/index.js.html +157 -0
- package/coverage/lcov-report/cloudfriend/lib/shortcuts/kinesis-firehose-base.js.html +418 -0
- package/coverage/lcov-report/cloudfriend/lib/shortcuts/lambda.js.html +832 -0
- package/coverage/lcov-report/cloudfriend/lib/shortcuts/log-subscription-lambda.js.html +310 -0
- package/coverage/lcov-report/cloudfriend/lib/shortcuts/queue-lambda.js.html +364 -0
- package/coverage/lcov-report/cloudfriend/lib/shortcuts/queue.js.html +619 -0
- package/coverage/lcov-report/cloudfriend/lib/shortcuts/role.js.html +382 -0
- package/coverage/lcov-report/cloudfriend/lib/shortcuts/s3-kinesis-firehose.js.html +568 -0
- package/coverage/lcov-report/cloudfriend/lib/shortcuts/scheduled-lambda.js.html +490 -0
- package/coverage/lcov-report/cloudfriend/lib/shortcuts/service-role.js.html +307 -0
- package/coverage/lcov-report/cloudfriend/lib/shortcuts/stream-lambda.js.html +493 -0
- package/coverage/lcov-report/cloudfriend/lib/validate.js.html +154 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +161 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +210 -0
- package/coverage/lcov.info +1319 -0
- package/jest.config.js +14 -0
- package/lib/shortcuts/api.md +37 -0
- package/lib/shortcuts/glue-iceberg-table.js +187 -0
- package/lib/shortcuts/index.js +1 -0
- package/package.json +15 -13
- package/readme.md +1 -1
- package/requirements.dev.txt +2 -2
- package/test/bin.test.js +18 -14
- package/test/fixtures/shortcuts/cross-account-role-defaults.json +1 -1
- package/test/fixtures/shortcuts/cross-account-role-no-defaults.json +1 -1
- package/test/fixtures/shortcuts/event-lambda-defaults.json +1 -1
- package/test/fixtures/shortcuts/event-lambda-full.json +1 -1
- package/test/fixtures/shortcuts/firehose-defaults.json +1 -1
- package/test/fixtures/shortcuts/firehose-with-stream.json +1 -1
- package/test/fixtures/shortcuts/glue-database-defaults.json +1 -1
- package/test/fixtures/shortcuts/glue-database-no-defaults.json +1 -1
- package/test/fixtures/shortcuts/glue-iceberg-table-defaults.json +41 -0
- package/test/fixtures/shortcuts/glue-iceberg-table-no-defaults.json +39 -0
- package/test/fixtures/shortcuts/glue-iceberg-table-with-all-optimizers.json +101 -0
- package/test/fixtures/shortcuts/glue-iceberg-table-with-both-optimizers.json +80 -0
- package/test/fixtures/shortcuts/glue-iceberg-table-with-compaction-custom.json +68 -0
- package/test/fixtures/shortcuts/glue-iceberg-table-with-compaction-defaults.json +57 -0
- package/test/fixtures/shortcuts/glue-iceberg-table-with-optimizer-custom.json +75 -0
- package/test/fixtures/shortcuts/glue-iceberg-table-with-optimizer-defaults.json +64 -0
- package/test/fixtures/shortcuts/glue-iceberg-table-with-orphan-deletion-custom.json +74 -0
- package/test/fixtures/shortcuts/glue-iceberg-table-with-orphan-deletion-defaults.json +62 -0
- package/test/fixtures/shortcuts/glue-json-table-defaults.json +1 -1
- package/test/fixtures/shortcuts/glue-json-table-no-defaults.json +1 -1
- package/test/fixtures/shortcuts/glue-orc-table-defaults.json +1 -1
- package/test/fixtures/shortcuts/glue-orc-table-no-defaults.json +1 -1
- package/test/fixtures/shortcuts/glue-parquet-table-defaults.json +1 -1
- package/test/fixtures/shortcuts/glue-parquet-table-no-defaults.json +1 -1
- package/test/fixtures/shortcuts/glue-table-defaults.json +1 -1
- package/test/fixtures/shortcuts/glue-table-no-defaults.json +1 -1
- package/test/fixtures/shortcuts/glue-view-defaults.json +1 -1
- package/test/fixtures/shortcuts/glue-view-no-defaults.json +1 -1
- package/test/fixtures/shortcuts/hookshot-github-secret-ref.json +1 -1
- package/test/fixtures/shortcuts/hookshot-github-secret-string.json +1 -1
- package/test/fixtures/shortcuts/hookshot-github.json +1 -1
- package/test/fixtures/shortcuts/hookshot-passthrough-access-log-format.json +1 -1
- package/test/fixtures/shortcuts/hookshot-passthrough-alarms.json +1 -1
- package/test/fixtures/shortcuts/hookshot-passthrough-enhanced-logging.json +1 -1
- package/test/fixtures/shortcuts/hookshot-passthrough-full-blown-logging.json +1 -1
- package/test/fixtures/shortcuts/hookshot-passthrough-logging.json +1 -1
- package/test/fixtures/shortcuts/hookshot-passthrough.json +1 -1
- package/test/fixtures/shortcuts/lambda-defaults.json +1 -1
- package/test/fixtures/shortcuts/lambda-docker.json +1 -1
- package/test/fixtures/shortcuts/lambda-full.json +1 -1
- package/test/fixtures/shortcuts/lambda-provided-role.json +1 -1
- package/test/fixtures/shortcuts/lambda-zipfile.json +1 -1
- package/test/fixtures/shortcuts/log-subscription-lambda-defaults.json +1 -1
- package/test/fixtures/shortcuts/log-subscription-lambda-no-defaults.json +1 -1
- package/test/fixtures/shortcuts/queue-defaults.json +1 -1
- package/test/fixtures/shortcuts/queue-external-topic-ref.json +1 -1
- package/test/fixtures/shortcuts/queue-external-topic.json +1 -1
- package/test/fixtures/shortcuts/queue-fifo-queuename.json +1 -1
- package/test/fixtures/shortcuts/queue-fifo.json +1 -1
- package/test/fixtures/shortcuts/queue-full.json +1 -1
- package/test/fixtures/shortcuts/queue-lambda-zero.json +1 -1
- package/test/fixtures/shortcuts/queue-lambda.json +1 -1
- package/test/fixtures/shortcuts/role-defaults.json +1 -1
- package/test/fixtures/shortcuts/role-no-defaults.json +1 -1
- package/test/fixtures/shortcuts/scheduled-lambda-defaults.json +1 -1
- package/test/fixtures/shortcuts/scheduled-lambda-full.json +1 -1
- package/test/fixtures/shortcuts/service-role-defaults.json +1 -1
- package/test/fixtures/shortcuts/service-role-no-defaults.json +1 -1
- package/test/fixtures/shortcuts/service-role-no-url-suffix.json +1 -1
- package/test/fixtures/shortcuts/service-role-url-suffix-with-replacement.json +1 -1
- package/test/fixtures/shortcuts/service-role-url-suffix.json +1 -1
- package/test/fixtures/shortcuts/stream-lambda-defaults.json +1 -1
- package/test/fixtures/shortcuts/stream-lambda-no-defaults.json +1 -1
- package/test/index.test.js +383 -235
- package/test/shortcuts.test.js +1523 -1483
- package/.nyc_output/2b544c0b-2830-4ad0-97cd-8e661710b0bb.json +0 -1
- package/.nyc_output/65e58b48-bf1c-412d-8dd4-d7b564b12d76.json +0 -1
- package/.nyc_output/processinfo/2b544c0b-2830-4ad0-97cd-8e661710b0bb.json +0 -1
- package/.nyc_output/processinfo/65e58b48-bf1c-412d-8dd4-d7b564b12d76.json +0 -1
package/test/shortcuts.test.js
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
const cp = require('child_process');
|
|
4
4
|
const path = require('path');
|
|
5
5
|
const fs = require('fs');
|
|
6
|
-
const test = require('tape');
|
|
7
6
|
const cf = require('..');
|
|
8
7
|
const fixtures = require('./fixtures/shortcuts');
|
|
9
8
|
const util = require('util');
|
|
@@ -13,11 +12,16 @@ const update = !!process.env.UPDATE;
|
|
|
13
12
|
|
|
14
13
|
const noUndefined = (template) => JSON.parse(JSON.stringify(template));
|
|
15
14
|
|
|
16
|
-
|
|
15
|
+
describe('[shortcuts] fixture validation', () => {
|
|
17
16
|
// Runs cfn-lint, ignoring "warnings". Install via pip or Homebrew to run these
|
|
18
17
|
// tests locally.
|
|
19
|
-
const cfnLint = (filepath) => new Promise((resolve, reject) => {
|
|
20
|
-
|
|
18
|
+
const cfnLint = (filepath, filename) => new Promise((resolve, reject) => {
|
|
19
|
+
// Ignore E3003 (missing TableInput) and E3002 (unexpected properties) for Iceberg tables only
|
|
20
|
+
// cfn-lint doesn't yet support OpenTableFormatInput (Iceberg table format)
|
|
21
|
+
const isIcebergTable = filename.includes('glue-iceberg-table');
|
|
22
|
+
const ignoreChecks = isIcebergTable ? 'W,E3003,E3002' : 'W';
|
|
23
|
+
|
|
24
|
+
cp.execFile('cfn-lint', [filepath, '--ignore-checks', ignoreChecks], (err, stdout) => {
|
|
21
25
|
if (err) return reject(new Error(stdout));
|
|
22
26
|
return resolve();
|
|
23
27
|
});
|
|
@@ -27,36 +31,25 @@ test('[shortcuts] fixture validation', async (assert) => {
|
|
|
27
31
|
.readdirSync(path.join(__dirname, 'fixtures', 'shortcuts'))
|
|
28
32
|
.filter((filename) => path.extname(filename) === '.json');
|
|
29
33
|
|
|
30
|
-
|
|
31
|
-
const filename = toValidate.shift();
|
|
34
|
+
test.each(toValidate)('%s fixture passes validation', async (filename) => {
|
|
32
35
|
await Promise.all([
|
|
33
|
-
cfnLint(path.join(__dirname, 'fixtures', 'shortcuts', filename))
|
|
34
|
-
.then(() => assert.pass(`${filename} fixture passed validation`))
|
|
35
|
-
.catch((err) => {
|
|
36
|
-
assert.fail(`${filename} fixture fails validation`);
|
|
37
|
-
console.log(err.message);
|
|
38
|
-
}),
|
|
36
|
+
cfnLint(path.join(__dirname, 'fixtures', 'shortcuts', filename), filename),
|
|
39
37
|
sleep(1000)
|
|
40
38
|
]);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
assert.end();
|
|
39
|
+
});
|
|
44
40
|
});
|
|
45
41
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
() => new cf.shortcuts.Lambda()
|
|
49
|
-
|
|
50
|
-
'throws without options'
|
|
51
|
-
);
|
|
52
|
-
assert.throws(
|
|
53
|
-
() => new cf.shortcuts.Lambda({}),
|
|
54
|
-
/You must provide a LogicalName, and Code/,
|
|
55
|
-
'throws without required parameters'
|
|
56
|
-
);
|
|
42
|
+
describe('[shortcuts] lambda', () => {
|
|
43
|
+
test('throws without options', () => {
|
|
44
|
+
expect(() => new cf.shortcuts.Lambda()).toThrow('Options required');
|
|
45
|
+
});
|
|
57
46
|
|
|
58
|
-
|
|
59
|
-
() => new cf.shortcuts.Lambda({
|
|
47
|
+
test('throws without required parameters', () => {
|
|
48
|
+
expect(() => new cf.shortcuts.Lambda({})).toThrow(/You must provide a LogicalName, and Code/);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test('throws for RoleArn and Statements both provided', () => {
|
|
52
|
+
expect(() => new cf.shortcuts.Lambda({
|
|
60
53
|
LogicalName: 'MyLambda',
|
|
61
54
|
Code: {
|
|
62
55
|
S3Bucket: 'my-code-bucket',
|
|
@@ -68,469 +61,400 @@ test('[shortcuts] lambda', (assert) => {
|
|
|
68
61
|
Action: 's3:GetObject',
|
|
69
62
|
Resource: 'arn:aws:s3:::my-bucket/*'
|
|
70
63
|
}]
|
|
71
|
-
})
|
|
72
|
-
/You cannot specify both Statements and a RoleArn/,
|
|
73
|
-
'throws for RoleArn and Statements both provided'
|
|
74
|
-
);
|
|
75
|
-
|
|
76
|
-
let lambda = new cf.shortcuts.Lambda({
|
|
77
|
-
LogicalName: 'MyLambda',
|
|
78
|
-
Code: {
|
|
79
|
-
S3Bucket: 'my-code-bucket',
|
|
80
|
-
S3Key: 'path/to/code.zip'
|
|
81
|
-
}
|
|
64
|
+
})).toThrow(/You cannot specify both Statements and a RoleArn/);
|
|
82
65
|
});
|
|
83
66
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
67
|
+
test('expected resources generated using all default values', () => {
|
|
68
|
+
const lambda = new cf.shortcuts.Lambda({
|
|
69
|
+
LogicalName: 'MyLambda',
|
|
70
|
+
Code: {
|
|
71
|
+
S3Bucket: 'my-code-bucket',
|
|
72
|
+
S3Key: 'path/to/code.zip'
|
|
73
|
+
}
|
|
74
|
+
});
|
|
91
75
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
LogPolicyDeletionPolicy: 'Retain'
|
|
76
|
+
const template = cf.merge(lambda);
|
|
77
|
+
if (update) fixtures.update('lambda-defaults', template);
|
|
78
|
+
expect(noUndefined(template)).toEqual(fixtures.get('lambda-defaults'));
|
|
96
79
|
});
|
|
97
|
-
const templateWithRetain = cf.merge(lambdaWithRetain);
|
|
98
|
-
assert.equal(
|
|
99
|
-
templateWithRetain.Resources.MyLambdaLogPolicy.DeletionPolicy,
|
|
100
|
-
'Retain',
|
|
101
|
-
'LogPolicyDeletionPolicy=Retain sets DeletionPolicy on IAM Policy resource'
|
|
102
|
-
);
|
|
103
80
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
81
|
+
test('LogPolicyDeletionPolicy=Retain sets DeletionPolicy on IAM Policy resource', () => {
|
|
82
|
+
const lambdaWithRetain = new cf.shortcuts.Lambda({
|
|
83
|
+
LogicalName: 'MyLambda',
|
|
84
|
+
Code: { S3Bucket: 'my-code-bucket', S3Key: 'path/to/code.zip' },
|
|
85
|
+
LogPolicyDeletionPolicy: 'Retain'
|
|
86
|
+
});
|
|
87
|
+
const templateWithRetain = cf.merge(lambdaWithRetain);
|
|
88
|
+
expect(templateWithRetain.Resources.MyLambdaLogPolicy.DeletionPolicy).toBe('Retain');
|
|
109
89
|
});
|
|
110
90
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
91
|
+
test('expected resources generated using all default values and a docker image', () => {
|
|
92
|
+
const lambda = new cf.shortcuts.Lambda({
|
|
93
|
+
LogicalName: 'MyLambda',
|
|
94
|
+
Code: {
|
|
95
|
+
ImageUri: 'MyImage'
|
|
96
|
+
}
|
|
97
|
+
});
|
|
118
98
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
ZipFile: 'fake code'
|
|
123
|
-
}
|
|
99
|
+
const template = cf.merge(lambda);
|
|
100
|
+
if (update) fixtures.update('lambda-docker', template);
|
|
101
|
+
expect(noUndefined(template)).toEqual(fixtures.get('lambda-docker'));
|
|
124
102
|
});
|
|
125
103
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
104
|
+
test('expected resources generated using all default values and inline code', () => {
|
|
105
|
+
const lambda = new cf.shortcuts.Lambda({
|
|
106
|
+
LogicalName: 'MyLambda',
|
|
107
|
+
Code: {
|
|
108
|
+
ZipFile: 'fake code'
|
|
109
|
+
}
|
|
110
|
+
});
|
|
133
111
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
112
|
+
const template = cf.merge(lambda);
|
|
113
|
+
if (update) fixtures.update('lambda-zipfile', template);
|
|
114
|
+
expect(noUndefined(template)).toEqual(fixtures.get('lambda-zipfile'));
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test('expected resources generated if RoleArn provided', () => {
|
|
118
|
+
const lambda = new cf.shortcuts.Lambda({
|
|
119
|
+
LogicalName: 'MyLambda',
|
|
120
|
+
Code: {
|
|
121
|
+
S3Bucket: 'my-code-bucket',
|
|
122
|
+
S3Key: 'path/to/code.zip'
|
|
123
|
+
},
|
|
124
|
+
RoleArn: cf.getAtt('CustomLambdaRole', 'Arn')
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
const template = cf.merge(lambda, {
|
|
128
|
+
Resources: {
|
|
129
|
+
'CustomLambdaRole': {
|
|
130
|
+
Type: 'AWS::IAM::Role',
|
|
131
|
+
Properties: {
|
|
132
|
+
AssumeRolePolicyDocument: {}
|
|
133
|
+
}
|
|
149
134
|
}
|
|
150
135
|
}
|
|
151
|
-
}
|
|
136
|
+
});
|
|
137
|
+
if (update) fixtures.update('lambda-provided-role', template);
|
|
138
|
+
expect(noUndefined(template)).toEqual(fixtures.get('lambda-provided-role'));
|
|
152
139
|
});
|
|
153
|
-
if (update) fixtures.update('lambda-provided-role', template);
|
|
154
|
-
assert.deepEqual(
|
|
155
|
-
noUndefined(template),
|
|
156
|
-
fixtures.get('lambda-provided-role'),
|
|
157
|
-
'expected resources generated if RoleArn provided'
|
|
158
|
-
);
|
|
159
140
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
template = cf.merge(
|
|
210
|
-
{ Conditions: { Always: cf.equals('1', '1') } },
|
|
211
|
-
{ Resources: { AnotherThing: { Type: 'AWS::SNS::Topic' } } },
|
|
212
|
-
lambda
|
|
213
|
-
);
|
|
214
|
-
if (update) fixtures.update('lambda-full', template);
|
|
215
|
-
assert.deepEqual(
|
|
216
|
-
noUndefined(template),
|
|
217
|
-
fixtures.get('lambda-full'),
|
|
218
|
-
'expected resources generated using no default values'
|
|
219
|
-
);
|
|
141
|
+
test('expected resources generated using no default values', () => {
|
|
142
|
+
const lambda = new cf.shortcuts.Lambda({
|
|
143
|
+
LogicalName: 'MyLambda',
|
|
144
|
+
Code: {
|
|
145
|
+
S3Bucket: 'my-code-bucket',
|
|
146
|
+
S3Key: 'path/to/code.zip'
|
|
147
|
+
},
|
|
148
|
+
DeadLetterConfig: {
|
|
149
|
+
TargetArn: 'arn:aws:sqs:us-east-1:123456789012:queue/fake'
|
|
150
|
+
},
|
|
151
|
+
Description: 'my description',
|
|
152
|
+
Environment: { Variables: { MyCoolEnv: 'a' } },
|
|
153
|
+
FunctionName: 'my-function',
|
|
154
|
+
Handler: 'index.something',
|
|
155
|
+
KmsKeyArn: 'arn:aws:kms:us-east-1:123456789012:key/fake',
|
|
156
|
+
Layers: ['arn:aws:lambda:us-east-2:590474943231:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4'],
|
|
157
|
+
MemorySize: 512,
|
|
158
|
+
ReservedConcurrentExecutions: 10,
|
|
159
|
+
Runtime: 'nodejs22.x',
|
|
160
|
+
Tags: [{ Key: 'a', Value: 'b' }],
|
|
161
|
+
Timeout: 30,
|
|
162
|
+
TracingConfig: { Mode: 'Active' },
|
|
163
|
+
VpcConfig: {
|
|
164
|
+
SecurityGroupIds: ['sg-12345678'],
|
|
165
|
+
SubnetIds: ['fake']
|
|
166
|
+
},
|
|
167
|
+
Condition: 'Always',
|
|
168
|
+
DependsOn: 'AnotherThing',
|
|
169
|
+
Statement: [
|
|
170
|
+
{
|
|
171
|
+
Effect: 'Allow',
|
|
172
|
+
Action: 's3:GetObject',
|
|
173
|
+
Resource: 'arn:aws:s3:::fake/data'
|
|
174
|
+
}
|
|
175
|
+
],
|
|
176
|
+
AlarmName: 'my-alarm',
|
|
177
|
+
AlarmDescription: 'some alarm',
|
|
178
|
+
AlarmActions: ['devnull@mapbox.com'],
|
|
179
|
+
Period: 120,
|
|
180
|
+
EvaluationPeriods: 2,
|
|
181
|
+
Statistic: 'Minimum',
|
|
182
|
+
Threshold: 10,
|
|
183
|
+
ComparisonOperator: 'LessThanThreshold',
|
|
184
|
+
TreatMissingData: 'breaching',
|
|
185
|
+
EvaluateLowSampleCountPercentile: 'ignore',
|
|
186
|
+
ExtendedStatistics: 'p100',
|
|
187
|
+
OKActions: ['devnull@mapbox.com'],
|
|
188
|
+
LogRetentionInDays: 30
|
|
189
|
+
});
|
|
220
190
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
191
|
+
const template = cf.merge(
|
|
192
|
+
{ Conditions: { Always: cf.equals('1', '1') } },
|
|
193
|
+
{ Resources: { AnotherThing: { Type: 'AWS::SNS::Topic' } } },
|
|
194
|
+
lambda
|
|
195
|
+
);
|
|
196
|
+
if (update) fixtures.update('lambda-full', template);
|
|
197
|
+
expect(noUndefined(template)).toEqual(fixtures.get('lambda-full'));
|
|
228
198
|
});
|
|
229
199
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
200
|
+
test('LogPolicyName parameter correctly overrides the default policy name', () => {
|
|
201
|
+
const lambda = new cf.shortcuts.Lambda({
|
|
202
|
+
LogicalName: 'MyLambda',
|
|
203
|
+
Code: {
|
|
204
|
+
S3Bucket: 'my-code-bucket',
|
|
205
|
+
S3Key: 'path/to/code.zip'
|
|
206
|
+
},
|
|
207
|
+
LogPolicyName: 'CustomLogPolicyName'
|
|
208
|
+
});
|
|
236
209
|
|
|
237
|
-
|
|
210
|
+
const template = cf.merge(lambda);
|
|
211
|
+
expect(template.Resources.MyLambdaLogPolicy.Properties.PolicyName).toBe('CustomLogPolicyName');
|
|
212
|
+
});
|
|
238
213
|
});
|
|
239
214
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
() => new cf.shortcuts.QueueLambda()
|
|
243
|
-
|
|
244
|
-
'throws without options'
|
|
245
|
-
);
|
|
246
|
-
assert.throws(
|
|
247
|
-
() => new cf.shortcuts.QueueLambda({}),
|
|
248
|
-
/You must provide a LogicalName, and Code/,
|
|
249
|
-
'throws without basic lambda required parameters'
|
|
250
|
-
);
|
|
215
|
+
describe('[shortcuts] queue-lambda', () => {
|
|
216
|
+
test('throws without options', () => {
|
|
217
|
+
expect(() => new cf.shortcuts.QueueLambda()).toThrow('Options required');
|
|
218
|
+
});
|
|
251
219
|
|
|
252
|
-
|
|
253
|
-
() =>
|
|
254
|
-
|
|
255
|
-
LogicalName: 'MyLambda',
|
|
256
|
-
Code: {
|
|
257
|
-
S3Bucket: 'my-code-bucket',
|
|
258
|
-
S3Key: 'path/to/code.zip'
|
|
259
|
-
}
|
|
260
|
-
}),
|
|
261
|
-
/You must provide an EventSourceArn and ReservedConcurrentExecutions/,
|
|
262
|
-
'throws without queue-lambda required parameters'
|
|
263
|
-
);
|
|
220
|
+
test('throws without basic lambda required parameters', () => {
|
|
221
|
+
expect(() => new cf.shortcuts.QueueLambda({})).toThrow(/You must provide a LogicalName, and Code/);
|
|
222
|
+
});
|
|
264
223
|
|
|
265
|
-
|
|
266
|
-
() =>
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
ReservedConcurrentExecutions: -1
|
|
275
|
-
}),
|
|
276
|
-
/ReservedConcurrentExecutions must be greater than or equal to 0/,
|
|
277
|
-
'throws when ReservedConcurrentExecutions is a negative number'
|
|
278
|
-
);
|
|
224
|
+
test('throws without queue-lambda required parameters', () => {
|
|
225
|
+
expect(() => new cf.shortcuts.QueueLambda({
|
|
226
|
+
LogicalName: 'MyLambda',
|
|
227
|
+
Code: {
|
|
228
|
+
S3Bucket: 'my-code-bucket',
|
|
229
|
+
S3Key: 'path/to/code.zip'
|
|
230
|
+
}
|
|
231
|
+
})).toThrow(/You must provide an EventSourceArn and ReservedConcurrentExecutions/);
|
|
232
|
+
});
|
|
279
233
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
assert.deepEqual(
|
|
292
|
-
noUndefined(zeroTemplate),
|
|
293
|
-
fixtures.get('queue-lambda-zero'),
|
|
294
|
-
'expected resources generated'
|
|
295
|
-
);
|
|
234
|
+
test('throws when ReservedConcurrentExecutions is a negative number', () => {
|
|
235
|
+
expect(() => new cf.shortcuts.QueueLambda({
|
|
236
|
+
LogicalName: 'MyLambda',
|
|
237
|
+
Code: {
|
|
238
|
+
S3Bucket: 'my-code-bucket',
|
|
239
|
+
S3Key: 'path/to/code.zip'
|
|
240
|
+
},
|
|
241
|
+
EventSourceArn: 'arn:aws:sqs:us-east-1:123456789012:queue/fake',
|
|
242
|
+
ReservedConcurrentExecutions: -1
|
|
243
|
+
})).toThrow(/ReservedConcurrentExecutions must be greater than or equal to 0/);
|
|
244
|
+
});
|
|
296
245
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
246
|
+
test('expected resources generated with zero concurrency', () => {
|
|
247
|
+
const zeroLambda = new cf.shortcuts.QueueLambda({
|
|
248
|
+
LogicalName: 'MyLambda',
|
|
249
|
+
Code: {
|
|
250
|
+
S3Bucket: 'my-code-bucket',
|
|
251
|
+
S3Key: 'path/to/code.zip'
|
|
252
|
+
},
|
|
253
|
+
EventSourceArn: 'arn:aws:sqs:us-east-1:123456789012:queue/fake',
|
|
254
|
+
ReservedConcurrentExecutions: 0
|
|
255
|
+
});
|
|
256
|
+
const zeroTemplate = cf.merge(zeroLambda);
|
|
257
|
+
if (update) fixtures.update('queue-lambda-zero', zeroTemplate);
|
|
258
|
+
expect(noUndefined(zeroTemplate)).toEqual(fixtures.get('queue-lambda-zero'));
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
test('expected resources generated', () => {
|
|
262
|
+
const lambda = new cf.shortcuts.QueueLambda({
|
|
263
|
+
LogicalName: 'MyLambda',
|
|
264
|
+
Code: {
|
|
265
|
+
S3Bucket: 'my-code-bucket',
|
|
266
|
+
S3Key: 'path/to/code.zip'
|
|
267
|
+
},
|
|
268
|
+
EventSourceArn: 'arn:aws:sqs:us-east-1:123456789012:queue/fake',
|
|
269
|
+
ReservedConcurrentExecutions: 10
|
|
270
|
+
});
|
|
314
271
|
|
|
315
|
-
|
|
272
|
+
const template = cf.merge(lambda);
|
|
273
|
+
if (update) fixtures.update('queue-lambda', template);
|
|
274
|
+
expect(noUndefined(template)).toEqual(fixtures.get('queue-lambda'));
|
|
275
|
+
});
|
|
316
276
|
});
|
|
317
277
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
() => new cf.shortcuts.ScheduledLambda()
|
|
321
|
-
|
|
322
|
-
'throws without options'
|
|
323
|
-
);
|
|
324
|
-
assert.throws(
|
|
325
|
-
() => new cf.shortcuts.ScheduledLambda({}),
|
|
326
|
-
/You must provide a LogicalName, and Code/,
|
|
327
|
-
'throws without basic lambda required parameters'
|
|
328
|
-
);
|
|
278
|
+
describe('[shortcuts] scheduled-lambda', () => {
|
|
279
|
+
test('throws without options', () => {
|
|
280
|
+
expect(() => new cf.shortcuts.ScheduledLambda()).toThrow('Options required');
|
|
281
|
+
});
|
|
329
282
|
|
|
330
|
-
|
|
331
|
-
() =>
|
|
332
|
-
|
|
333
|
-
LogicalName: 'MyLambda',
|
|
334
|
-
Code: {
|
|
335
|
-
S3Bucket: 'my-code-bucket',
|
|
336
|
-
S3Key: 'path/to/code.zip'
|
|
337
|
-
}
|
|
338
|
-
}),
|
|
339
|
-
/You must provide a ScheduleExpression/,
|
|
340
|
-
'throws without scheduled-lambda required parameters'
|
|
341
|
-
);
|
|
283
|
+
test('throws without basic lambda required parameters', () => {
|
|
284
|
+
expect(() => new cf.shortcuts.ScheduledLambda({})).toThrow(/You must provide a LogicalName, and Code/);
|
|
285
|
+
});
|
|
342
286
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
let template = cf.merge(lambda);
|
|
353
|
-
if (update) fixtures.update('scheduled-lambda-defaults', template);
|
|
354
|
-
assert.deepEqual(
|
|
355
|
-
noUndefined(template),
|
|
356
|
-
fixtures.get('scheduled-lambda-defaults'),
|
|
357
|
-
'expected resources generated with defaults'
|
|
358
|
-
);
|
|
287
|
+
test('throws without scheduled-lambda required parameters', () => {
|
|
288
|
+
expect(() => new cf.shortcuts.ScheduledLambda({
|
|
289
|
+
LogicalName: 'MyLambda',
|
|
290
|
+
Code: {
|
|
291
|
+
S3Bucket: 'my-code-bucket',
|
|
292
|
+
S3Key: 'path/to/code.zip'
|
|
293
|
+
}
|
|
294
|
+
})).toThrow(/You must provide a ScheduleExpression/);
|
|
295
|
+
});
|
|
359
296
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
297
|
+
test('expected resources generated with defaults', () => {
|
|
298
|
+
const lambda = new cf.shortcuts.ScheduledLambda({
|
|
299
|
+
LogicalName: 'MyLambda',
|
|
300
|
+
Code: {
|
|
301
|
+
S3Bucket: 'my-code-bucket',
|
|
302
|
+
S3Key: 'path/to/code.zip'
|
|
303
|
+
},
|
|
304
|
+
ScheduleExpression: 'rate(1 hour)'
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
const template = cf.merge(lambda);
|
|
308
|
+
if (update) fixtures.update('scheduled-lambda-defaults', template);
|
|
309
|
+
expect(noUndefined(template)).toEqual(fixtures.get('scheduled-lambda-defaults'));
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
test('expected resources generated without defaults', () => {
|
|
313
|
+
const lambda = new cf.shortcuts.ScheduledLambda({
|
|
314
|
+
LogicalName: 'MyLambda',
|
|
315
|
+
Code: {
|
|
316
|
+
S3Bucket: 'my-code-bucket',
|
|
317
|
+
S3Key: 'path/to/code.zip'
|
|
318
|
+
},
|
|
319
|
+
ScheduleRoleArn: 'arn:aws:iam::012345678901:role/MyCoolRole',
|
|
320
|
+
ScheduleGroupName: 'my-cool-stack',
|
|
321
|
+
ScheduleExpression: 'rate(1 hour)',
|
|
322
|
+
State: 'DISABLED'
|
|
323
|
+
});
|
|
379
324
|
|
|
380
|
-
|
|
325
|
+
const template = cf.merge(lambda);
|
|
326
|
+
if (update) fixtures.update('scheduled-lambda-full', template);
|
|
327
|
+
expect(noUndefined(template)).toEqual(fixtures.get('scheduled-lambda-full'));
|
|
328
|
+
});
|
|
381
329
|
});
|
|
382
330
|
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
() => new cf.shortcuts.EventLambda()
|
|
386
|
-
|
|
387
|
-
'throws without options'
|
|
388
|
-
);
|
|
389
|
-
assert.throws(
|
|
390
|
-
() => new cf.shortcuts.EventLambda({}),
|
|
391
|
-
/You must provide a LogicalName, and Code/,
|
|
392
|
-
'throws without basic lambda required parameters'
|
|
393
|
-
);
|
|
331
|
+
describe('[shortcuts] event-lambda', () => {
|
|
332
|
+
test('throws without options', () => {
|
|
333
|
+
expect(() => new cf.shortcuts.EventLambda()).toThrow('Options required');
|
|
334
|
+
});
|
|
394
335
|
|
|
395
|
-
|
|
396
|
-
() =>
|
|
397
|
-
|
|
398
|
-
LogicalName: 'MyLambda',
|
|
399
|
-
Code: {
|
|
400
|
-
S3Bucket: 'my-code-bucket',
|
|
401
|
-
S3Key: 'path/to/code.zip'
|
|
402
|
-
}
|
|
403
|
-
}),
|
|
404
|
-
/You must provide an EventPattern/,
|
|
405
|
-
'throws without event-lambda required parameters'
|
|
406
|
-
);
|
|
336
|
+
test('throws without basic lambda required parameters', () => {
|
|
337
|
+
expect(() => new cf.shortcuts.EventLambda({})).toThrow(/You must provide a LogicalName, and Code/);
|
|
338
|
+
});
|
|
407
339
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
EventPattern: {
|
|
415
|
-
source: ['aws.ec2'],
|
|
416
|
-
'detail-type': ['EC2 Instance State-change Notification'],
|
|
417
|
-
detail: {
|
|
418
|
-
state: ['running']
|
|
340
|
+
test('throws without event-lambda required parameters', () => {
|
|
341
|
+
expect(() => new cf.shortcuts.EventLambda({
|
|
342
|
+
LogicalName: 'MyLambda',
|
|
343
|
+
Code: {
|
|
344
|
+
S3Bucket: 'my-code-bucket',
|
|
345
|
+
S3Key: 'path/to/code.zip'
|
|
419
346
|
}
|
|
420
|
-
}
|
|
347
|
+
})).toThrow(/You must provide an EventPattern/);
|
|
421
348
|
});
|
|
422
349
|
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
},
|
|
437
|
-
EventPattern: {
|
|
438
|
-
source: ['aws.ec2'],
|
|
439
|
-
'detail-type': ['EC2 Instance State-change Notification'],
|
|
440
|
-
detail: {
|
|
441
|
-
state: ['running']
|
|
350
|
+
test('expected resources generated with defaults', () => {
|
|
351
|
+
const lambda = new cf.shortcuts.EventLambda({
|
|
352
|
+
LogicalName: 'MyLambda',
|
|
353
|
+
Code: {
|
|
354
|
+
S3Bucket: 'my-code-bucket',
|
|
355
|
+
S3Key: 'path/to/code.zip'
|
|
356
|
+
},
|
|
357
|
+
EventPattern: {
|
|
358
|
+
source: ['aws.ec2'],
|
|
359
|
+
'detail-type': ['EC2 Instance State-change Notification'],
|
|
360
|
+
detail: {
|
|
361
|
+
state: ['running']
|
|
362
|
+
}
|
|
442
363
|
}
|
|
443
|
-
}
|
|
444
|
-
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
const template = cf.merge(lambda);
|
|
367
|
+
if (update) fixtures.update('event-lambda-defaults', template);
|
|
368
|
+
expect(noUndefined(template)).toEqual(fixtures.get('event-lambda-defaults'));
|
|
445
369
|
});
|
|
446
370
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
371
|
+
test('expected resources generated without defaults', () => {
|
|
372
|
+
const lambda = new cf.shortcuts.EventLambda({
|
|
373
|
+
LogicalName: 'MyLambda',
|
|
374
|
+
Code: {
|
|
375
|
+
S3Bucket: 'my-code-bucket',
|
|
376
|
+
S3Key: 'path/to/code.zip'
|
|
377
|
+
},
|
|
378
|
+
EventPattern: {
|
|
379
|
+
source: ['aws.ec2'],
|
|
380
|
+
'detail-type': ['EC2 Instance State-change Notification'],
|
|
381
|
+
detail: {
|
|
382
|
+
state: ['running']
|
|
383
|
+
}
|
|
384
|
+
},
|
|
385
|
+
State: 'DISABLED'
|
|
386
|
+
});
|
|
454
387
|
|
|
455
|
-
|
|
388
|
+
const template = cf.merge(lambda);
|
|
389
|
+
if (update) fixtures.update('event-lambda-full', template);
|
|
390
|
+
expect(noUndefined(template)).toEqual(fixtures.get('event-lambda-full'));
|
|
391
|
+
});
|
|
456
392
|
});
|
|
457
393
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
() => new cf.shortcuts.StreamLambda()
|
|
461
|
-
|
|
462
|
-
'throws without options'
|
|
463
|
-
);
|
|
464
|
-
assert.throws(
|
|
465
|
-
() => new cf.shortcuts.StreamLambda({}),
|
|
466
|
-
/You must provide a LogicalName, and Code/,
|
|
467
|
-
'throws without basic lambda required parameters'
|
|
468
|
-
);
|
|
394
|
+
describe('[shortcuts] stream-lambda', () => {
|
|
395
|
+
test('throws without options', () => {
|
|
396
|
+
expect(() => new cf.shortcuts.StreamLambda()).toThrow('Options required');
|
|
397
|
+
});
|
|
469
398
|
|
|
470
|
-
|
|
471
|
-
() =>
|
|
472
|
-
|
|
473
|
-
LogicalName: 'MyLambda',
|
|
474
|
-
Code: {
|
|
475
|
-
S3Bucket: 'my-code-bucket',
|
|
476
|
-
S3Key: 'path/to/code.zip'
|
|
477
|
-
}
|
|
478
|
-
}),
|
|
479
|
-
/You must provide an EventSourceArn/,
|
|
480
|
-
'throws without stream-lambda required parameters'
|
|
481
|
-
);
|
|
399
|
+
test('throws without basic lambda required parameters', () => {
|
|
400
|
+
expect(() => new cf.shortcuts.StreamLambda({})).toThrow(/You must provide a LogicalName, and Code/);
|
|
401
|
+
});
|
|
482
402
|
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
let template = cf.merge(lambda);
|
|
493
|
-
if (update) fixtures.update('stream-lambda-defaults', template);
|
|
494
|
-
assert.deepEqual(
|
|
495
|
-
noUndefined(template),
|
|
496
|
-
fixtures.get('stream-lambda-defaults'),
|
|
497
|
-
'expected resources generated via defaults'
|
|
498
|
-
);
|
|
403
|
+
test('throws without stream-lambda required parameters', () => {
|
|
404
|
+
expect(() => new cf.shortcuts.StreamLambda({
|
|
405
|
+
LogicalName: 'MyLambda',
|
|
406
|
+
Code: {
|
|
407
|
+
S3Bucket: 'my-code-bucket',
|
|
408
|
+
S3Key: 'path/to/code.zip'
|
|
409
|
+
}
|
|
410
|
+
})).toThrow(/You must provide an EventSourceArn/);
|
|
411
|
+
});
|
|
499
412
|
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
413
|
+
test('expected resources generated via defaults', () => {
|
|
414
|
+
const lambda = new cf.shortcuts.StreamLambda({
|
|
415
|
+
LogicalName: 'MyLambda',
|
|
416
|
+
Code: {
|
|
417
|
+
S3Bucket: 'my-code-bucket',
|
|
418
|
+
S3Key: 'path/to/code.zip'
|
|
419
|
+
},
|
|
420
|
+
EventSourceArn: 'arn:aws:kinesis:us-east-1:123456789012:stream/fake'
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
const template = cf.merge(lambda);
|
|
424
|
+
if (update) fixtures.update('stream-lambda-defaults', template);
|
|
425
|
+
expect(noUndefined(template)).toEqual(fixtures.get('stream-lambda-defaults'));
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
test('expected resources generated without defaults', () => {
|
|
429
|
+
const lambda = new cf.shortcuts.StreamLambda({
|
|
430
|
+
LogicalName: 'MyLambda',
|
|
431
|
+
Code: {
|
|
432
|
+
S3Bucket: 'my-code-bucket',
|
|
433
|
+
S3Key: 'path/to/code.zip'
|
|
434
|
+
},
|
|
435
|
+
EventSourceArn: 'arn:aws:kinesis:us-east-1:123456789012:stream/fake',
|
|
436
|
+
FilterCriteria: {
|
|
437
|
+
Filters: [
|
|
438
|
+
{
|
|
439
|
+
Pattern: JSON.stringify({ eventName: ['INSERT', 'MODIFY'] })
|
|
440
|
+
}
|
|
441
|
+
]
|
|
442
|
+
},
|
|
443
|
+
BatchSize: 10000,
|
|
444
|
+
MaximumBatchingWindowInSeconds: 300,
|
|
445
|
+
Enabled: false,
|
|
446
|
+
StartingPosition: 'TRIM_HORIZON'
|
|
447
|
+
});
|
|
527
448
|
|
|
528
|
-
|
|
449
|
+
const template = cf.merge(lambda);
|
|
450
|
+
if (update) fixtures.update('stream-lambda-no-defaults', template);
|
|
451
|
+
expect(noUndefined(template)).toEqual(fixtures.get('stream-lambda-no-defaults'));
|
|
452
|
+
});
|
|
529
453
|
});
|
|
530
454
|
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
() => new cf.shortcuts.StreamLambda({
|
|
455
|
+
describe('[shortcuts] StreamLambda FilterCriteria', () => {
|
|
456
|
+
test('FilterCriteria must be a JSON-like object', () => {
|
|
457
|
+
expect(() => new cf.shortcuts.StreamLambda({
|
|
534
458
|
LogicalName: 'MyLambda',
|
|
535
459
|
Code: {
|
|
536
460
|
S3Bucket: 'my-code-bucket',
|
|
@@ -538,11 +462,11 @@ test('[shortcuts] StreamLambda FilterCriteria', (assert) => {
|
|
|
538
462
|
},
|
|
539
463
|
EventSourceArn: 'arn:aws:kinesis:us-east-1:123456789012:stream/fake',
|
|
540
464
|
FilterCriteria: ['test']
|
|
541
|
-
})
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
() => new cf.shortcuts.StreamLambda({
|
|
465
|
+
})).toThrow();
|
|
466
|
+
});
|
|
467
|
+
|
|
468
|
+
test('FilterCriteria must contain property Filter of type array', () => {
|
|
469
|
+
expect(() => new cf.shortcuts.StreamLambda({
|
|
546
470
|
LogicalName: 'MyLambda',
|
|
547
471
|
Code: {
|
|
548
472
|
S3Bucket: 'my-code-bucket',
|
|
@@ -550,11 +474,11 @@ test('[shortcuts] StreamLambda FilterCriteria', (assert) => {
|
|
|
550
474
|
},
|
|
551
475
|
EventSourceArn: 'arn:aws:kinesis:us-east-1:123456789012:stream/fake',
|
|
552
476
|
FilterCriteria: {}
|
|
553
|
-
})
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
() => new cf.shortcuts.StreamLambda({
|
|
477
|
+
})).toThrow();
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
test('FilterCriteria.Filter must be an array', () => {
|
|
481
|
+
expect(() => new cf.shortcuts.StreamLambda({
|
|
558
482
|
LogicalName: 'MyLambda',
|
|
559
483
|
Code: {
|
|
560
484
|
S3Bucket: 'my-code-bucket',
|
|
@@ -564,11 +488,11 @@ test('[shortcuts] StreamLambda FilterCriteria', (assert) => {
|
|
|
564
488
|
FilterCriteria: {
|
|
565
489
|
Filter: 613
|
|
566
490
|
}
|
|
567
|
-
})
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
() => new cf.shortcuts.StreamLambda({
|
|
491
|
+
})).toThrow();
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
test('FilterCriteria.Filter objects must have Pattern property', () => {
|
|
495
|
+
expect(() => new cf.shortcuts.StreamLambda({
|
|
572
496
|
LogicalName: 'MyLambda',
|
|
573
497
|
Code: {
|
|
574
498
|
S3Bucket: 'my-code-bucket',
|
|
@@ -585,11 +509,11 @@ test('[shortcuts] StreamLambda FilterCriteria', (assert) => {
|
|
|
585
509
|
}
|
|
586
510
|
]
|
|
587
511
|
}
|
|
588
|
-
})
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
() => new cf.shortcuts.StreamLambda({
|
|
512
|
+
})).toThrow();
|
|
513
|
+
});
|
|
514
|
+
|
|
515
|
+
test('FilterCriteria.Filter Pattern must be JSON parseable string', () => {
|
|
516
|
+
expect(() => new cf.shortcuts.StreamLambda({
|
|
593
517
|
LogicalName: 'MyLambda',
|
|
594
518
|
Code: {
|
|
595
519
|
S3Bucket: 'my-code-bucket',
|
|
@@ -606,930 +530,1084 @@ test('[shortcuts] StreamLambda FilterCriteria', (assert) => {
|
|
|
606
530
|
}
|
|
607
531
|
]
|
|
608
532
|
}
|
|
609
|
-
})
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
533
|
+
})).toThrow();
|
|
534
|
+
});
|
|
535
|
+
});
|
|
536
|
+
|
|
537
|
+
describe('[shortcuts] log-subscription-lambda', () => {
|
|
538
|
+
test('throws without options', () => {
|
|
539
|
+
expect(() => new cf.shortcuts.LogSubscriptionLambda()).toThrow('Options required');
|
|
540
|
+
});
|
|
541
|
+
|
|
542
|
+
test('throws without basic lambda required parameters', () => {
|
|
543
|
+
expect(() => new cf.shortcuts.LogSubscriptionLambda({})).toThrow(/You must provide a LogicalName, and Code/);
|
|
544
|
+
});
|
|
545
|
+
|
|
546
|
+
test('throws without log-subscription-lambda required parameters', () => {
|
|
547
|
+
expect(() => new cf.shortcuts.LogSubscriptionLambda({
|
|
548
|
+
LogicalName: 'MyLambda',
|
|
549
|
+
Code: {
|
|
550
|
+
S3Bucket: 'my-code-bucket',
|
|
551
|
+
S3Key: 'path/to/code.zip'
|
|
552
|
+
}
|
|
553
|
+
})).toThrow(/You must provide a LogGroupName/);
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
test('expected resources generated via defaults', () => {
|
|
557
|
+
const lambda = new cf.shortcuts.LogSubscriptionLambda({
|
|
558
|
+
LogicalName: 'MyLambda',
|
|
559
|
+
Code: {
|
|
560
|
+
S3Bucket: 'my-code-bucket',
|
|
561
|
+
S3Key: 'path/to/code.zip'
|
|
562
|
+
},
|
|
563
|
+
LogGroupName: 'my-log-group'
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
const template = cf.merge(lambda);
|
|
567
|
+
if (update) fixtures.update('log-subscription-lambda-defaults', template);
|
|
568
|
+
expect(noUndefined(template)).toEqual(fixtures.get('log-subscription-lambda-defaults'));
|
|
569
|
+
});
|
|
570
|
+
|
|
571
|
+
test('expected resources generated without defaults', () => {
|
|
572
|
+
const lambda = new cf.shortcuts.LogSubscriptionLambda({
|
|
573
|
+
LogicalName: 'MyLambda',
|
|
574
|
+
Code: {
|
|
575
|
+
S3Bucket: 'my-code-bucket',
|
|
576
|
+
S3Key: 'path/to/code.zip'
|
|
577
|
+
},
|
|
578
|
+
FilterPattern: '{ $.errorCode = 400 }',
|
|
579
|
+
LogGroupName: 'my-log-group'
|
|
580
|
+
});
|
|
581
|
+
|
|
582
|
+
const template = cf.merge(lambda);
|
|
583
|
+
if (update) fixtures.update('log-subscription-lambda-no-defaults', template);
|
|
584
|
+
expect(noUndefined(template)).toEqual(fixtures.get('log-subscription-lambda-no-defaults'));
|
|
585
|
+
});
|
|
586
|
+
});
|
|
587
|
+
|
|
588
|
+
describe('[shortcuts] queue', () => {
|
|
589
|
+
test('throws without options', () => {
|
|
590
|
+
expect(() => new cf.shortcuts.Queue()).toThrow('Options required');
|
|
591
|
+
});
|
|
592
|
+
|
|
593
|
+
test('throws without required parameters', () => {
|
|
594
|
+
expect(() => new cf.shortcuts.Queue({})).toThrow(/You must provide a LogicalName/);
|
|
595
|
+
});
|
|
596
|
+
|
|
597
|
+
test('expected resources generated for full defaults', () => {
|
|
598
|
+
const queue = new cf.shortcuts.Queue({
|
|
599
|
+
LogicalName: 'MyQueue'
|
|
600
|
+
});
|
|
601
|
+
|
|
602
|
+
const template = cf.merge(queue);
|
|
603
|
+
if (update) fixtures.update('queue-defaults', template);
|
|
604
|
+
expect(noUndefined(template)).toEqual(fixtures.get('queue-defaults'));
|
|
605
|
+
});
|
|
606
|
+
|
|
607
|
+
test('expected resources generated no defaults', () => {
|
|
608
|
+
const queue = new cf.shortcuts.Queue({
|
|
609
|
+
LogicalName: 'MyQueue',
|
|
610
|
+
VisibilityTimeout: 60,
|
|
611
|
+
maxReceiveCount: 100,
|
|
612
|
+
DelaySeconds: 60,
|
|
613
|
+
KmsMasterKeyId: 'alias/my-key',
|
|
614
|
+
KmsDataKeyReusePeriondSeconds: 86400,
|
|
615
|
+
MaximumMessageSize: 1024,
|
|
616
|
+
MessageRetentionPeriod: 60,
|
|
617
|
+
QueueName: 'my-queue',
|
|
618
|
+
ReceiveMessageWaitTimeSeconds: 20,
|
|
619
|
+
Condition: 'Always',
|
|
620
|
+
DependsOn: 'AnotherThing',
|
|
621
|
+
TopicName: 'my-topic',
|
|
622
|
+
DisplayName: 'topic-display-name',
|
|
623
|
+
DeadLetterVisibilityTimeout: 60
|
|
624
|
+
});
|
|
625
|
+
|
|
626
|
+
const template = cf.merge(
|
|
627
|
+
{ Conditions: { Always: cf.equals('1', '1') } },
|
|
628
|
+
{ Resources: { AnotherThing: { Type: 'AWS::SNS::Topic' } } },
|
|
629
|
+
queue
|
|
630
|
+
);
|
|
631
|
+
if (update) fixtures.update('queue-full', template);
|
|
632
|
+
expect(noUndefined(template)).toEqual(fixtures.get('queue-full'));
|
|
633
|
+
});
|
|
634
|
+
|
|
635
|
+
test('expected resources generated for external topic', () => {
|
|
636
|
+
const queue = new cf.shortcuts.Queue({
|
|
637
|
+
LogicalName: 'MyQueue',
|
|
638
|
+
ExistingTopicArn: 'arn:aws:sns:us-east-1:111122223333:MyTopic'
|
|
639
|
+
});
|
|
640
|
+
const template = cf.merge(queue);
|
|
641
|
+
if (update) fixtures.update('queue-external-topic', template);
|
|
642
|
+
expect(noUndefined(template)).toEqual(fixtures.get('queue-external-topic'));
|
|
643
|
+
});
|
|
644
|
+
|
|
645
|
+
test('expected resources generated for external topic identified by ref', () => {
|
|
646
|
+
const queue = new cf.shortcuts.Queue({
|
|
647
|
+
LogicalName: 'MyQueue',
|
|
648
|
+
ExistingTopicArn: { Ref: 'TopicForOtherThing' }
|
|
649
|
+
});
|
|
650
|
+
const template = cf.merge(
|
|
651
|
+
{ Resources: { TopicForOtherThing: { Type: 'AWS::SNS::Topic' } } },
|
|
652
|
+
queue
|
|
653
|
+
);
|
|
654
|
+
if (update) fixtures.update('queue-external-topic-ref', template);
|
|
655
|
+
expect(noUndefined(template)).toEqual(fixtures.get('queue-external-topic-ref'));
|
|
656
|
+
});
|
|
657
|
+
|
|
658
|
+
test('expected resources generated for FIFO queue', () => {
|
|
659
|
+
const queue = new cf.shortcuts.Queue({
|
|
660
|
+
LogicalName: 'MyFifoQueue',
|
|
661
|
+
FifoQueue: true
|
|
662
|
+
});
|
|
663
|
+
const template = cf.merge(queue);
|
|
664
|
+
if (update) fixtures.update('queue-fifo', template);
|
|
665
|
+
expect(noUndefined(template)).toEqual(fixtures.get('queue-fifo'));
|
|
666
|
+
});
|
|
667
|
+
|
|
668
|
+
test('expected resources generated for FIFO queue with specified QueueName', () => {
|
|
669
|
+
const queue = new cf.shortcuts.Queue({
|
|
670
|
+
LogicalName: 'MyFifoQueue',
|
|
671
|
+
QueueName: 'custom-and-fancy',
|
|
672
|
+
FifoQueue: true
|
|
673
|
+
});
|
|
674
|
+
const template = cf.merge(queue);
|
|
675
|
+
if (update) fixtures.update('queue-fifo-queuename', template);
|
|
676
|
+
expect(noUndefined(template)).toEqual(fixtures.get('queue-fifo-queuename'));
|
|
677
|
+
});
|
|
678
|
+
|
|
679
|
+
test('the FifoQueue value false is converted to undefined, to pass CFN validation', () => {
|
|
680
|
+
const queue = new cf.shortcuts.Queue({
|
|
681
|
+
LogicalName: 'MyFifoFalseQueue',
|
|
682
|
+
FifoQueue: false
|
|
683
|
+
});
|
|
684
|
+
const template = cf.merge(queue);
|
|
685
|
+
expect(template.Resources.MyFifoFalseQueue.Properties.FifoQueue).toBeUndefined();
|
|
686
|
+
});
|
|
687
|
+
});
|
|
688
|
+
|
|
689
|
+
describe('[shortcuts] s3 kinesis firehose', () => {
|
|
690
|
+
test('throws without options', () => {
|
|
691
|
+
expect(() => new cf.shortcuts.S3KinesisFirehose()).toThrow('Options required');
|
|
692
|
+
});
|
|
693
|
+
|
|
694
|
+
test('throws without required LogicalName parameter', () => {
|
|
695
|
+
expect(() => new cf.shortcuts.S3KinesisFirehose({})).toThrow(/You must provide a LogicalName/);
|
|
696
|
+
});
|
|
697
|
+
|
|
698
|
+
test('throws without required DestinationBucket parameter', () => {
|
|
699
|
+
expect(() => new cf.shortcuts.S3KinesisFirehose({
|
|
700
|
+
LogicalName: 'MyKinesisFirehose'
|
|
701
|
+
})).toThrow(/You must provide a DestinationBucket/);
|
|
702
|
+
});
|
|
703
|
+
|
|
704
|
+
test('expected resources generated for full defaults', () => {
|
|
705
|
+
const firehose = new cf.shortcuts.S3KinesisFirehose({
|
|
706
|
+
LogicalName: 'MyKinesisFirehose',
|
|
707
|
+
DestinationBucket: 'mah-bukkit'
|
|
708
|
+
});
|
|
709
|
+
|
|
710
|
+
const template = cf.merge(firehose);
|
|
711
|
+
if (update) fixtures.update('firehose-defaults', template);
|
|
712
|
+
expect(noUndefined(template)).toEqual(fixtures.get('firehose-defaults'));
|
|
713
|
+
});
|
|
714
|
+
|
|
715
|
+
test('expected resources generated with stream', () => {
|
|
716
|
+
const firehose = new cf.shortcuts.S3KinesisFirehose({
|
|
717
|
+
LogicalName: 'MyKinesisFirehose',
|
|
718
|
+
DestinationBucket: 'mah-bukkit',
|
|
719
|
+
KinesisStreamARN: 'arn:aws:kinesis:us-east-1:111122223333:stream/my-stream'
|
|
720
|
+
});
|
|
721
|
+
|
|
722
|
+
const template = cf.merge(
|
|
723
|
+
{ Conditions: { Always: cf.equals('1', '1') } },
|
|
724
|
+
{ Resources: { AnotherThing: { Type: 'AWS::SNS::Topic' } } },
|
|
725
|
+
firehose
|
|
726
|
+
);
|
|
727
|
+
if (update) fixtures.update('firehose-with-stream', template);
|
|
728
|
+
expect(noUndefined(template)).toEqual(fixtures.get('firehose-with-stream'));
|
|
729
|
+
});
|
|
730
|
+
});
|
|
731
|
+
|
|
732
|
+
describe('[shortcuts] role', () => {
|
|
733
|
+
test('throws without options', () => {
|
|
734
|
+
expect(() => new cf.shortcuts.Role()).toThrow('Options required');
|
|
735
|
+
});
|
|
736
|
+
|
|
737
|
+
test('throws without required parameters', () => {
|
|
738
|
+
expect(() => new cf.shortcuts.Role({})).toThrow(/You must provide a LogicalName and AssumeRolePrincipals/);
|
|
739
|
+
});
|
|
740
|
+
|
|
741
|
+
test('expected resources generated with defaults', () => {
|
|
742
|
+
const role = new cf.shortcuts.Role({
|
|
743
|
+
LogicalName: 'MyRole',
|
|
744
|
+
AssumeRolePrincipals: [{ Service: 'ec2.amazonaws.com' }]
|
|
745
|
+
});
|
|
746
|
+
|
|
747
|
+
const template = cf.merge(role);
|
|
748
|
+
if (update) fixtures.update('role-defaults', template);
|
|
749
|
+
expect(noUndefined(template)).toEqual(fixtures.get('role-defaults'));
|
|
750
|
+
});
|
|
751
|
+
|
|
752
|
+
test('expected resources generated without defaults', () => {
|
|
753
|
+
const role = new cf.shortcuts.Role({
|
|
754
|
+
LogicalName: 'MyRole',
|
|
755
|
+
AssumeRolePrincipals: [{ Service: 'ec2.amazonaws.com' }],
|
|
756
|
+
Statement: [
|
|
757
|
+
{
|
|
758
|
+
Effect: 'Allow',
|
|
759
|
+
Action: 's3:GetObject',
|
|
760
|
+
Resource: 'arn:aws:s3:::fake/data'
|
|
761
|
+
}
|
|
762
|
+
],
|
|
763
|
+
ManagedPolicyArns: ['arn:aws:iam::123456789012:policy/fake'],
|
|
764
|
+
MaxSessionDuration: 3600,
|
|
765
|
+
Path: '/fake/',
|
|
766
|
+
RoleName: 'my-role',
|
|
767
|
+
Tags: [{ Key: 'pipeline-name', Value: 'test' }],
|
|
768
|
+
Condition: 'Always',
|
|
769
|
+
DependsOn: 'AnotherThing'
|
|
770
|
+
});
|
|
771
|
+
|
|
772
|
+
const template = cf.merge(
|
|
773
|
+
{ Conditions: { Always: cf.equals('1', '1') } },
|
|
774
|
+
{ Resources: { AnotherThing: { Type: 'AWS::SNS::Topic' } } },
|
|
775
|
+
role
|
|
776
|
+
);
|
|
777
|
+
if (update) fixtures.update('role-no-defaults', template);
|
|
778
|
+
expect(noUndefined(template)).toEqual(fixtures.get('role-no-defaults'));
|
|
779
|
+
});
|
|
613
780
|
});
|
|
614
781
|
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
() => new cf.shortcuts.
|
|
618
|
-
|
|
619
|
-
'throws without options'
|
|
620
|
-
);
|
|
621
|
-
assert.throws(
|
|
622
|
-
() => new cf.shortcuts.LogSubscriptionLambda({}),
|
|
623
|
-
/You must provide a LogicalName, and Code/,
|
|
624
|
-
'throws without basic lambda required parameters'
|
|
625
|
-
);
|
|
782
|
+
describe('[shortcuts] cross-account role', () => {
|
|
783
|
+
test('throws without options', () => {
|
|
784
|
+
expect(() => new cf.shortcuts.CrossAccountRole()).toThrow('Options required');
|
|
785
|
+
});
|
|
626
786
|
|
|
627
|
-
|
|
628
|
-
() =>
|
|
629
|
-
|
|
630
|
-
LogicalName: 'MyLambda',
|
|
631
|
-
Code: {
|
|
632
|
-
S3Bucket: 'my-code-bucket',
|
|
633
|
-
S3Key: 'path/to/code.zip'
|
|
634
|
-
}
|
|
635
|
-
}),
|
|
636
|
-
/You must provide a LogGroupName/,
|
|
637
|
-
'throws without log-subscription-lambda required parameters'
|
|
638
|
-
);
|
|
787
|
+
test('throws without required parameters', () => {
|
|
788
|
+
expect(() => new cf.shortcuts.CrossAccountRole({})).toThrow(/You must provide a LogicalName and Accounts/);
|
|
789
|
+
});
|
|
639
790
|
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
let template = cf.merge(lambda);
|
|
650
|
-
if (update) fixtures.update('log-subscription-lambda-defaults', template);
|
|
651
|
-
assert.deepEqual(
|
|
652
|
-
noUndefined(template),
|
|
653
|
-
fixtures.get('log-subscription-lambda-defaults'),
|
|
654
|
-
'expected resources generated via defaults'
|
|
655
|
-
);
|
|
791
|
+
test('expected resources generated with defaults', () => {
|
|
792
|
+
const role = new cf.shortcuts.CrossAccountRole({
|
|
793
|
+
LogicalName: 'MyRole',
|
|
794
|
+
Accounts: [
|
|
795
|
+
'123456789012',
|
|
796
|
+
'arn:aws:iam::123456789012:root',
|
|
797
|
+
{ 'Fn::Sub': 'arn:aws:iam::${AWS::AccountId}:root' }
|
|
798
|
+
]
|
|
799
|
+
});
|
|
656
800
|
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
S3Key: 'path/to/code.zip'
|
|
662
|
-
},
|
|
663
|
-
FilterPattern: '{ $.errorCode = 400 }',
|
|
664
|
-
LogGroupName: 'my-log-group'
|
|
665
|
-
});
|
|
666
|
-
|
|
667
|
-
template = cf.merge(lambda);
|
|
668
|
-
if (update) fixtures.update('log-subscription-lambda-no-defaults', template);
|
|
669
|
-
assert.deepEqual(
|
|
670
|
-
noUndefined(template),
|
|
671
|
-
fixtures.get('log-subscription-lambda-no-defaults'),
|
|
672
|
-
'expected resources generated without defaults'
|
|
673
|
-
);
|
|
801
|
+
const template = cf.merge(role);
|
|
802
|
+
if (update) fixtures.update('cross-account-role-defaults', template);
|
|
803
|
+
expect(noUndefined(template)).toEqual(fixtures.get('cross-account-role-defaults'));
|
|
804
|
+
});
|
|
674
805
|
|
|
675
|
-
|
|
676
|
-
|
|
806
|
+
test('expected resources generated without defaults', () => {
|
|
807
|
+
const role = new cf.shortcuts.CrossAccountRole({
|
|
808
|
+
LogicalName: 'MyRole',
|
|
809
|
+
Accounts: [
|
|
810
|
+
'123456789012',
|
|
811
|
+
'arn:aws:iam::123456789012:root',
|
|
812
|
+
{ 'Fn::Sub': 'arn:aws:iam::${AWS::AccountId}:root' }
|
|
813
|
+
],
|
|
814
|
+
Statement: [
|
|
815
|
+
{
|
|
816
|
+
Effect: 'Allow',
|
|
817
|
+
Action: 's3:GetObject',
|
|
818
|
+
Resource: 'arn:aws:s3:::fake/data'
|
|
819
|
+
}
|
|
820
|
+
],
|
|
821
|
+
ManagedPolicyArns: ['arn:aws:iam::123456789012:policy/fake'],
|
|
822
|
+
MaxSessionDuration: 3600,
|
|
823
|
+
Path: '/fake/',
|
|
824
|
+
RoleName: 'my-role',
|
|
825
|
+
Condition: 'Always',
|
|
826
|
+
DependsOn: 'AnotherThing'
|
|
827
|
+
});
|
|
677
828
|
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
'throws without required parameters'
|
|
688
|
-
);
|
|
829
|
+
const template = cf.merge(
|
|
830
|
+
{ Conditions: { Always: cf.equals('1', '1') } },
|
|
831
|
+
{ Resources: { AnotherThing: { Type: 'AWS::SNS::Topic' } } },
|
|
832
|
+
role
|
|
833
|
+
);
|
|
834
|
+
if (update) fixtures.update('cross-account-role-no-defaults', template);
|
|
835
|
+
expect(noUndefined(template)).toEqual(fixtures.get('cross-account-role-no-defaults'));
|
|
836
|
+
});
|
|
837
|
+
});
|
|
689
838
|
|
|
690
|
-
|
|
691
|
-
|
|
839
|
+
describe('[shortcuts] service role', () => {
|
|
840
|
+
test('throws without options', () => {
|
|
841
|
+
expect(() => new cf.shortcuts.ServiceRole()).toThrow('Options required');
|
|
692
842
|
});
|
|
693
843
|
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
noUndefined(template),
|
|
698
|
-
fixtures.get('queue-defaults'),
|
|
699
|
-
'expected resources generated for full defaults'
|
|
700
|
-
);
|
|
844
|
+
test('throws without required parameters', () => {
|
|
845
|
+
expect(() => new cf.shortcuts.ServiceRole({})).toThrow(/You must provide a LogicalName and Service/);
|
|
846
|
+
});
|
|
701
847
|
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
KmsMasterKeyId: 'alias/my-key',
|
|
708
|
-
KmsDataKeyReusePeriondSeconds: 86400,
|
|
709
|
-
MaximumMessageSize: 1024,
|
|
710
|
-
MessageRetentionPeriod: 60,
|
|
711
|
-
QueueName: 'my-queue',
|
|
712
|
-
ReceiveMessageWaitTimeSeconds: 20,
|
|
713
|
-
Condition: 'Always',
|
|
714
|
-
DependsOn: 'AnotherThing',
|
|
715
|
-
TopicName: 'my-topic',
|
|
716
|
-
DisplayName: 'topic-display-name',
|
|
717
|
-
DeadLetterVisibilityTimeout: 60
|
|
718
|
-
});
|
|
719
|
-
|
|
720
|
-
template = cf.merge(
|
|
721
|
-
{ Conditions: { Always: cf.equals('1', '1') } },
|
|
722
|
-
{ Resources: { AnotherThing: { Type: 'AWS::SNS::Topic' } } },
|
|
723
|
-
queue
|
|
724
|
-
);
|
|
725
|
-
if (update) fixtures.update('queue-full', template);
|
|
726
|
-
assert.deepEqual(
|
|
727
|
-
noUndefined(template),
|
|
728
|
-
fixtures.get('queue-full'),
|
|
729
|
-
'expected resources generated no defaults'
|
|
730
|
-
);
|
|
848
|
+
test('expected resources generated with defaults', () => {
|
|
849
|
+
const role = new cf.shortcuts.ServiceRole({
|
|
850
|
+
LogicalName: 'MyRole',
|
|
851
|
+
Service: 'lambda'
|
|
852
|
+
});
|
|
731
853
|
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
854
|
+
const template = cf.merge(role);
|
|
855
|
+
if (update) fixtures.update('service-role-defaults', template);
|
|
856
|
+
expect(noUndefined(template)).toEqual(fixtures.get('service-role-defaults'));
|
|
735
857
|
});
|
|
736
|
-
template = cf.merge(queue);
|
|
737
|
-
if (update) fixtures.update('queue-external-topic', template);
|
|
738
|
-
assert.deepEqual(
|
|
739
|
-
noUndefined(template),
|
|
740
|
-
fixtures.get('queue-external-topic'),
|
|
741
|
-
'expected resources generated for external topic'
|
|
742
|
-
);
|
|
743
858
|
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
859
|
+
test('expected resources generated, service for which AWS::URLSuffix is invalid', () => {
|
|
860
|
+
const role = new cf.shortcuts.ServiceRole({
|
|
861
|
+
LogicalName: 'MyRole',
|
|
862
|
+
Service: 'lambda.amazonaws.com'
|
|
863
|
+
});
|
|
864
|
+
|
|
865
|
+
const template = cf.merge(role);
|
|
866
|
+
if (update) fixtures.update('service-role-no-url-suffix', template);
|
|
867
|
+
expect(noUndefined(template)).toEqual(fixtures.get('service-role-no-url-suffix'));
|
|
747
868
|
});
|
|
748
|
-
template = cf.merge(
|
|
749
|
-
{ Resources: { TopicForOtherThing: { Type: 'AWS::SNS::Topic' } } },
|
|
750
|
-
queue
|
|
751
|
-
);
|
|
752
|
-
if (update) fixtures.update('queue-external-topic-ref', template);
|
|
753
|
-
assert.deepEqual(
|
|
754
|
-
noUndefined(template),
|
|
755
|
-
fixtures.get('queue-external-topic-ref'),
|
|
756
|
-
'expected resources generated for external topic identified by ref'
|
|
757
|
-
);
|
|
758
869
|
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
870
|
+
test('expected resources generated, service for which AWS::URLSuffix is valid', () => {
|
|
871
|
+
const role = new cf.shortcuts.ServiceRole({
|
|
872
|
+
LogicalName: 'MyRole',
|
|
873
|
+
Service: 'ec2'
|
|
874
|
+
});
|
|
875
|
+
|
|
876
|
+
const template = cf.merge(role);
|
|
877
|
+
if (update) fixtures.update('service-role-url-suffix', template);
|
|
878
|
+
expect(noUndefined(template)).toEqual(fixtures.get('service-role-url-suffix'));
|
|
762
879
|
});
|
|
763
|
-
template = cf.merge(queue);
|
|
764
|
-
if (update) fixtures.update('queue-fifo', template);
|
|
765
|
-
assert.deepEqual(
|
|
766
|
-
noUndefined(template),
|
|
767
|
-
fixtures.get('queue-fifo'),
|
|
768
|
-
'expected resources generated for FIFO queue'
|
|
769
|
-
);
|
|
770
880
|
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
template = cf.merge(queue);
|
|
777
|
-
if (update) fixtures.update('queue-fifo-queuename', template);
|
|
778
|
-
assert.deepEqual(
|
|
779
|
-
noUndefined(template),
|
|
780
|
-
fixtures.get('queue-fifo-queuename'),
|
|
781
|
-
'expected resources generated for FIFO queue with specified QueueName'
|
|
782
|
-
);
|
|
881
|
+
test('expected resources generated, service for which AWS::URLSuffix is invalid specified with a suffix', () => {
|
|
882
|
+
const role = new cf.shortcuts.ServiceRole({
|
|
883
|
+
LogicalName: 'MyRole',
|
|
884
|
+
Service: 'ec2.amazonaws.com'
|
|
885
|
+
});
|
|
783
886
|
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
887
|
+
const template = cf.merge(role);
|
|
888
|
+
if (update) fixtures.update('service-role-url-suffix-with-replacement', template);
|
|
889
|
+
expect(noUndefined(template)).toEqual(fixtures.get('service-role-url-suffix-with-replacement'));
|
|
787
890
|
});
|
|
788
|
-
template = cf.merge(queue);
|
|
789
|
-
assert.equal(
|
|
790
|
-
template.Resources.MyFifoFalseQueue.Properties.FifoQueue,
|
|
791
|
-
undefined,
|
|
792
|
-
'the FifoQueue value false is converted to undefined, to pass CFN validation'
|
|
793
|
-
);
|
|
794
891
|
|
|
795
|
-
|
|
796
|
-
|
|
892
|
+
test('expected resources generated without defaults', () => {
|
|
893
|
+
const role = new cf.shortcuts.ServiceRole({
|
|
894
|
+
LogicalName: 'MyRole',
|
|
895
|
+
Service: 'lambda.amazonaws.com',
|
|
896
|
+
Statement: [
|
|
897
|
+
{
|
|
898
|
+
Effect: 'Allow',
|
|
899
|
+
Action: 's3:GetObject',
|
|
900
|
+
Resource: 'arn:aws:s3:::fake/data'
|
|
901
|
+
}
|
|
902
|
+
],
|
|
903
|
+
ManagedPolicyArns: ['arn:aws:iam::123456789012:policy/fake'],
|
|
904
|
+
MaxSessionDuration: 3600,
|
|
905
|
+
Path: '/fake/',
|
|
906
|
+
RoleName: 'my-role',
|
|
907
|
+
Condition: 'Always',
|
|
908
|
+
DependsOn: 'AnotherThing'
|
|
909
|
+
});
|
|
797
910
|
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
'throws without required LogicalName parameter'
|
|
808
|
-
);
|
|
911
|
+
const template = cf.merge(
|
|
912
|
+
{ Conditions: { Always: cf.equals('1', '1') } },
|
|
913
|
+
{ Resources: { AnotherThing: { Type: 'AWS::SNS::Topic' } } },
|
|
914
|
+
role
|
|
915
|
+
);
|
|
916
|
+
if (update) fixtures.update('service-role-no-defaults', template);
|
|
917
|
+
expect(noUndefined(template)).toEqual(fixtures.get('service-role-no-defaults'));
|
|
918
|
+
});
|
|
919
|
+
});
|
|
809
920
|
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
/You must provide a DestinationBucket/,
|
|
815
|
-
'throws without required DestinationBucket parameter'
|
|
816
|
-
);
|
|
921
|
+
describe('[shortcuts] glue database', () => {
|
|
922
|
+
test('throws without options', () => {
|
|
923
|
+
expect(() => new cf.shortcuts.GlueDatabase()).toThrow('Options required');
|
|
924
|
+
});
|
|
817
925
|
|
|
818
|
-
|
|
819
|
-
LogicalName
|
|
820
|
-
DestinationBucket: 'mah-bukkit'
|
|
926
|
+
test('throws without required parameters', () => {
|
|
927
|
+
expect(() => new cf.shortcuts.GlueDatabase({})).toThrow(/You must provide a LogicalName and Name/);
|
|
821
928
|
});
|
|
822
929
|
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
'expected resources generated for full defaults'
|
|
829
|
-
);
|
|
930
|
+
test('expected resources generated with defaults', () => {
|
|
931
|
+
const db = new cf.shortcuts.GlueDatabase({
|
|
932
|
+
LogicalName: 'MyDatabase',
|
|
933
|
+
Name: 'my_database'
|
|
934
|
+
});
|
|
830
935
|
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
KinesisStreamARN: 'arn:aws:kinesis:us-east-1:111122223333:stream/my-stream'
|
|
936
|
+
const template = cf.merge(db);
|
|
937
|
+
if (update) fixtures.update('glue-database-defaults', template);
|
|
938
|
+
expect(noUndefined(template)).toEqual(fixtures.get('glue-database-defaults'));
|
|
835
939
|
});
|
|
836
940
|
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
941
|
+
test('expected resources generated without defaults', () => {
|
|
942
|
+
const db = new cf.shortcuts.GlueDatabase({
|
|
943
|
+
LogicalName: 'MyDatabase',
|
|
944
|
+
Name: 'my_database',
|
|
945
|
+
CatalogId: '123456',
|
|
946
|
+
Description: 'my_database description',
|
|
947
|
+
LocationUri: 'fakeuri',
|
|
948
|
+
Parameters: { thing: 'a' },
|
|
949
|
+
Condition: 'Always',
|
|
950
|
+
DependsOn: 'AnotherThing'
|
|
951
|
+
});
|
|
848
952
|
|
|
849
|
-
|
|
953
|
+
const template = cf.merge(
|
|
954
|
+
{ Conditions: { Always: cf.equals('1', '1') } },
|
|
955
|
+
{ Resources: { AnotherThing: { Type: 'AWS::SNS::Topic' } } },
|
|
956
|
+
db
|
|
957
|
+
);
|
|
958
|
+
if (update) fixtures.update('glue-database-no-defaults', template);
|
|
959
|
+
expect(noUndefined(template)).toEqual(fixtures.get('glue-database-no-defaults'));
|
|
960
|
+
});
|
|
850
961
|
});
|
|
851
962
|
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
() => new cf.shortcuts.
|
|
855
|
-
|
|
856
|
-
'throws without options'
|
|
857
|
-
);
|
|
858
|
-
assert.throws(
|
|
859
|
-
() => new cf.shortcuts.Role({}),
|
|
860
|
-
/You must provide a LogicalName and AssumeRolePrincipals/,
|
|
861
|
-
'throws without required parameters'
|
|
862
|
-
);
|
|
963
|
+
describe('[shortcuts] glue table', () => {
|
|
964
|
+
test('throws without options', () => {
|
|
965
|
+
expect(() => new cf.shortcuts.GlueTable()).toThrow('Options required');
|
|
966
|
+
});
|
|
863
967
|
|
|
864
|
-
|
|
865
|
-
LogicalName
|
|
866
|
-
AssumeRolePrincipals: [{ Service: 'ec2.amazonaws.com' }]
|
|
968
|
+
test('throws without required parameters', () => {
|
|
969
|
+
expect(() => new cf.shortcuts.GlueTable({})).toThrow(/You must provide a LogicalName, Name, DatabaseName, and Columns/);
|
|
867
970
|
});
|
|
868
971
|
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
972
|
+
test('expected resources generated with defaults', () => {
|
|
973
|
+
const db = new cf.shortcuts.GlueTable({
|
|
974
|
+
LogicalName: 'MyTable',
|
|
975
|
+
DatabaseName: 'my_database',
|
|
976
|
+
Name: 'my_table',
|
|
977
|
+
Columns: [
|
|
978
|
+
{ Name: 'column', Type: 'string' }
|
|
979
|
+
]
|
|
980
|
+
});
|
|
876
981
|
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
982
|
+
const template = cf.merge(db);
|
|
983
|
+
if (update) fixtures.update('glue-table-defaults', template);
|
|
984
|
+
expect(noUndefined(template)).toEqual(fixtures.get('glue-table-defaults'));
|
|
985
|
+
});
|
|
986
|
+
|
|
987
|
+
test('expected resources generated without defaults', () => {
|
|
988
|
+
const db = new cf.shortcuts.GlueTable({
|
|
989
|
+
LogicalName: 'MyTable',
|
|
990
|
+
DatabaseName: 'my_database',
|
|
991
|
+
Name: 'my_table',
|
|
992
|
+
Columns: [
|
|
993
|
+
{ Name: 'column', Type: 'string' }
|
|
994
|
+
],
|
|
995
|
+
CatalogId: '1234',
|
|
996
|
+
Owner: 'Team',
|
|
997
|
+
Parameters: { table: 'params' },
|
|
998
|
+
Description: 'my_table description',
|
|
999
|
+
Retention: 12,
|
|
1000
|
+
TableType: 'EXTERNAL_TABLE',
|
|
1001
|
+
ViewExpandedText: '/* Presto View */',
|
|
1002
|
+
ViewOriginalText: '/* Presto View: abc123= */',
|
|
1003
|
+
BucketColumns: ['column'],
|
|
1004
|
+
Compressed: true,
|
|
1005
|
+
InputFormat: 'fake.input.format',
|
|
1006
|
+
Location: 's3://fake/location',
|
|
1007
|
+
OutputFormat: 'fake.output.format',
|
|
1008
|
+
StorageParameters: { storage: 'parameters' },
|
|
1009
|
+
SerdeInfo: {
|
|
1010
|
+
SerializationLibrary: 'fake.serde'
|
|
1011
|
+
},
|
|
1012
|
+
SkewedColumns: {
|
|
1013
|
+
SkewedColumnNames: ['column'],
|
|
1014
|
+
SkewedColumnValueLocationMap: { fake: 'map' },
|
|
1015
|
+
SkewedColumnValues: ['value']
|
|
1016
|
+
},
|
|
1017
|
+
SortColumns: [
|
|
1018
|
+
{ Column: 'column', SortOrder: 0 }
|
|
1019
|
+
],
|
|
1020
|
+
StoredAsSubdirectory: true,
|
|
1021
|
+
Condition: 'Always',
|
|
1022
|
+
DependsOn: 'AnotherThing'
|
|
1023
|
+
});
|
|
907
1024
|
|
|
908
|
-
|
|
1025
|
+
const template = cf.merge(
|
|
1026
|
+
{ Conditions: { Always: cf.equals('1', '1') } },
|
|
1027
|
+
{ Resources: { AnotherThing: { Type: 'AWS::SNS::Topic' } } },
|
|
1028
|
+
db
|
|
1029
|
+
);
|
|
1030
|
+
if (update) fixtures.update('glue-table-no-defaults', template);
|
|
1031
|
+
expect(noUndefined(template)).toEqual(fixtures.get('glue-table-no-defaults'));
|
|
1032
|
+
});
|
|
909
1033
|
});
|
|
910
1034
|
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
() => new cf.shortcuts.
|
|
914
|
-
|
|
915
|
-
'throws without options'
|
|
916
|
-
);
|
|
917
|
-
assert.throws(
|
|
918
|
-
() => new cf.shortcuts.CrossAccountRole({}),
|
|
919
|
-
/You must provide a LogicalName and Accounts/,
|
|
920
|
-
'throws without required parameters'
|
|
921
|
-
);
|
|
1035
|
+
describe('[shortcuts] glue json table', () => {
|
|
1036
|
+
test('throws without options', () => {
|
|
1037
|
+
expect(() => new cf.shortcuts.GlueJsonTable()).toThrow('Options required');
|
|
1038
|
+
});
|
|
922
1039
|
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
'123456789012',
|
|
927
|
-
'arn:aws:iam::123456789012:root',
|
|
928
|
-
{ 'Fn::Sub': 'arn:aws:iam::${AWS::AccountId}:root' }
|
|
929
|
-
]
|
|
930
|
-
});
|
|
931
|
-
|
|
932
|
-
let template = cf.merge(role);
|
|
933
|
-
if (update) fixtures.update('cross-account-role-defaults', template);
|
|
934
|
-
assert.deepEqual(
|
|
935
|
-
noUndefined(template),
|
|
936
|
-
fixtures.get('cross-account-role-defaults'),
|
|
937
|
-
'expected resources generated with defaults'
|
|
938
|
-
);
|
|
1040
|
+
test('throws without required parameters', () => {
|
|
1041
|
+
expect(() => new cf.shortcuts.GlueJsonTable({})).toThrow(/You must provide a Location/);
|
|
1042
|
+
});
|
|
939
1043
|
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
'
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
1044
|
+
test('expected resources generated with defaults', () => {
|
|
1045
|
+
const db = new cf.shortcuts.GlueJsonTable({
|
|
1046
|
+
LogicalName: 'MyTable',
|
|
1047
|
+
DatabaseName: 'my_database',
|
|
1048
|
+
Name: 'my_table',
|
|
1049
|
+
Columns: [
|
|
1050
|
+
{ Name: 'column', Type: 'string' }
|
|
1051
|
+
],
|
|
1052
|
+
Location: 's3://fake/location'
|
|
1053
|
+
});
|
|
1054
|
+
|
|
1055
|
+
const template = cf.merge(db);
|
|
1056
|
+
if (update) fixtures.update('glue-json-table-defaults', template);
|
|
1057
|
+
expect(noUndefined(template)).toEqual(fixtures.get('glue-json-table-defaults'));
|
|
1058
|
+
});
|
|
1059
|
+
|
|
1060
|
+
test('expected resources generated without defaults', () => {
|
|
1061
|
+
const db = new cf.shortcuts.GlueJsonTable({
|
|
1062
|
+
LogicalName: 'MyTable',
|
|
1063
|
+
DatabaseName: 'my_database',
|
|
1064
|
+
Name: 'my_table',
|
|
1065
|
+
Columns: [
|
|
1066
|
+
{ Name: 'column', Type: 'string' }
|
|
1067
|
+
],
|
|
1068
|
+
CatalogId: '1234',
|
|
1069
|
+
Owner: 'Team',
|
|
1070
|
+
Parameters: { table: 'params' },
|
|
1071
|
+
Description: 'my_table description',
|
|
1072
|
+
Retention: 12,
|
|
1073
|
+
TableType: 'EXTERNAL_TABLE',
|
|
1074
|
+
ViewExpandedText: '/* Presto View */',
|
|
1075
|
+
ViewOriginalText: '/* Presto View: abc123= */',
|
|
1076
|
+
BucketColumns: ['column'],
|
|
1077
|
+
Compressed: true,
|
|
1078
|
+
Location: 's3://fake/location',
|
|
1079
|
+
InputFormat: 'fake.input.format',
|
|
1080
|
+
OutputFormat: 'fake.output.format',
|
|
1081
|
+
StorageParameters: { storage: 'parameters' },
|
|
1082
|
+
SerdeInfo: {
|
|
1083
|
+
SerializationLibrary: 'fake.serde'
|
|
1084
|
+
},
|
|
1085
|
+
SkewedColumns: {
|
|
1086
|
+
SkewedColumnNames: ['column'],
|
|
1087
|
+
SkewedColumnValueLocationMap: { fake: 'map' },
|
|
1088
|
+
SkewedColumnValues: ['value']
|
|
1089
|
+
},
|
|
1090
|
+
SortColumns: [
|
|
1091
|
+
{ Column: 'column', SortOrder: 0 }
|
|
1092
|
+
],
|
|
1093
|
+
StoredAsSubdirectory: true,
|
|
1094
|
+
Condition: 'Always',
|
|
1095
|
+
DependsOn: 'AnotherThing'
|
|
1096
|
+
});
|
|
973
1097
|
|
|
974
|
-
|
|
1098
|
+
const template = cf.merge(
|
|
1099
|
+
{ Conditions: { Always: cf.equals('1', '1') } },
|
|
1100
|
+
{ Resources: { AnotherThing: { Type: 'AWS::SNS::Topic' } } },
|
|
1101
|
+
db
|
|
1102
|
+
);
|
|
1103
|
+
if (update) fixtures.update('glue-json-table-no-defaults', template);
|
|
1104
|
+
expect(noUndefined(template)).toEqual(fixtures.get('glue-json-table-no-defaults'));
|
|
1105
|
+
});
|
|
975
1106
|
});
|
|
976
1107
|
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
() => new cf.shortcuts.
|
|
980
|
-
|
|
981
|
-
'throws without options'
|
|
982
|
-
);
|
|
983
|
-
assert.throws(
|
|
984
|
-
() => new cf.shortcuts.ServiceRole({}),
|
|
985
|
-
/You must provide a LogicalName and Service/,
|
|
986
|
-
'throws without required parameters'
|
|
987
|
-
);
|
|
1108
|
+
describe('[shortcuts] glue orc table', () => {
|
|
1109
|
+
test('throws without options', () => {
|
|
1110
|
+
expect(() => new cf.shortcuts.GlueOrcTable()).toThrow('Options required');
|
|
1111
|
+
});
|
|
988
1112
|
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
Service: 'lambda'
|
|
1113
|
+
test('throws without required parameters', () => {
|
|
1114
|
+
expect(() => new cf.shortcuts.GlueOrcTable({})).toThrow(/You must provide a Location/);
|
|
992
1115
|
});
|
|
993
1116
|
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1117
|
+
test('expected resources generated with defaults', () => {
|
|
1118
|
+
const db = new cf.shortcuts.GlueOrcTable({
|
|
1119
|
+
LogicalName: 'MyTable',
|
|
1120
|
+
DatabaseName: 'my_database',
|
|
1121
|
+
Name: 'my_table',
|
|
1122
|
+
Columns: [
|
|
1123
|
+
{ Name: 'column', Type: 'string' }
|
|
1124
|
+
],
|
|
1125
|
+
Location: 's3://fake/location'
|
|
1126
|
+
});
|
|
1001
1127
|
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1128
|
+
const template = cf.merge(db);
|
|
1129
|
+
if (update) fixtures.update('glue-orc-table-defaults', template);
|
|
1130
|
+
expect(noUndefined(template)).toEqual(fixtures.get('glue-orc-table-defaults'));
|
|
1005
1131
|
});
|
|
1006
1132
|
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1133
|
+
test('expected resources generated without defaults', () => {
|
|
1134
|
+
const db = new cf.shortcuts.GlueOrcTable({
|
|
1135
|
+
LogicalName: 'MyTable',
|
|
1136
|
+
DatabaseName: 'my_database',
|
|
1137
|
+
Name: 'my_table',
|
|
1138
|
+
Columns: [
|
|
1139
|
+
{ Name: 'column', Type: 'string' }
|
|
1140
|
+
],
|
|
1141
|
+
CatalogId: '1234',
|
|
1142
|
+
Owner: 'Team',
|
|
1143
|
+
Parameters: { table: 'params' },
|
|
1144
|
+
Description: 'my_table description',
|
|
1145
|
+
Retention: 12,
|
|
1146
|
+
TableType: 'EXTERNAL_TABLE',
|
|
1147
|
+
ViewExpandedText: '/* Presto View */',
|
|
1148
|
+
ViewOriginalText: '/* Presto View: abc123= */',
|
|
1149
|
+
BucketColumns: ['column'],
|
|
1150
|
+
Compressed: true,
|
|
1151
|
+
Location: 's3://fake/location',
|
|
1152
|
+
InputFormat: 'fake.input.format',
|
|
1153
|
+
OutputFormat: 'fake.output.format',
|
|
1154
|
+
StorageParameters: { storage: 'parameters' },
|
|
1155
|
+
SerdeInfo: {
|
|
1156
|
+
SerializationLibrary: 'fake.serde'
|
|
1157
|
+
},
|
|
1158
|
+
SkewedColumns: {
|
|
1159
|
+
SkewedColumnNames: ['column'],
|
|
1160
|
+
SkewedColumnValueLocationMap: { fake: 'map' },
|
|
1161
|
+
SkewedColumnValues: ['value']
|
|
1162
|
+
},
|
|
1163
|
+
SortColumns: [
|
|
1164
|
+
{ Column: 'column', SortOrder: 0 }
|
|
1165
|
+
],
|
|
1166
|
+
StoredAsSubdirectory: true,
|
|
1167
|
+
Condition: 'Always',
|
|
1168
|
+
DependsOn: 'AnotherThing'
|
|
1169
|
+
});
|
|
1014
1170
|
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1171
|
+
const template = cf.merge(
|
|
1172
|
+
{ Conditions: { Always: cf.equals('1', '1') } },
|
|
1173
|
+
{ Resources: { AnotherThing: { Type: 'AWS::SNS::Topic' } } },
|
|
1174
|
+
db
|
|
1175
|
+
);
|
|
1176
|
+
if (update) fixtures.update('glue-orc-table-no-defaults', template);
|
|
1177
|
+
expect(noUndefined(template)).toEqual(fixtures.get('glue-orc-table-no-defaults'));
|
|
1018
1178
|
});
|
|
1179
|
+
});
|
|
1019
1180
|
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
fixtures.get('service-role-url-suffix'),
|
|
1025
|
-
'expected resources generated, service for which AWS::URLSuffix is invalid'
|
|
1026
|
-
);
|
|
1181
|
+
describe('[shortcuts] glue parquet table', () => {
|
|
1182
|
+
test('throws without options', () => {
|
|
1183
|
+
expect(() => new cf.shortcuts.GlueParquetTable()).toThrow('Options required');
|
|
1184
|
+
});
|
|
1027
1185
|
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
Service: 'ec2.amazonaws.com'
|
|
1186
|
+
test('throws without required parameters', () => {
|
|
1187
|
+
expect(() => new cf.shortcuts.GlueParquetTable({})).toThrow(/You must provide a Location/);
|
|
1031
1188
|
});
|
|
1032
1189
|
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1190
|
+
test('expected resources generated with defaults', () => {
|
|
1191
|
+
const db = new cf.shortcuts.GlueParquetTable({
|
|
1192
|
+
LogicalName: 'MyTable',
|
|
1193
|
+
DatabaseName: 'my_database',
|
|
1194
|
+
Name: 'my_table',
|
|
1195
|
+
Columns: [
|
|
1196
|
+
{ Name: 'column', Type: 'string' }
|
|
1197
|
+
],
|
|
1198
|
+
Location: 's3://fake/location'
|
|
1199
|
+
});
|
|
1041
1200
|
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1201
|
+
const template = cf.merge(db);
|
|
1202
|
+
if (update) fixtures.update('glue-parquet-table-defaults', template);
|
|
1203
|
+
expect(noUndefined(template)).toEqual(fixtures.get('glue-parquet-table-defaults'));
|
|
1204
|
+
});
|
|
1205
|
+
|
|
1206
|
+
test('expected resources generated without defaults', () => {
|
|
1207
|
+
const db = new cf.shortcuts.GlueParquetTable({
|
|
1208
|
+
LogicalName: 'MyTable',
|
|
1209
|
+
DatabaseName: 'my_database',
|
|
1210
|
+
Name: 'my_table',
|
|
1211
|
+
Columns: [
|
|
1212
|
+
{ Name: 'column', Type: 'string' }
|
|
1213
|
+
],
|
|
1214
|
+
CatalogId: '1234',
|
|
1215
|
+
Owner: 'Team',
|
|
1216
|
+
Parameters: { table: 'params' },
|
|
1217
|
+
Description: 'my_table description',
|
|
1218
|
+
Retention: 12,
|
|
1219
|
+
TableType: 'EXTERNAL_TABLE',
|
|
1220
|
+
ViewExpandedText: '/* Presto View */',
|
|
1221
|
+
ViewOriginalText: '/* Presto View: abc123= */',
|
|
1222
|
+
BucketColumns: ['column'],
|
|
1223
|
+
Compressed: true,
|
|
1224
|
+
Location: 's3://fake/location',
|
|
1225
|
+
InputFormat: 'fake.input.format',
|
|
1226
|
+
OutputFormat: 'fake.output.format',
|
|
1227
|
+
StorageParameters: { storage: 'parameters' },
|
|
1228
|
+
SerdeInfo: {
|
|
1229
|
+
SerializationLibrary: 'fake.serde'
|
|
1230
|
+
},
|
|
1231
|
+
SkewedColumns: {
|
|
1232
|
+
SkewedColumnNames: ['column'],
|
|
1233
|
+
SkewedColumnValueLocationMap: { fake: 'map' },
|
|
1234
|
+
SkewedColumnValues: ['value']
|
|
1235
|
+
},
|
|
1236
|
+
SortColumns: [
|
|
1237
|
+
{ Column: 'column', SortOrder: 0 }
|
|
1238
|
+
],
|
|
1239
|
+
StoredAsSubdirectory: true,
|
|
1240
|
+
Condition: 'Always',
|
|
1241
|
+
DependsOn: 'AnotherThing'
|
|
1242
|
+
});
|
|
1071
1243
|
|
|
1072
|
-
|
|
1244
|
+
const template = cf.merge(
|
|
1245
|
+
{ Conditions: { Always: cf.equals('1', '1') } },
|
|
1246
|
+
{ Resources: { AnotherThing: { Type: 'AWS::SNS::Topic' } } },
|
|
1247
|
+
db
|
|
1248
|
+
);
|
|
1249
|
+
if (update) fixtures.update('glue-parquet-table-no-defaults', template);
|
|
1250
|
+
expect(noUndefined(template)).toEqual(fixtures.get('glue-parquet-table-no-defaults'));
|
|
1251
|
+
});
|
|
1073
1252
|
});
|
|
1074
1253
|
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
() => new cf.shortcuts.
|
|
1078
|
-
|
|
1079
|
-
'throws without options'
|
|
1080
|
-
);
|
|
1081
|
-
assert.throws(
|
|
1082
|
-
() => new cf.shortcuts.GlueDatabase({}),
|
|
1083
|
-
/You must provide a LogicalName and Name/,
|
|
1084
|
-
'throws without required parameters'
|
|
1085
|
-
);
|
|
1254
|
+
describe('[shortcuts] glue iceberg table', () => {
|
|
1255
|
+
test('throws without options', () => {
|
|
1256
|
+
expect(() => new cf.shortcuts.GlueIcebergTable()).toThrow('Options required');
|
|
1257
|
+
});
|
|
1086
1258
|
|
|
1087
|
-
|
|
1088
|
-
LogicalName
|
|
1089
|
-
Name: 'my_database'
|
|
1259
|
+
test('throws without required parameters', () => {
|
|
1260
|
+
expect(() => new cf.shortcuts.GlueIcebergTable({})).toThrow(/You must provide a LogicalName, Name, DatabaseName, Location, and Schema/);
|
|
1090
1261
|
});
|
|
1091
1262
|
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1263
|
+
test('expected resources generated with defaults', () => {
|
|
1264
|
+
const db = new cf.shortcuts.GlueIcebergTable({
|
|
1265
|
+
LogicalName: 'MyTable',
|
|
1266
|
+
DatabaseName: 'my_database',
|
|
1267
|
+
Name: 'my_table',
|
|
1268
|
+
Schema: {
|
|
1269
|
+
Type: 'struct',
|
|
1270
|
+
Fields: [
|
|
1271
|
+
{ Name: 'column', Type: 'string', Id: 1, Required: true }
|
|
1272
|
+
]
|
|
1273
|
+
},
|
|
1274
|
+
Location: 's3://fake/location'
|
|
1275
|
+
});
|
|
1099
1276
|
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
Description: 'my_database description',
|
|
1105
|
-
LocationUri: 'fakeuri',
|
|
1106
|
-
Parameters: { thing: 'a' },
|
|
1107
|
-
Condition: 'Always',
|
|
1108
|
-
DependsOn: 'AnotherThing'
|
|
1109
|
-
});
|
|
1110
|
-
|
|
1111
|
-
template = cf.merge(
|
|
1112
|
-
{ Conditions: { Always: cf.equals('1', '1') } },
|
|
1113
|
-
{ Resources: { AnotherThing: { Type: 'AWS::SNS::Topic' } } },
|
|
1114
|
-
db
|
|
1115
|
-
);
|
|
1116
|
-
if (update) fixtures.update('glue-database-no-defaults', template);
|
|
1117
|
-
assert.deepEqual(
|
|
1118
|
-
noUndefined(template),
|
|
1119
|
-
fixtures.get('glue-database-no-defaults'),
|
|
1120
|
-
'expected resources generated without defaults'
|
|
1121
|
-
);
|
|
1277
|
+
const template = cf.merge(db);
|
|
1278
|
+
if (update) fixtures.update('glue-iceberg-table-defaults', template);
|
|
1279
|
+
expect(noUndefined(template)).toEqual(fixtures.get('glue-iceberg-table-defaults'));
|
|
1280
|
+
});
|
|
1122
1281
|
|
|
1123
|
-
|
|
1124
|
-
|
|
1282
|
+
test('expected resources generated without defaults', () => {
|
|
1283
|
+
const db = new cf.shortcuts.GlueIcebergTable({
|
|
1284
|
+
LogicalName: 'MyTable',
|
|
1285
|
+
DatabaseName: 'my_database',
|
|
1286
|
+
Name: 'my_table',
|
|
1287
|
+
Schema: {
|
|
1288
|
+
Type: 'struct',
|
|
1289
|
+
Fields: [
|
|
1290
|
+
{ Name: 'column', Type: 'string', Id: 1, Required: true }
|
|
1291
|
+
]
|
|
1292
|
+
},
|
|
1293
|
+
CatalogId: '1234',
|
|
1294
|
+
Location: 's3://fake/location',
|
|
1295
|
+
IcebergVersion: '2'
|
|
1296
|
+
});
|
|
1125
1297
|
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
()
|
|
1129
|
-
|
|
1130
|
-
'throws without options'
|
|
1131
|
-
);
|
|
1132
|
-
assert.throws(
|
|
1133
|
-
() => new cf.shortcuts.GlueTable({}),
|
|
1134
|
-
/You must provide a LogicalName, Name, DatabaseName, and Columns/,
|
|
1135
|
-
'throws without required parameters'
|
|
1136
|
-
);
|
|
1298
|
+
const template = cf.merge(db);
|
|
1299
|
+
if (update) fixtures.update('glue-iceberg-table-no-defaults', template);
|
|
1300
|
+
expect(noUndefined(template)).toEqual(fixtures.get('glue-iceberg-table-no-defaults'));
|
|
1301
|
+
});
|
|
1137
1302
|
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
);
|
|
1303
|
+
test('throws when EnableOptimizer is true but OptimizerRoleArn is missing', () => {
|
|
1304
|
+
expect(() => new cf.shortcuts.GlueIcebergTable({
|
|
1305
|
+
LogicalName: 'MyTable',
|
|
1306
|
+
DatabaseName: 'my_database',
|
|
1307
|
+
Name: 'my_table',
|
|
1308
|
+
Schema: {
|
|
1309
|
+
Type: 'struct',
|
|
1310
|
+
Fields: [
|
|
1311
|
+
{ Name: 'column', Type: 'string', Id: 1, Required: true }
|
|
1312
|
+
]
|
|
1313
|
+
},
|
|
1314
|
+
Location: 's3://fake/location',
|
|
1315
|
+
EnableOptimizer: true
|
|
1316
|
+
})).toThrow(/You must provide an OptimizerRoleArn when EnableOptimizer is true/);
|
|
1317
|
+
});
|
|
1154
1318
|
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
BucketColumns: ['column'],
|
|
1171
|
-
Compressed: true,
|
|
1172
|
-
InputFormat: 'fake.input.format',
|
|
1173
|
-
Location: 's3://fake/location',
|
|
1174
|
-
OutputFormat: 'fake.output.format',
|
|
1175
|
-
StorageParameters: { storage: 'parameters' },
|
|
1176
|
-
SerdeInfo: {
|
|
1177
|
-
SerializationLibrary: 'fake.serde'
|
|
1178
|
-
},
|
|
1179
|
-
SkewedColumns: {
|
|
1180
|
-
SkewedColumnNames: ['column'],
|
|
1181
|
-
SkewedColumnValueLocationMap: { fake: 'map' },
|
|
1182
|
-
SkewedColumnValues: ['value']
|
|
1183
|
-
},
|
|
1184
|
-
SortColumns: [
|
|
1185
|
-
{ Column: 'column', SortOrder: 0 }
|
|
1186
|
-
],
|
|
1187
|
-
StoredAsSubdirectory: true,
|
|
1188
|
-
Condition: 'Always',
|
|
1189
|
-
DependsOn: 'AnotherThing'
|
|
1190
|
-
});
|
|
1191
|
-
|
|
1192
|
-
template = cf.merge(
|
|
1193
|
-
{ Conditions: { Always: cf.equals('1', '1') } },
|
|
1194
|
-
{ Resources: { AnotherThing: { Type: 'AWS::SNS::Topic' } } },
|
|
1195
|
-
db
|
|
1196
|
-
);
|
|
1197
|
-
if (update) fixtures.update('glue-table-no-defaults', template);
|
|
1198
|
-
assert.deepEqual(
|
|
1199
|
-
noUndefined(template),
|
|
1200
|
-
fixtures.get('glue-table-no-defaults'),
|
|
1201
|
-
'expected resources generated without defaults'
|
|
1202
|
-
);
|
|
1319
|
+
test('expected resources generated with optimizer using default retention settings', () => {
|
|
1320
|
+
const db = new cf.shortcuts.GlueIcebergTable({
|
|
1321
|
+
LogicalName: 'MyTable',
|
|
1322
|
+
DatabaseName: 'my_database',
|
|
1323
|
+
Name: 'my_table',
|
|
1324
|
+
Schema: {
|
|
1325
|
+
Type: 'struct',
|
|
1326
|
+
Fields: [
|
|
1327
|
+
{ Name: 'column', Type: 'string', Id: 1, Required: true }
|
|
1328
|
+
]
|
|
1329
|
+
},
|
|
1330
|
+
Location: 's3://fake/location',
|
|
1331
|
+
EnableOptimizer: true,
|
|
1332
|
+
OptimizerRoleArn: 'arn:aws:iam::123456789012:role/OptimizerRole'
|
|
1333
|
+
});
|
|
1203
1334
|
|
|
1204
|
-
|
|
1205
|
-
|
|
1335
|
+
const template = cf.merge(db);
|
|
1336
|
+
if (update) fixtures.update('glue-iceberg-table-with-optimizer-defaults', template);
|
|
1337
|
+
expect(noUndefined(template)).toEqual(fixtures.get('glue-iceberg-table-with-optimizer-defaults'));
|
|
1338
|
+
});
|
|
1206
1339
|
|
|
1207
|
-
test('
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1340
|
+
test('expected resources generated with optimizer using custom retention settings', () => {
|
|
1341
|
+
const db = new cf.shortcuts.GlueIcebergTable({
|
|
1342
|
+
LogicalName: 'MyTable',
|
|
1343
|
+
DatabaseName: 'my_database',
|
|
1344
|
+
Name: 'my_table',
|
|
1345
|
+
Schema: {
|
|
1346
|
+
Type: 'struct',
|
|
1347
|
+
Fields: [
|
|
1348
|
+
{ Name: 'column', Type: 'string', Id: 1, Required: true }
|
|
1349
|
+
]
|
|
1350
|
+
},
|
|
1351
|
+
Location: 's3://fake/location',
|
|
1352
|
+
EnableOptimizer: true,
|
|
1353
|
+
OptimizerRoleArn: cf.getAtt('OptimizerRole', 'Arn'),
|
|
1354
|
+
SnapshotRetentionPeriodInDays: 7,
|
|
1355
|
+
NumberOfSnapshotsToRetain: 3,
|
|
1356
|
+
CleanExpiredFiles: false
|
|
1357
|
+
});
|
|
1218
1358
|
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
Location: 's3://fake/location'
|
|
1227
|
-
});
|
|
1228
|
-
|
|
1229
|
-
let template = cf.merge(db);
|
|
1230
|
-
if (update) fixtures.update('glue-json-table-defaults', template);
|
|
1231
|
-
assert.deepEqual(
|
|
1232
|
-
noUndefined(template),
|
|
1233
|
-
fixtures.get('glue-json-table-defaults'),
|
|
1234
|
-
'expected resources generated with defaults'
|
|
1235
|
-
);
|
|
1359
|
+
const template = cf.merge(
|
|
1360
|
+
{ Resources: { OptimizerRole: { Type: 'AWS::IAM::Role', Properties: { AssumeRolePolicyDocument: {} } } } },
|
|
1361
|
+
db
|
|
1362
|
+
);
|
|
1363
|
+
if (update) fixtures.update('glue-iceberg-table-with-optimizer-custom', template);
|
|
1364
|
+
expect(noUndefined(template)).toEqual(fixtures.get('glue-iceberg-table-with-optimizer-custom'));
|
|
1365
|
+
});
|
|
1236
1366
|
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
BucketColumns: ['column'],
|
|
1253
|
-
Compressed: true,
|
|
1254
|
-
Location: 's3://fake/location',
|
|
1255
|
-
InputFormat: 'fake.input.format',
|
|
1256
|
-
OutputFormat: 'fake.output.format',
|
|
1257
|
-
StorageParameters: { storage: 'parameters' },
|
|
1258
|
-
SerdeInfo: {
|
|
1259
|
-
SerializationLibrary: 'fake.serde'
|
|
1260
|
-
},
|
|
1261
|
-
SkewedColumns: {
|
|
1262
|
-
SkewedColumnNames: ['column'],
|
|
1263
|
-
SkewedColumnValueLocationMap: { fake: 'map' },
|
|
1264
|
-
SkewedColumnValues: ['value']
|
|
1265
|
-
},
|
|
1266
|
-
SortColumns: [
|
|
1267
|
-
{ Column: 'column', SortOrder: 0 }
|
|
1268
|
-
],
|
|
1269
|
-
StoredAsSubdirectory: true,
|
|
1270
|
-
Condition: 'Always',
|
|
1271
|
-
DependsOn: 'AnotherThing'
|
|
1272
|
-
});
|
|
1273
|
-
|
|
1274
|
-
template = cf.merge(
|
|
1275
|
-
{ Conditions: { Always: cf.equals('1', '1') } },
|
|
1276
|
-
{ Resources: { AnotherThing: { Type: 'AWS::SNS::Topic' } } },
|
|
1277
|
-
db
|
|
1278
|
-
);
|
|
1279
|
-
if (update) fixtures.update('glue-json-table-no-defaults', template);
|
|
1280
|
-
assert.deepEqual(
|
|
1281
|
-
noUndefined(template),
|
|
1282
|
-
fixtures.get('glue-json-table-no-defaults'),
|
|
1283
|
-
'expected resources generated without defaults'
|
|
1284
|
-
);
|
|
1367
|
+
test('throws when EnableCompaction is true but CompactionRoleArn is missing', () => {
|
|
1368
|
+
expect(() => new cf.shortcuts.GlueIcebergTable({
|
|
1369
|
+
LogicalName: 'MyTable',
|
|
1370
|
+
DatabaseName: 'my_database',
|
|
1371
|
+
Name: 'my_table',
|
|
1372
|
+
Schema: {
|
|
1373
|
+
Type: 'struct',
|
|
1374
|
+
Fields: [
|
|
1375
|
+
{ Name: 'column', Type: 'string', Id: 1, Required: true }
|
|
1376
|
+
]
|
|
1377
|
+
},
|
|
1378
|
+
Location: 's3://fake/location',
|
|
1379
|
+
EnableCompaction: true
|
|
1380
|
+
})).toThrow(/You must provide a CompactionRoleArn when EnableCompaction is true/);
|
|
1381
|
+
});
|
|
1285
1382
|
|
|
1286
|
-
|
|
1287
|
-
|
|
1383
|
+
test('expected resources generated with compaction using default settings', () => {
|
|
1384
|
+
const db = new cf.shortcuts.GlueIcebergTable({
|
|
1385
|
+
LogicalName: 'MyTable',
|
|
1386
|
+
DatabaseName: 'my_database',
|
|
1387
|
+
Name: 'my_table',
|
|
1388
|
+
Schema: {
|
|
1389
|
+
Type: 'struct',
|
|
1390
|
+
Fields: [
|
|
1391
|
+
{ Name: 'column', Type: 'string', Id: 1, Required: true }
|
|
1392
|
+
]
|
|
1393
|
+
},
|
|
1394
|
+
Location: 's3://fake/location',
|
|
1395
|
+
EnableCompaction: true,
|
|
1396
|
+
CompactionRoleArn: 'arn:aws:iam::123456789012:role/CompactionRole'
|
|
1397
|
+
});
|
|
1288
1398
|
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
()
|
|
1292
|
-
|
|
1293
|
-
'throws without options'
|
|
1294
|
-
);
|
|
1295
|
-
assert.throws(
|
|
1296
|
-
() => new cf.shortcuts.GlueOrcTable({}),
|
|
1297
|
-
/You must provide a Location/,
|
|
1298
|
-
'throws without required parameters'
|
|
1299
|
-
);
|
|
1399
|
+
const template = cf.merge(db);
|
|
1400
|
+
if (update) fixtures.update('glue-iceberg-table-with-compaction-defaults', template);
|
|
1401
|
+
expect(noUndefined(template)).toEqual(fixtures.get('glue-iceberg-table-with-compaction-defaults'));
|
|
1402
|
+
});
|
|
1300
1403
|
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
'expected resources generated with defaults'
|
|
1317
|
-
);
|
|
1404
|
+
test('expected resources generated with compaction using custom settings', () => {
|
|
1405
|
+
const db = new cf.shortcuts.GlueIcebergTable({
|
|
1406
|
+
LogicalName: 'MyTable',
|
|
1407
|
+
DatabaseName: 'my_database',
|
|
1408
|
+
Name: 'my_table',
|
|
1409
|
+
Schema: {
|
|
1410
|
+
Type: 'struct',
|
|
1411
|
+
Fields: [
|
|
1412
|
+
{ Name: 'column', Type: 'string', Id: 1, Required: true }
|
|
1413
|
+
]
|
|
1414
|
+
},
|
|
1415
|
+
Location: 's3://fake/location',
|
|
1416
|
+
EnableCompaction: true,
|
|
1417
|
+
CompactionRoleArn: cf.getAtt('CompactionRole', 'Arn')
|
|
1418
|
+
});
|
|
1318
1419
|
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
CatalogId: '1234',
|
|
1327
|
-
Owner: 'Team',
|
|
1328
|
-
Parameters: { table: 'params' },
|
|
1329
|
-
Description: 'my_table description',
|
|
1330
|
-
Retention: 12,
|
|
1331
|
-
TableType: 'EXTERNAL_TABLE',
|
|
1332
|
-
ViewExpandedText: '/* Presto View */',
|
|
1333
|
-
ViewOriginalText: '/* Presto View: abc123= */',
|
|
1334
|
-
BucketColumns: ['column'],
|
|
1335
|
-
Compressed: true,
|
|
1336
|
-
Location: 's3://fake/location',
|
|
1337
|
-
InputFormat: 'fake.input.format',
|
|
1338
|
-
OutputFormat: 'fake.output.format',
|
|
1339
|
-
StorageParameters: { storage: 'parameters' },
|
|
1340
|
-
SerdeInfo: {
|
|
1341
|
-
SerializationLibrary: 'fake.serde'
|
|
1342
|
-
},
|
|
1343
|
-
SkewedColumns: {
|
|
1344
|
-
SkewedColumnNames: ['column'],
|
|
1345
|
-
SkewedColumnValueLocationMap: { fake: 'map' },
|
|
1346
|
-
SkewedColumnValues: ['value']
|
|
1347
|
-
},
|
|
1348
|
-
SortColumns: [
|
|
1349
|
-
{ Column: 'column', SortOrder: 0 }
|
|
1350
|
-
],
|
|
1351
|
-
StoredAsSubdirectory: true,
|
|
1352
|
-
Condition: 'Always',
|
|
1353
|
-
DependsOn: 'AnotherThing'
|
|
1354
|
-
});
|
|
1355
|
-
|
|
1356
|
-
template = cf.merge(
|
|
1357
|
-
{ Conditions: { Always: cf.equals('1', '1') } },
|
|
1358
|
-
{ Resources: { AnotherThing: { Type: 'AWS::SNS::Topic' } } },
|
|
1359
|
-
db
|
|
1360
|
-
);
|
|
1361
|
-
if (update) fixtures.update('glue-orc-table-no-defaults', template);
|
|
1362
|
-
assert.deepEqual(
|
|
1363
|
-
noUndefined(template),
|
|
1364
|
-
fixtures.get('glue-orc-table-no-defaults'),
|
|
1365
|
-
'expected resources generated without defaults'
|
|
1366
|
-
);
|
|
1420
|
+
const template = cf.merge(
|
|
1421
|
+
{ Resources: { CompactionRole: { Type: 'AWS::IAM::Role', Properties: { AssumeRolePolicyDocument: {} } } } },
|
|
1422
|
+
db
|
|
1423
|
+
);
|
|
1424
|
+
if (update) fixtures.update('glue-iceberg-table-with-compaction-custom', template);
|
|
1425
|
+
expect(noUndefined(template)).toEqual(fixtures.get('glue-iceberg-table-with-compaction-custom'));
|
|
1426
|
+
});
|
|
1367
1427
|
|
|
1368
|
-
|
|
1369
|
-
|
|
1428
|
+
test('expected resources generated with both retention and compaction optimizers', () => {
|
|
1429
|
+
const db = new cf.shortcuts.GlueIcebergTable({
|
|
1430
|
+
LogicalName: 'MyTable',
|
|
1431
|
+
DatabaseName: 'my_database',
|
|
1432
|
+
Name: 'my_table',
|
|
1433
|
+
Schema: {
|
|
1434
|
+
Type: 'struct',
|
|
1435
|
+
Fields: [
|
|
1436
|
+
{ Name: 'column', Type: 'string', Id: 1, Required: true }
|
|
1437
|
+
]
|
|
1438
|
+
},
|
|
1439
|
+
Location: 's3://fake/location',
|
|
1440
|
+
EnableOptimizer: true,
|
|
1441
|
+
OptimizerRoleArn: 'arn:aws:iam::123456789012:role/RetentionRole',
|
|
1442
|
+
EnableCompaction: true,
|
|
1443
|
+
CompactionRoleArn: 'arn:aws:iam::123456789012:role/CompactionRole'
|
|
1444
|
+
});
|
|
1370
1445
|
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
()
|
|
1374
|
-
|
|
1375
|
-
'throws without options'
|
|
1376
|
-
);
|
|
1377
|
-
assert.throws(
|
|
1378
|
-
() => new cf.shortcuts.GlueParquetTable({}),
|
|
1379
|
-
/You must provide a Location/,
|
|
1380
|
-
'throws without required parameters'
|
|
1381
|
-
);
|
|
1446
|
+
const template = cf.merge(db);
|
|
1447
|
+
if (update) fixtures.update('glue-iceberg-table-with-both-optimizers', template);
|
|
1448
|
+
expect(noUndefined(template)).toEqual(fixtures.get('glue-iceberg-table-with-both-optimizers'));
|
|
1449
|
+
});
|
|
1382
1450
|
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
'expected resources generated with defaults'
|
|
1399
|
-
);
|
|
1451
|
+
test('throws when EnableOrphanFileDeletion is true but OrphanFileDeletionRoleArn is missing', () => {
|
|
1452
|
+
expect(() => new cf.shortcuts.GlueIcebergTable({
|
|
1453
|
+
LogicalName: 'MyTable',
|
|
1454
|
+
DatabaseName: 'my_database',
|
|
1455
|
+
Name: 'my_table',
|
|
1456
|
+
Schema: {
|
|
1457
|
+
Type: 'struct',
|
|
1458
|
+
Fields: [
|
|
1459
|
+
{ Name: 'column', Type: 'string', Id: 1, Required: true }
|
|
1460
|
+
]
|
|
1461
|
+
},
|
|
1462
|
+
Location: 's3://fake/location',
|
|
1463
|
+
EnableOrphanFileDeletion: true
|
|
1464
|
+
})).toThrow(/You must provide an OrphanFileDeletionRoleArn when EnableOrphanFileDeletion is true/);
|
|
1465
|
+
});
|
|
1400
1466
|
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
{ Conditions: { Always: cf.equals('1', '1') } },
|
|
1440
|
-
{ Resources: { AnotherThing: { Type: 'AWS::SNS::Topic' } } },
|
|
1441
|
-
db
|
|
1442
|
-
);
|
|
1443
|
-
if (update) fixtures.update('glue-parquet-table-no-defaults', template);
|
|
1444
|
-
assert.deepEqual(
|
|
1445
|
-
noUndefined(template),
|
|
1446
|
-
fixtures.get('glue-parquet-table-no-defaults'),
|
|
1447
|
-
'expected resources generated without defaults'
|
|
1448
|
-
);
|
|
1467
|
+
test('expected resources generated with orphan file deletion using default settings', () => {
|
|
1468
|
+
const db = new cf.shortcuts.GlueIcebergTable({
|
|
1469
|
+
LogicalName: 'MyTable',
|
|
1470
|
+
DatabaseName: 'my_database',
|
|
1471
|
+
Name: 'my_table',
|
|
1472
|
+
Schema: {
|
|
1473
|
+
Type: 'struct',
|
|
1474
|
+
Fields: [
|
|
1475
|
+
{ Name: 'column', Type: 'string', Id: 1, Required: true }
|
|
1476
|
+
]
|
|
1477
|
+
},
|
|
1478
|
+
Location: 's3://fake/location',
|
|
1479
|
+
EnableOrphanFileDeletion: true,
|
|
1480
|
+
OrphanFileDeletionRoleArn: 'arn:aws:iam::123456789012:role/OrphanFileDeletionRole'
|
|
1481
|
+
});
|
|
1482
|
+
|
|
1483
|
+
const template = cf.merge(db);
|
|
1484
|
+
if (update) fixtures.update('glue-iceberg-table-with-orphan-deletion-defaults', template);
|
|
1485
|
+
expect(noUndefined(template)).toEqual(fixtures.get('glue-iceberg-table-with-orphan-deletion-defaults'));
|
|
1486
|
+
});
|
|
1487
|
+
|
|
1488
|
+
test('expected resources generated with orphan file deletion using custom settings', () => {
|
|
1489
|
+
const db = new cf.shortcuts.GlueIcebergTable({
|
|
1490
|
+
LogicalName: 'MyTable',
|
|
1491
|
+
DatabaseName: 'my_database',
|
|
1492
|
+
Name: 'my_table',
|
|
1493
|
+
Schema: {
|
|
1494
|
+
Type: 'struct',
|
|
1495
|
+
Fields: [
|
|
1496
|
+
{ Name: 'column', Type: 'string', Id: 1, Required: true }
|
|
1497
|
+
]
|
|
1498
|
+
},
|
|
1499
|
+
Location: 's3://fake/location',
|
|
1500
|
+
EnableOrphanFileDeletion: true,
|
|
1501
|
+
OrphanFileDeletionRoleArn: cf.getAtt('OrphanFileDeletionRole', 'Arn'),
|
|
1502
|
+
OrphanFileRetentionPeriodInDays: 7,
|
|
1503
|
+
OrphanFileDeletionLocation: 's3://fake/location/subdir'
|
|
1504
|
+
});
|
|
1449
1505
|
|
|
1450
|
-
|
|
1506
|
+
const template = cf.merge(
|
|
1507
|
+
{ Resources: { OrphanFileDeletionRole: { Type: 'AWS::IAM::Role', Properties: { AssumeRolePolicyDocument: {} } } } },
|
|
1508
|
+
db
|
|
1509
|
+
);
|
|
1510
|
+
if (update) fixtures.update('glue-iceberg-table-with-orphan-deletion-custom', template);
|
|
1511
|
+
expect(noUndefined(template)).toEqual(fixtures.get('glue-iceberg-table-with-orphan-deletion-custom'));
|
|
1512
|
+
});
|
|
1513
|
+
|
|
1514
|
+
test('expected resources generated with all three optimizers using same role', () => {
|
|
1515
|
+
const db = new cf.shortcuts.GlueIcebergTable({
|
|
1516
|
+
LogicalName: 'MyTable',
|
|
1517
|
+
DatabaseName: 'my_database',
|
|
1518
|
+
Name: 'my_table',
|
|
1519
|
+
Schema: {
|
|
1520
|
+
Type: 'struct',
|
|
1521
|
+
Fields: [
|
|
1522
|
+
{ Name: 'column', Type: 'string', Id: 1, Required: true }
|
|
1523
|
+
]
|
|
1524
|
+
},
|
|
1525
|
+
Location: 's3://fake/location',
|
|
1526
|
+
EnableOptimizer: true,
|
|
1527
|
+
OptimizerRoleArn: 'arn:aws:iam::123456789012:role/SharedRole',
|
|
1528
|
+
EnableCompaction: true,
|
|
1529
|
+
CompactionRoleArn: 'arn:aws:iam::123456789012:role/SharedRole',
|
|
1530
|
+
EnableOrphanFileDeletion: true,
|
|
1531
|
+
OrphanFileDeletionRoleArn: 'arn:aws:iam::123456789012:role/SharedRole'
|
|
1532
|
+
});
|
|
1533
|
+
|
|
1534
|
+
const template = cf.merge(db);
|
|
1535
|
+
if (update) fixtures.update('glue-iceberg-table-with-all-optimizers', template);
|
|
1536
|
+
expect(noUndefined(template)).toEqual(fixtures.get('glue-iceberg-table-with-all-optimizers'));
|
|
1537
|
+
});
|
|
1451
1538
|
});
|
|
1452
1539
|
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
() => new cf.shortcuts.GluePrestoView()
|
|
1456
|
-
|
|
1457
|
-
'throws without options'
|
|
1458
|
-
);
|
|
1459
|
-
assert.throws(
|
|
1460
|
-
() => new cf.shortcuts.GluePrestoView({}),
|
|
1461
|
-
/You must provide a DatabaseName, Columns, and OriginalSql/,
|
|
1462
|
-
'throws without required parameters'
|
|
1463
|
-
);
|
|
1540
|
+
describe('[shortcuts] glue view', () => {
|
|
1541
|
+
test('throws without options', () => {
|
|
1542
|
+
expect(() => new cf.shortcuts.GluePrestoView()).toThrow('Options required');
|
|
1543
|
+
});
|
|
1464
1544
|
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
Name: 'my_view',
|
|
1469
|
-
Columns: [
|
|
1470
|
-
{ Name: 'column', Type: 'string' }
|
|
1471
|
-
],
|
|
1472
|
-
OriginalSql: 'SELECT * FROM another.table'
|
|
1473
|
-
});
|
|
1474
|
-
|
|
1475
|
-
let template = cf.merge(db);
|
|
1476
|
-
if (update) fixtures.update('glue-view-defaults', template);
|
|
1477
|
-
assert.deepEqual(
|
|
1478
|
-
noUndefined(template),
|
|
1479
|
-
fixtures.get('glue-view-defaults'),
|
|
1480
|
-
'expected resources generated with defaults'
|
|
1481
|
-
);
|
|
1545
|
+
test('throws without required parameters', () => {
|
|
1546
|
+
expect(() => new cf.shortcuts.GluePrestoView({})).toThrow(/You must provide a DatabaseName, Columns, and OriginalSql/);
|
|
1547
|
+
});
|
|
1482
1548
|
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1549
|
+
test('expected resources generated with defaults', () => {
|
|
1550
|
+
const db = new cf.shortcuts.GluePrestoView({
|
|
1551
|
+
LogicalName: 'MyView',
|
|
1552
|
+
DatabaseName: 'my_database',
|
|
1553
|
+
Name: 'my_view',
|
|
1554
|
+
Columns: [
|
|
1555
|
+
{ Name: 'column', Type: 'string' }
|
|
1556
|
+
],
|
|
1557
|
+
OriginalSql: 'SELECT * FROM another.table'
|
|
1558
|
+
});
|
|
1559
|
+
|
|
1560
|
+
const template = cf.merge(db);
|
|
1561
|
+
if (update) fixtures.update('glue-view-defaults', template);
|
|
1562
|
+
expect(noUndefined(template)).toEqual(fixtures.get('glue-view-defaults'));
|
|
1563
|
+
});
|
|
1564
|
+
|
|
1565
|
+
test('expected resources generated without defaults', () => {
|
|
1566
|
+
const db = new cf.shortcuts.GluePrestoView({
|
|
1567
|
+
LogicalName: 'MyTable',
|
|
1568
|
+
DatabaseName: 'my_database',
|
|
1569
|
+
Name: 'my_view',
|
|
1570
|
+
Columns: [
|
|
1571
|
+
{ Name: 'column', Type: 'string' }
|
|
1572
|
+
],
|
|
1573
|
+
OriginalSql: 'SELECT * FROM another.table',
|
|
1574
|
+
CatalogId: '1234',
|
|
1575
|
+
Owner: 'Team',
|
|
1576
|
+
Parameters: { table: 'params' },
|
|
1577
|
+
Description: 'my_view description',
|
|
1578
|
+
Retention: 12,
|
|
1579
|
+
TableType: 'EXTERNAL_TABLE',
|
|
1580
|
+
BucketColumns: ['column'],
|
|
1581
|
+
Compressed: true,
|
|
1582
|
+
Location: 's3://fake/location',
|
|
1583
|
+
InputFormat: 'fake.input.format',
|
|
1584
|
+
OutputFormat: 'fake.output.format',
|
|
1585
|
+
StorageParameters: { storage: 'parameters' },
|
|
1586
|
+
SerdeInfo: {
|
|
1587
|
+
SerializationLibrary: 'fake.serde'
|
|
1588
|
+
},
|
|
1589
|
+
SkewedColumns: {
|
|
1590
|
+
SkewedColumnNames: ['column'],
|
|
1591
|
+
SkewedColumnValueLocationMap: { fake: 'map' },
|
|
1592
|
+
SkewedColumnValues: ['value']
|
|
1593
|
+
},
|
|
1594
|
+
SortColumns: [
|
|
1595
|
+
{ Column: 'column', SortOrder: 0 }
|
|
1596
|
+
],
|
|
1597
|
+
StoredAsSubdirectory: true,
|
|
1598
|
+
SqlVariables: { env: { Ref: 'AWS::StackName' } },
|
|
1599
|
+
Condition: 'Always',
|
|
1600
|
+
DependsOn: 'AnotherThing'
|
|
1601
|
+
});
|
|
1531
1602
|
|
|
1532
|
-
|
|
1603
|
+
const template = cf.merge(
|
|
1604
|
+
{ Conditions: { Always: cf.equals('1', '1') } },
|
|
1605
|
+
{ Resources: { AnotherThing: { Type: 'AWS::SNS::Topic' } } },
|
|
1606
|
+
db
|
|
1607
|
+
);
|
|
1608
|
+
if (update) fixtures.update('glue-view-no-defaults', template);
|
|
1609
|
+
expect(noUndefined(template)).toEqual(fixtures.get('glue-view-no-defaults'));
|
|
1610
|
+
});
|
|
1533
1611
|
});
|
|
1534
1612
|
|
|
1535
1613
|
const normalizeDeployment = (template) => {
|
|
@@ -1540,230 +1618,192 @@ const normalizeDeployment = (template) => {
|
|
|
1540
1618
|
return JSON.parse(str);
|
|
1541
1619
|
};
|
|
1542
1620
|
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
() => new cf.shortcuts.hookshot.Passthrough()
|
|
1546
|
-
|
|
1547
|
-
'throws without options'
|
|
1548
|
-
);
|
|
1549
|
-
assert.throws(
|
|
1550
|
-
() => new cf.shortcuts.hookshot.Passthrough({}),
|
|
1551
|
-
/You must provide a Prefix, and PassthroughTo/,
|
|
1552
|
-
'throws without required parameters'
|
|
1553
|
-
);
|
|
1621
|
+
describe('[shortcuts] hookshot passthrough', () => {
|
|
1622
|
+
test('throws without options', () => {
|
|
1623
|
+
expect(() => new cf.shortcuts.hookshot.Passthrough()).toThrow('Options required');
|
|
1624
|
+
});
|
|
1554
1625
|
|
|
1555
|
-
|
|
1556
|
-
() =>
|
|
1557
|
-
|
|
1558
|
-
Prefix: 'Pass',
|
|
1559
|
-
PassthroughTo: 'Destination',
|
|
1560
|
-
LoggingLevel: 'HAM'
|
|
1561
|
-
}),
|
|
1562
|
-
/LoggingLevel must be one of OFF, INFO, or ERROR/,
|
|
1563
|
-
'throws with invalid LoggingLevel'
|
|
1564
|
-
);
|
|
1626
|
+
test('throws without required parameters', () => {
|
|
1627
|
+
expect(() => new cf.shortcuts.hookshot.Passthrough({})).toThrow(/You must provide a Prefix, and PassthroughTo/);
|
|
1628
|
+
});
|
|
1565
1629
|
|
|
1566
|
-
|
|
1567
|
-
() =>
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
}),
|
|
1574
|
-
/Only valid nodejs runtimes are supported for hookshot lambdas, received: 'python3.7'/,
|
|
1575
|
-
'throws with invalid lambda Runtime python3.7'
|
|
1576
|
-
);
|
|
1630
|
+
test('throws with invalid LoggingLevel', () => {
|
|
1631
|
+
expect(() => new cf.shortcuts.hookshot.Passthrough({
|
|
1632
|
+
Prefix: 'Pass',
|
|
1633
|
+
PassthroughTo: 'Destination',
|
|
1634
|
+
LoggingLevel: 'HAM'
|
|
1635
|
+
})).toThrow(/LoggingLevel must be one of OFF, INFO, or ERROR/);
|
|
1636
|
+
});
|
|
1577
1637
|
|
|
1578
|
-
|
|
1579
|
-
() =>
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1638
|
+
test('throws with invalid lambda Runtime python3.7', () => {
|
|
1639
|
+
expect(() => new cf.shortcuts.hookshot.Passthrough({
|
|
1640
|
+
Prefix: 'Pass',
|
|
1641
|
+
PassthroughTo: 'Destination',
|
|
1642
|
+
LoggingLevel: 'INFO',
|
|
1643
|
+
Runtime: 'python3.7'
|
|
1644
|
+
})).toThrow(/Only valid nodejs runtimes are supported for hookshot lambdas, received: 'python3.7'/);
|
|
1645
|
+
});
|
|
1646
|
+
|
|
1647
|
+
test('throws with invalid lambda Runtime nodejs16.x', () => {
|
|
1648
|
+
expect(() => new cf.shortcuts.hookshot.Passthrough({
|
|
1649
|
+
Prefix: 'Pass',
|
|
1650
|
+
PassthroughTo: 'Destination',
|
|
1651
|
+
LoggingLevel: 'INFO',
|
|
1652
|
+
Runtime: 'nodejs16.x'
|
|
1653
|
+
})).toThrow(/Only nodejs runtimes >= 18 are supported for hookshot lambdas, received: 'nodejs16.x'/);
|
|
1654
|
+
});
|
|
1589
1655
|
|
|
1590
|
-
const
|
|
1656
|
+
const getDestinationLambda = () => new cf.shortcuts.Lambda({
|
|
1591
1657
|
LogicalName: 'Destination',
|
|
1592
1658
|
Code: {
|
|
1593
1659
|
ZipFile: 'module.exports.handler = (e, c, cb) => cb();'
|
|
1594
1660
|
}
|
|
1595
1661
|
});
|
|
1596
1662
|
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1663
|
+
test('expected resources generated with defaults', () => {
|
|
1664
|
+
const to = getDestinationLambda();
|
|
1665
|
+
const passthrough = new cf.shortcuts.hookshot.Passthrough({
|
|
1666
|
+
Prefix: 'Pass',
|
|
1667
|
+
PassthroughTo: 'Destination'
|
|
1668
|
+
});
|
|
1669
|
+
|
|
1670
|
+
const template = cf.merge(passthrough, to);
|
|
1671
|
+
if (update) fixtures.update('hookshot-passthrough', template);
|
|
1672
|
+
expect(normalizeDeployment(noUndefined(template))).toEqual(normalizeDeployment(fixtures.get('hookshot-passthrough')));
|
|
1600
1673
|
});
|
|
1601
1674
|
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1675
|
+
test('expected resources generated with alarm config', () => {
|
|
1676
|
+
const to = getDestinationLambda();
|
|
1677
|
+
const passthrough = new cf.shortcuts.hookshot.Passthrough({
|
|
1678
|
+
Prefix: 'Pass',
|
|
1679
|
+
PassthroughTo: 'Destination',
|
|
1680
|
+
AlarmActions: ['devnull@mapbox.com']
|
|
1681
|
+
});
|
|
1609
1682
|
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
AlarmActions: ['devnull@mapbox.com']
|
|
1683
|
+
const template = cf.merge(passthrough, to);
|
|
1684
|
+
if (update) fixtures.update('hookshot-passthrough-alarms', template);
|
|
1685
|
+
expect(normalizeDeployment(noUndefined(template))).toEqual(normalizeDeployment(fixtures.get('hookshot-passthrough-alarms')));
|
|
1614
1686
|
});
|
|
1615
1687
|
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1688
|
+
test('expected resources generated with configured LoggingLevel', () => {
|
|
1689
|
+
const to = getDestinationLambda();
|
|
1690
|
+
const passthrough = new cf.shortcuts.hookshot.Passthrough({
|
|
1691
|
+
Prefix: 'Pass',
|
|
1692
|
+
PassthroughTo: 'Destination',
|
|
1693
|
+
LoggingLevel: 'INFO'
|
|
1694
|
+
});
|
|
1623
1695
|
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
LoggingLevel: 'INFO'
|
|
1696
|
+
const template = cf.merge(passthrough, to);
|
|
1697
|
+
if (update) fixtures.update('hookshot-passthrough-logging', template);
|
|
1698
|
+
expect(normalizeDeployment(noUndefined(template))).toEqual(normalizeDeployment(fixtures.get('hookshot-passthrough-logging')));
|
|
1628
1699
|
});
|
|
1629
1700
|
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1701
|
+
test('expected resources generated with detailed logging and metrics', () => {
|
|
1702
|
+
const to = getDestinationLambda();
|
|
1703
|
+
const passthrough = new cf.shortcuts.hookshot.Passthrough({
|
|
1704
|
+
Prefix: 'Pass',
|
|
1705
|
+
PassthroughTo: 'Destination',
|
|
1706
|
+
DataTraceEnabled: true,
|
|
1707
|
+
MetricsEnabled: true
|
|
1708
|
+
});
|
|
1637
1709
|
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
DataTraceEnabled: true,
|
|
1642
|
-
MetricsEnabled: true
|
|
1710
|
+
const template = cf.merge(passthrough, to);
|
|
1711
|
+
if (update) fixtures.update('hookshot-passthrough-enhanced-logging', template);
|
|
1712
|
+
expect(normalizeDeployment(noUndefined(template))).toEqual(normalizeDeployment(fixtures.get('hookshot-passthrough-enhanced-logging')));
|
|
1643
1713
|
});
|
|
1644
1714
|
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
passthrough = new cf.shortcuts.hookshot.Passthrough({
|
|
1655
|
-
Prefix: 'Pass',
|
|
1656
|
-
PassthroughTo: 'Destination',
|
|
1657
|
-
DataTraceEnabled: true,
|
|
1658
|
-
MetricsEnabled: true,
|
|
1659
|
-
LoggingLevel: 'INFO'
|
|
1660
|
-
});
|
|
1661
|
-
|
|
1662
|
-
template = cf.merge(passthrough, to);
|
|
1663
|
-
if (update)
|
|
1664
|
-
fixtures.update('hookshot-passthrough-full-blown-logging', template);
|
|
1665
|
-
assert.deepEqual(
|
|
1666
|
-
normalizeDeployment(noUndefined(template)),
|
|
1667
|
-
normalizeDeployment(
|
|
1668
|
-
fixtures.get('hookshot-passthrough-full-blown-logging')
|
|
1669
|
-
),
|
|
1670
|
-
'LoggingLevel respected with detailed logging and metrics'
|
|
1671
|
-
);
|
|
1715
|
+
test('LoggingLevel respected with detailed logging and metrics', () => {
|
|
1716
|
+
const to = getDestinationLambda();
|
|
1717
|
+
const passthrough = new cf.shortcuts.hookshot.Passthrough({
|
|
1718
|
+
Prefix: 'Pass',
|
|
1719
|
+
PassthroughTo: 'Destination',
|
|
1720
|
+
DataTraceEnabled: true,
|
|
1721
|
+
MetricsEnabled: true,
|
|
1722
|
+
LoggingLevel: 'INFO'
|
|
1723
|
+
});
|
|
1672
1724
|
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
AccessLogFormat: '{ "requestId":"$context.requestId" }'
|
|
1725
|
+
const template = cf.merge(passthrough, to);
|
|
1726
|
+
if (update) fixtures.update('hookshot-passthrough-full-blown-logging', template);
|
|
1727
|
+
expect(normalizeDeployment(noUndefined(template))).toEqual(normalizeDeployment(fixtures.get('hookshot-passthrough-full-blown-logging')));
|
|
1677
1728
|
});
|
|
1678
1729
|
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
);
|
|
1730
|
+
test('expected resources generated with access logs', () => {
|
|
1731
|
+
const to = getDestinationLambda();
|
|
1732
|
+
const passthrough = new cf.shortcuts.hookshot.Passthrough({
|
|
1733
|
+
Prefix: 'Pass',
|
|
1734
|
+
PassthroughTo: 'Destination',
|
|
1735
|
+
AccessLogFormat: '{ "requestId":"$context.requestId" }'
|
|
1736
|
+
});
|
|
1687
1737
|
|
|
1688
|
-
|
|
1738
|
+
const template = cf.merge(passthrough, to);
|
|
1739
|
+
if (update) fixtures.update('hookshot-passthrough-access-log-format', template);
|
|
1740
|
+
expect(normalizeDeployment(noUndefined(template))).toEqual(normalizeDeployment(fixtures.get('hookshot-passthrough-access-log-format')));
|
|
1741
|
+
});
|
|
1689
1742
|
});
|
|
1690
1743
|
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
() => new cf.shortcuts.hookshot.Github(),
|
|
1694
|
-
|
|
1695
|
-
'throws without required parameters'
|
|
1696
|
-
);
|
|
1744
|
+
describe('[shortcuts] hookshot github', () => {
|
|
1745
|
+
test('throws without required parameters', () => {
|
|
1746
|
+
expect(() => new cf.shortcuts.hookshot.Github()).toThrow(/You must provide a Prefix, and PassthroughTo/);
|
|
1747
|
+
});
|
|
1697
1748
|
|
|
1698
|
-
|
|
1699
|
-
() =>
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
/Only valid nodejs runtimes are supported for hookshot lambdas, received: 'python3.7'/,
|
|
1706
|
-
'throws with invalid lambda Runtime python3.7'
|
|
1707
|
-
);
|
|
1749
|
+
test('throws with invalid lambda Runtime python3.7', () => {
|
|
1750
|
+
expect(() => new cf.shortcuts.hookshot.Github({
|
|
1751
|
+
Prefix: 'Pass',
|
|
1752
|
+
PassthroughTo: 'Destination',
|
|
1753
|
+
Runtime: 'python3.7'
|
|
1754
|
+
})).toThrow(/Only valid nodejs runtimes are supported for hookshot lambdas, received: 'python3.7'/);
|
|
1755
|
+
});
|
|
1708
1756
|
|
|
1709
|
-
|
|
1710
|
-
() =>
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
/Only nodejs runtimes >= 18 are supported for hookshot lambdas, received: 'nodejs16.x'/,
|
|
1717
|
-
'throws with invalid lambda Runtime nodejs16.x'
|
|
1718
|
-
);
|
|
1757
|
+
test('throws with invalid lambda Runtime nodejs16.x', () => {
|
|
1758
|
+
expect(() => new cf.shortcuts.hookshot.Github({
|
|
1759
|
+
Prefix: 'Pass',
|
|
1760
|
+
PassthroughTo: 'Destination',
|
|
1761
|
+
Runtime: 'nodejs16.x'
|
|
1762
|
+
})).toThrow(/Only nodejs runtimes >= 18 are supported for hookshot lambdas, received: 'nodejs16.x'/);
|
|
1763
|
+
});
|
|
1719
1764
|
|
|
1720
|
-
const
|
|
1765
|
+
const getDestinationLambda = () => new cf.shortcuts.Lambda({
|
|
1721
1766
|
LogicalName: 'Destination',
|
|
1722
1767
|
Code: {
|
|
1723
1768
|
ZipFile: 'module.exports.handler = (e, c, cb) => cb();'
|
|
1724
1769
|
}
|
|
1725
1770
|
});
|
|
1726
1771
|
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
if (update) fixtures.update('hookshot-github', template);
|
|
1734
|
-
assert.deepEqual(
|
|
1735
|
-
normalizeDeployment(noUndefined(template)),
|
|
1736
|
-
normalizeDeployment(fixtures.get('hookshot-github')),
|
|
1737
|
-
'expected resources generated with defaults'
|
|
1738
|
-
);
|
|
1772
|
+
test('expected resources generated with defaults', () => {
|
|
1773
|
+
const to = getDestinationLambda();
|
|
1774
|
+
const github = new cf.shortcuts.hookshot.Github({
|
|
1775
|
+
Prefix: 'Pass',
|
|
1776
|
+
PassthroughTo: 'Destination'
|
|
1777
|
+
});
|
|
1739
1778
|
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
WebhookSecret: 'abc123'
|
|
1779
|
+
const template = cf.merge(github, to);
|
|
1780
|
+
if (update) fixtures.update('hookshot-github', template);
|
|
1781
|
+
expect(normalizeDeployment(noUndefined(template))).toEqual(normalizeDeployment(fixtures.get('hookshot-github')));
|
|
1744
1782
|
});
|
|
1745
1783
|
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1784
|
+
test('expected resources generated when secret passed as string', () => {
|
|
1785
|
+
const to = getDestinationLambda();
|
|
1786
|
+
const github = new cf.shortcuts.hookshot.Github({
|
|
1787
|
+
Prefix: 'Pass',
|
|
1788
|
+
PassthroughTo: 'Destination',
|
|
1789
|
+
WebhookSecret: 'abc123'
|
|
1790
|
+
});
|
|
1753
1791
|
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
});
|
|
1759
|
-
const Parameters = { SomeParameter: { Type: 'String' } };
|
|
1760
|
-
template = cf.merge(github, to, { Parameters });
|
|
1761
|
-
if (update) fixtures.update('hookshot-github-secret-ref', template);
|
|
1762
|
-
assert.deepEqual(
|
|
1763
|
-
normalizeDeployment(noUndefined(template)),
|
|
1764
|
-
normalizeDeployment(fixtures.get('hookshot-github-secret-ref')),
|
|
1765
|
-
'expected resources generated when secret passed as ref'
|
|
1766
|
-
);
|
|
1792
|
+
const template = cf.merge(github, to);
|
|
1793
|
+
if (update) fixtures.update('hookshot-github-secret-string', template);
|
|
1794
|
+
expect(normalizeDeployment(noUndefined(template))).toEqual(normalizeDeployment(fixtures.get('hookshot-github-secret-string')));
|
|
1795
|
+
});
|
|
1767
1796
|
|
|
1768
|
-
|
|
1797
|
+
test('expected resources generated when secret passed as ref', () => {
|
|
1798
|
+
const to = getDestinationLambda();
|
|
1799
|
+
const github = new cf.shortcuts.hookshot.Github({
|
|
1800
|
+
Prefix: 'Pass',
|
|
1801
|
+
PassthroughTo: 'Destination',
|
|
1802
|
+
WebhookSecret: cf.ref('SomeParameter')
|
|
1803
|
+
});
|
|
1804
|
+
const Parameters = { SomeParameter: { Type: 'String' } };
|
|
1805
|
+
const template = cf.merge(github, to, { Parameters });
|
|
1806
|
+
if (update) fixtures.update('hookshot-github-secret-ref', template);
|
|
1807
|
+
expect(normalizeDeployment(noUndefined(template))).toEqual(normalizeDeployment(fixtures.get('hookshot-github-secret-ref')));
|
|
1808
|
+
});
|
|
1769
1809
|
});
|