1 | 'use strict'
|
2 |
|
3 | const path = require('path')
|
4 | const os = require('os')
|
5 | const fs = require('fs-extra')
|
6 | const lambda = require(path.join(__dirname, '..', 'lib', 'main'))
|
7 | const Zip = require('node-zip')
|
8 | const { assert } = require('chai')
|
9 | const awsMock = require('aws-sdk-mock')
|
10 | awsMock.setSDK(path.resolve('node_modules/aws-sdk'))
|
11 |
|
12 | const originalProgram = {
|
13 | environment: 'development',
|
14 | accessKey: 'key',
|
15 | secretKey: 'secret',
|
16 | sessionToken: 'token',
|
17 | functionName: '___node-lambda',
|
18 | handler: 'index.handler',
|
19 | role: 'some:arn:aws:iam::role',
|
20 | memorySize: 128,
|
21 | timeout: 3,
|
22 | description: '',
|
23 | runtime: 'nodejs14.x',
|
24 | deadLetterConfigTargetArn: '',
|
25 | tracingConfig: '',
|
26 | Layers: '',
|
27 | retentionInDays: 30,
|
28 | region: 'us-east-1,us-west-2,eu-west-1',
|
29 | eventFile: 'event.json',
|
30 | eventSourceFile: '',
|
31 | contextFile: 'context.json',
|
32 | deployTimeout: 120000,
|
33 | prebuiltDirectory: '',
|
34 | proxy: ''
|
35 | }
|
36 |
|
37 | let program = {}
|
38 | let codeDirectory = lambda._codeDirectory()
|
39 |
|
40 | const _timeout = function (params) {
|
41 |
|
42 |
|
43 |
|
44 | if (process.platform !== 'win32') {
|
45 | params.this.timeout(params.sec * 1000)
|
46 | }
|
47 | }
|
48 |
|
49 |
|
50 | const lambdaMockSettings = {
|
51 | addPermission: {},
|
52 | getFunction: {
|
53 | Code: {},
|
54 | Configuration: {},
|
55 | FunctionArn: 'Lambda.getFunction.mock.FunctionArn'
|
56 | },
|
57 | createFunction: {
|
58 | FunctionArn: 'Lambda.createFunction.mock.FunctionArn',
|
59 | FunctionName: 'Lambda.createFunction.mock.FunctionName'
|
60 | },
|
61 | listEventSourceMappings: {
|
62 | EventSourceMappings: [{
|
63 | EventSourceArn: 'Lambda.listEventSourceMappings.mock.EventSourceArn',
|
64 | UUID: 'Lambda.listEventSourceMappings.mock.UUID'
|
65 | }]
|
66 | },
|
67 | updateFunctionCode: {
|
68 | FunctionArn: 'Lambda.updateFunctionCode.mock.FunctionArn',
|
69 | FunctionName: 'Lambda.updateFunctionCode.mock.FunctionName'
|
70 | },
|
71 | updateFunctionConfiguration: {
|
72 | FunctionArn: 'Lambda.updateFunctionConfiguration.mock.FunctionArn',
|
73 | FunctionName: 'Lambda.updateFunctionConfiguration.mock.FunctionName'
|
74 | },
|
75 | createEventSourceMapping: {
|
76 | EventSourceArn: 'Lambda.createEventSourceMapping.mock.EventSourceArn',
|
77 | FunctionName: 'Lambda.createEventSourceMapping.mock.EventSourceArn'
|
78 | },
|
79 | updateEventSourceMapping: {
|
80 | EventSourceArn: 'Lambda.updateEventSourceMapping.mock.EventSourceArn',
|
81 | FunctionName: 'Lambda.updateEventSourceMapping.mock.EventSourceArn'
|
82 | },
|
83 | deleteEventSourceMapping: {
|
84 | EventSourceArn: 'Lambda.deleteEventSourceMapping.mock.EventSourceArn',
|
85 | FunctionName: 'Lambda.deleteEventSourceMapping.mock.EventSourceArn'
|
86 | },
|
87 | listTags: {
|
88 | Tags: { tag1: 'key1' }
|
89 | },
|
90 | untagResource: {},
|
91 | tagResource: {}
|
92 | }
|
93 |
|
94 | const _mockSetting = () => {
|
95 | awsMock.mock('CloudWatchEvents', 'putRule', (params, callback) => {
|
96 | callback(null, {})
|
97 | })
|
98 | awsMock.mock('CloudWatchEvents', 'putTargets', (params, callback) => {
|
99 | callback(null, {})
|
100 | })
|
101 | awsMock.mock('CloudWatchLogs', 'createLogGroup', (params, callback) => {
|
102 | callback(null, {})
|
103 | })
|
104 | awsMock.mock('CloudWatchLogs', 'putRetentionPolicy', (params, callback) => {
|
105 | callback(null, {})
|
106 | })
|
107 | awsMock.mock('S3', 'putBucketNotificationConfiguration', (params, callback) => {
|
108 | callback(null, {})
|
109 | })
|
110 | awsMock.mock('S3', 'putObject', (params, callback) => {
|
111 | callback(null, { test: 'putObject' })
|
112 | })
|
113 |
|
114 | Object.keys(lambdaMockSettings).forEach((method) => {
|
115 | awsMock.mock('Lambda', method, (params, callback) => {
|
116 | callback(null, lambdaMockSettings[method])
|
117 | })
|
118 | })
|
119 |
|
120 | return require('aws-sdk')
|
121 | }
|
122 |
|
123 | const _awsRestore = () => {
|
124 | awsMock.restore('CloudWatchEvents')
|
125 | awsMock.restore('CloudWatchLogs')
|
126 | awsMock.restore('S3')
|
127 | awsMock.restore('Lambda')
|
128 | }
|
129 |
|
130 |
|
131 | describe('lib/main', function () {
|
132 | if (process.platform === 'win32') {
|
133 |
|
134 |
|
135 | this.timeout(60000)
|
136 | }
|
137 |
|
138 | let aws = null
|
139 | let awsLambda = null
|
140 | before(() => {
|
141 | aws = _mockSetting()
|
142 | awsLambda = new aws.Lambda({ apiVersion: '2015-03-31' })
|
143 | })
|
144 | after(() => _awsRestore())
|
145 |
|
146 | beforeEach(() => {
|
147 | program = Object.assign({}, originalProgram)
|
148 | })
|
149 |
|
150 | it('version should be set', () => {
|
151 | assert.equal(lambda.version, '0.18.0')
|
152 | })
|
153 |
|
154 | describe('_codeDirectory', () => {
|
155 | it('Working directory in the /tmp directory', () => {
|
156 | assert.equal(
|
157 | lambda._codeDirectory(),
|
158 | path.join(fs.realpathSync(os.tmpdir()), 'node-lambda-lambda')
|
159 | )
|
160 | })
|
161 | })
|
162 |
|
163 | describe('_runHandler', () => {
|
164 | it('context methods is a function', (done) => {
|
165 | const handler = (event, context, callback) => {
|
166 | assert.isFunction(context.succeed)
|
167 | assert.isFunction(context.fail)
|
168 | assert.isFunction(context.done)
|
169 | done()
|
170 | }
|
171 | lambda._runHandler(handler, {}, program, {})
|
172 | })
|
173 | })
|
174 |
|
175 | describe('_isFunctionDoesNotExist', () => {
|
176 | it('=== true', () => {
|
177 | const err = {
|
178 | code: 'ResourceNotFoundException',
|
179 | message: 'Function not found: arn:aws:lambda:XXX'
|
180 | }
|
181 | assert.isTrue(lambda._isFunctionDoesNotExist(err))
|
182 | })
|
183 |
|
184 | it('=== false', () => {
|
185 | const err = {
|
186 | code: 'MissingRequiredParameter',
|
187 | message: 'Missing required key \'FunctionName\' in params'
|
188 | }
|
189 | assert.isFalse(lambda._isFunctionDoesNotExist(err))
|
190 | })
|
191 | })
|
192 |
|
193 | describe('_isUseS3', () => {
|
194 | it('=== true', () => {
|
195 | assert.isTrue(lambda._isUseS3({ deployUseS3: true }))
|
196 | assert.isTrue(lambda._isUseS3({ deployUseS3: 'true' }))
|
197 | })
|
198 |
|
199 | it('=== false', () => {
|
200 | [
|
201 | {},
|
202 | { deployUseS3: false },
|
203 | { deployUseS3: 'false' },
|
204 | { deployUseS3: 'foo' }
|
205 | ].forEach((params) => {
|
206 | assert.isFalse(lambda._isUseS3(params), params)
|
207 | })
|
208 | })
|
209 | })
|
210 |
|
211 | describe('_useECR', () => {
|
212 | it('=== true', () => {
|
213 | assert.isTrue(lambda._useECR({ imageUri: 'xxx' }))
|
214 | })
|
215 |
|
216 | it('=== false', () => {
|
217 | [
|
218 | {},
|
219 | { imageUri: null },
|
220 | { imageUri: '' }
|
221 | ].forEach((params) => {
|
222 | assert.isFalse(lambda._useECR(params), params)
|
223 | })
|
224 | })
|
225 | })
|
226 |
|
227 | describe('_params', () => {
|
228 |
|
229 | const functionNamePattern =
|
230 | /(arn:aws:lambda:)?([a-z]{2}-[a-z]+-\d{1}:)?(\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\$LATEST|[a-zA-Z0-9-_]+))?/
|
231 | it('appends environment to original functionName', () => {
|
232 | const params = lambda._params(program)
|
233 | assert.equal(params.FunctionName, '___node-lambda-development')
|
234 | assert.match(params.FunctionName, functionNamePattern)
|
235 | })
|
236 |
|
237 | it('appends environment to original functionName (production)', () => {
|
238 | program.environment = 'production'
|
239 | const params = lambda._params(program)
|
240 | assert.equal(params.FunctionName, '___node-lambda-production')
|
241 | assert.match(params.FunctionName, functionNamePattern)
|
242 | })
|
243 |
|
244 | it('appends version to original functionName', () => {
|
245 | program.lambdaVersion = '2015-02-01'
|
246 | const params = lambda._params(program)
|
247 | assert.equal(params.FunctionName, '___node-lambda-development-2015-02-01')
|
248 | assert.match(params.FunctionName, functionNamePattern)
|
249 | })
|
250 |
|
251 | it('appends version to original functionName (value not allowed by AWS)', () => {
|
252 | program.lambdaVersion = '2015.02.01'
|
253 | const params = lambda._params(program)
|
254 | assert.equal(params.FunctionName, '___node-lambda-development-2015_02_01')
|
255 | assert.match(params.FunctionName, functionNamePattern)
|
256 | })
|
257 |
|
258 | it('appends VpcConfig to params when vpc params set', () => {
|
259 | program.vpcSubnets = 'subnet-00000000,subnet-00000001,subnet-00000002'
|
260 | program.vpcSecurityGroups = 'sg-00000000,sg-00000001,sg-00000002'
|
261 | const params = lambda._params(program)
|
262 | assert.equal(params.VpcConfig.SubnetIds[0], program.vpcSubnets.split(',')[0])
|
263 | assert.equal(params.VpcConfig.SubnetIds[1], program.vpcSubnets.split(',')[1])
|
264 | assert.equal(params.VpcConfig.SubnetIds[2], program.vpcSubnets.split(',')[2])
|
265 | assert.equal(params.VpcConfig.SecurityGroupIds[0], program.vpcSecurityGroups.split(',')[0])
|
266 | assert.equal(params.VpcConfig.SecurityGroupIds[1], program.vpcSecurityGroups.split(',')[1])
|
267 | assert.equal(params.VpcConfig.SecurityGroupIds[2], program.vpcSecurityGroups.split(',')[2])
|
268 | })
|
269 |
|
270 | it('does not append VpcConfig when params are not set', () => {
|
271 | const params = lambda._params(program)
|
272 | assert.equal(Object.keys(params.VpcConfig.SubnetIds).length, 0)
|
273 | assert.equal(Object.keys(params.VpcConfig.SecurityGroupIds).length, 0)
|
274 | })
|
275 |
|
276 | it('appends KMSKeyArn to params when KMS params set', () => {
|
277 | ['', 'arn:aws:kms:test'].forEach((v) => {
|
278 | program.kmsKeyArn = v
|
279 | const params = lambda._params(program)
|
280 | assert.equal(params.KMSKeyArn, v, v)
|
281 | })
|
282 | })
|
283 |
|
284 | it('does not append KMSKeyArn when params are not set', () => {
|
285 | const params = lambda._params(program)
|
286 | assert.isUndefined(params.KMSKeyArn)
|
287 | })
|
288 |
|
289 | it('appends DeadLetterConfig to params when DLQ params set', () => {
|
290 | ['', 'arn:aws:sqs:test'].forEach((v) => {
|
291 | program.deadLetterConfigTargetArn = v
|
292 | const params = lambda._params(program)
|
293 | assert.equal(params.DeadLetterConfig.TargetArn, v, v)
|
294 | })
|
295 | })
|
296 |
|
297 | it('does not append DeadLetterConfig when params are not set', () => {
|
298 | delete program.deadLetterConfigTargetArn
|
299 | const params = lambda._params(program)
|
300 | assert.isNull(params.DeadLetterConfig.TargetArn)
|
301 | })
|
302 |
|
303 | it('appends TracingConfig to params when params set', () => {
|
304 | program.tracingConfig = 'Active'
|
305 | const params = lambda._params(program)
|
306 | assert.equal(params.TracingConfig.Mode, 'Active')
|
307 | })
|
308 |
|
309 | it('does not append TracingConfig when params are not set', () => {
|
310 | program.tracingConfig = ''
|
311 | const params = lambda._params(program)
|
312 | assert.isNull(params.TracingConfig.Mode)
|
313 | })
|
314 |
|
315 | it('appends Layers to params when params set', () => {
|
316 | program.layers = 'Layer1,Layer2'
|
317 | const params = lambda._params(program)
|
318 | assert.deepEqual(params.Layers, ['Layer1', 'Layer2'])
|
319 | })
|
320 |
|
321 | it('does not append Layers when params are not set', () => {
|
322 | program.layers = ''
|
323 | const params = lambda._params(program)
|
324 | assert.deepEqual(params.Layers, [])
|
325 | })
|
326 |
|
327 | describe('S3 deploy', () => {
|
328 | it('Do not use S3 deploy', () => {
|
329 | const params = lambda._params(program, 'Buffer')
|
330 | assert.deepEqual(
|
331 | params.Code,
|
332 | { ZipFile: 'Buffer' }
|
333 | )
|
334 | })
|
335 |
|
336 | it('Use S3 deploy', () => {
|
337 | const params = lambda._params(Object.assign({ deployUseS3: true }, program), 'Buffer')
|
338 | assert.deepEqual(
|
339 | params.Code,
|
340 | {
|
341 | S3Bucket: null,
|
342 | S3Key: null
|
343 | }
|
344 | )
|
345 | })
|
346 | })
|
347 |
|
348 | describe('PackageType: Zip|Image', () => {
|
349 | it('PackageType: Zip', () => {
|
350 | const params = lambda._params(program, 'Buffer')
|
351 | assert.equal(params.PackageType, 'Zip')
|
352 | assert.deepEqual(
|
353 | params.Code,
|
354 | { ZipFile: 'Buffer' }
|
355 | )
|
356 | })
|
357 |
|
358 | it('PackageType: Image', () => {
|
359 | program.imageUri = 'xxx'
|
360 | const params = lambda._params(program, 'Buffer')
|
361 | assert.equal(params.PackageType, 'Image')
|
362 |
|
363 | assert.isUndefined(params.Handler)
|
364 | assert.isUndefined(params.Runtime)
|
365 | assert.isUndefined(params.KMSKeyArn)
|
366 |
|
367 | assert.deepEqual(
|
368 | params.Code,
|
369 | { ImageUri: 'xxx' }
|
370 | )
|
371 | })
|
372 | })
|
373 |
|
374 | describe('params.Publish', () => {
|
375 | describe('boolean', () => {
|
376 | it('If true, it is set to true', () => {
|
377 | program.publish = true
|
378 | const params = lambda._params(program)
|
379 | assert.isTrue(params.Publish)
|
380 | })
|
381 | it('If false, it is set to false', () => {
|
382 | program.publish = false
|
383 | const params = lambda._params(program)
|
384 | assert.isFalse(params.Publish)
|
385 | })
|
386 | })
|
387 |
|
388 | describe('string', () => {
|
389 | it('If "true", it is set to true', () => {
|
390 | program.publish = 'true'
|
391 | const params = lambda._params(program)
|
392 | assert.isTrue(params.Publish)
|
393 | })
|
394 | it('If not "true", it is set to false', () => {
|
395 | program.publish = 'false'
|
396 | assert.isFalse(lambda._params(program).Publish)
|
397 | program.publish = 'aaa'
|
398 | assert.isFalse(lambda._params(program).Publish)
|
399 | })
|
400 | })
|
401 | })
|
402 |
|
403 | describe('configFile', () => {
|
404 | beforeEach(() => {
|
405 |
|
406 | fs.writeFileSync('tmp.env', 'FOO=bar\nBAZ=bing\n')
|
407 | fs.writeFileSync('empty.env', '')
|
408 | })
|
409 |
|
410 | afterEach(() => {
|
411 | fs.unlinkSync('tmp.env')
|
412 | fs.unlinkSync('empty.env')
|
413 | })
|
414 |
|
415 | it('adds variables when configFile param is set', () => {
|
416 | program.configFile = 'tmp.env'
|
417 | const params = lambda._params(program)
|
418 | assert.equal(params.Environment.Variables.FOO, 'bar')
|
419 | assert.equal(params.Environment.Variables.BAZ, 'bing')
|
420 | })
|
421 |
|
422 | it('when configFile param is set but it is an empty file', () => {
|
423 | program.configFile = 'empty.env'
|
424 | const params = lambda._params(program)
|
425 | assert.equal(Object.keys(params.Environment.Variables).length, 0)
|
426 | })
|
427 |
|
428 | it('does not add when configFile param is not set', () => {
|
429 | const params = lambda._params(program)
|
430 | assert.isNull(params.Environment.Variables)
|
431 | })
|
432 | })
|
433 | })
|
434 |
|
435 | describe('_cleanDirectory', () => {
|
436 | it('`codeDirectory` is empty', () => {
|
437 | return lambda._cleanDirectory(codeDirectory).then(() => {
|
438 | assert.isTrue(fs.existsSync(codeDirectory))
|
439 | const contents = fs.readdirSync(codeDirectory)
|
440 | assert.equal(contents.length, 0)
|
441 | })
|
442 | })
|
443 |
|
444 | it('`codeDirectory` is empty. (For `codeDirectory` where the file was present)', () => {
|
445 | return lambda._fileCopy(program, '.', codeDirectory, true).then(() => {
|
446 | const contents = fs.readdirSync(codeDirectory)
|
447 | assert.isTrue(contents.length > 0)
|
448 | return lambda._cleanDirectory(codeDirectory).then(() => {
|
449 | assert.isTrue(fs.existsSync(codeDirectory))
|
450 | const contents = fs.readdirSync(codeDirectory)
|
451 | assert.equal(contents.length, 0)
|
452 | })
|
453 | })
|
454 | })
|
455 | })
|
456 |
|
457 | describe('_fileCopy', () => {
|
458 | before(() => {
|
459 | fs.mkdirSync('build')
|
460 | fs.mkdirsSync(path.join('__unittest', 'hoge'))
|
461 | fs.mkdirsSync(path.join('__unittest', 'fuga'))
|
462 | fs.writeFileSync(path.join('__unittest', 'hoge', 'piyo'), '')
|
463 | fs.writeFileSync(path.join('__unittest', 'hoge', 'package.json'), '')
|
464 | fs.writeFileSync('fuga', '')
|
465 | })
|
466 | after(() => {
|
467 | ['build', 'fuga', '__unittest'].forEach((path) => {
|
468 | fs.removeSync(path)
|
469 | })
|
470 | })
|
471 |
|
472 | beforeEach(() => lambda._cleanDirectory(codeDirectory))
|
473 |
|
474 | it('_fileCopy an index.js as well as other files', () => {
|
475 | return lambda._fileCopy(program, '.', codeDirectory, true).then(() => {
|
476 | const contents = fs.readdirSync(codeDirectory);
|
477 | ['index.js', 'package.json'].forEach((needle) => {
|
478 | assert.include(contents, needle, `Target: "${needle}"`)
|
479 | });
|
480 | ['node_modules', 'build'].forEach((needle) => {
|
481 | assert.notInclude(contents, needle, `Target: "${needle}"`)
|
482 | })
|
483 | })
|
484 | })
|
485 |
|
486 | describe('when there are excluded files', () => {
|
487 | beforeEach((done) => {
|
488 |
|
489 |
|
490 | program.excludeGlobs = [
|
491 | '*.png',
|
492 | 'test',
|
493 | '*main*',
|
494 | path.join('__unittest', 'hoge', '*'),
|
495 | path.join('fuga', path.sep)
|
496 | ].join(' ')
|
497 | done()
|
498 | })
|
499 |
|
500 | it('_fileCopy an index.js as well as other files', () => {
|
501 | return lambda._fileCopy(program, '.', codeDirectory, true).then(() => {
|
502 | const contents = fs.readdirSync(codeDirectory);
|
503 | ['index.js', 'package.json'].forEach((needle) => {
|
504 | assert.include(contents, needle, `Target: "${needle}"`)
|
505 | })
|
506 | })
|
507 | })
|
508 |
|
509 | it('_fileCopy excludes files matching excludeGlobs', () => {
|
510 | return lambda._fileCopy(program, '.', codeDirectory, true).then(() => {
|
511 | let contents = fs.readdirSync(codeDirectory);
|
512 | ['__unittest', 'fuga'].forEach((needle) => {
|
513 | assert.include(contents, needle, `Target: "${needle}"`)
|
514 | });
|
515 |
|
516 | ['node-lambda.png', 'test'].forEach((needle) => {
|
517 | assert.notInclude(contents, needle, `Target: "${needle}"`)
|
518 | })
|
519 |
|
520 | contents = fs.readdirSync(path.join(codeDirectory, 'lib'))
|
521 | assert.notInclude(contents, 'main.js', 'Target: "lib/main.js"')
|
522 |
|
523 | contents = fs.readdirSync(path.join(codeDirectory, '__unittest'))
|
524 | assert.include(contents, 'hoge', 'Target: "__unittest/hoge"')
|
525 | assert.notInclude(contents, 'fuga', 'Target: "__unittest/fuga"')
|
526 |
|
527 | contents = fs.readdirSync(path.join(codeDirectory, '__unittest', 'hoge'))
|
528 | assert.equal(contents.length, 0, 'directory:__unittest/hoge is empty')
|
529 | })
|
530 | })
|
531 |
|
532 | it('_fileCopy should not exclude package.json, even when excluded by excludeGlobs', () => {
|
533 | program.excludeGlobs = '*.json'
|
534 | return lambda._fileCopy(program, '.', codeDirectory, true).then(() => {
|
535 | const contents = fs.readdirSync(codeDirectory)
|
536 | assert.include(contents, 'package.json')
|
537 | })
|
538 | })
|
539 | it('_fileCopy should not exclude package-lock.json, even when excluded by excludeGlobs', () => {
|
540 | program.excludeGlobs = '*.json'
|
541 | return lambda._fileCopy(program, '.', codeDirectory, true).then(() => {
|
542 | const contents = fs.readdirSync(codeDirectory)
|
543 | assert.include(contents, 'package-lock.json')
|
544 | })
|
545 | })
|
546 |
|
547 | it('_fileCopy should not include package.json when --prebuiltDirectory is set', () => {
|
548 | const buildDir = '.build_' + Date.now()
|
549 | after(() => fs.removeSync(buildDir))
|
550 |
|
551 | fs.mkdirSync(buildDir)
|
552 | fs.writeFileSync(path.join(buildDir, 'testa'), '')
|
553 | fs.writeFileSync(path.join(buildDir, 'package.json'), '')
|
554 |
|
555 | program.excludeGlobs = '*.json'
|
556 | program.prebuiltDirectory = buildDir
|
557 | return lambda._fileCopy(program, buildDir, codeDirectory, true).then(() => {
|
558 | const contents = fs.readdirSync(codeDirectory)
|
559 | assert.notInclude(contents, 'package.json', 'Target: "packages.json"')
|
560 | assert.include(contents, 'testa', 'Target: "testa"')
|
561 | })
|
562 | })
|
563 | })
|
564 | })
|
565 |
|
566 | describe('_shouldUseNpmCi', () => {
|
567 | beforeEach(() => {
|
568 | return lambda._cleanDirectory(codeDirectory)
|
569 | })
|
570 |
|
571 | describe('when package-lock.json exists', () => {
|
572 | beforeEach(() => {
|
573 | fs.writeFileSync(path.join(codeDirectory, 'package-lock.json'), JSON.stringify({}))
|
574 | })
|
575 |
|
576 | it('returns true', () => {
|
577 | assert.isTrue(lambda._shouldUseNpmCi(codeDirectory))
|
578 | })
|
579 | })
|
580 |
|
581 | describe('when package-lock.json does not exist', () => {
|
582 | beforeEach(() => {
|
583 | fs.removeSync(path.join(codeDirectory, 'package-lock.json'))
|
584 | })
|
585 |
|
586 | it('returns false', () => {
|
587 | assert.isFalse(lambda._shouldUseNpmCi(codeDirectory))
|
588 | })
|
589 | })
|
590 | })
|
591 |
|
592 | describe('_npmInstall', function () {
|
593 | _timeout({ this: this, sec: 30 })
|
594 |
|
595 |
|
596 |
|
597 | const nodeModulesMocha = path.join(codeDirectory, 'node_modules', 'mocha')
|
598 |
|
599 | beforeEach(() => {
|
600 | return lambda._cleanDirectory(codeDirectory).then(() => {
|
601 | fs.copySync(
|
602 | path.join('node_modules', 'aws-sdk'),
|
603 | path.join(codeDirectory, 'node_modules', 'aws-sdk')
|
604 | )
|
605 | return lambda._fileCopy(program, '.', codeDirectory, true)
|
606 | })
|
607 | })
|
608 |
|
609 | describe('when package-lock.json does exist', () => {
|
610 | it('should use "npm ci"', () => {
|
611 | const beforeAwsSdkStat = fs.statSync(path.join(codeDirectory, 'node_modules', 'aws-sdk'))
|
612 | return lambda._npmInstall(program, codeDirectory).then(() => {
|
613 | const contents = fs.readdirSync(path.join(codeDirectory, 'node_modules'))
|
614 | assert.include(contents, 'dotenv')
|
615 |
|
616 |
|
617 |
|
618 | const afterAwsSdkStat = fs.statSync(path.join(codeDirectory, 'node_modules', 'aws-sdk'))
|
619 | assert.isBelow(beforeAwsSdkStat.ctimeMs, afterAwsSdkStat.ctimeMs)
|
620 |
|
621 |
|
622 | assert.isFalse(fs.existsSync(nodeModulesMocha))
|
623 | })
|
624 | })
|
625 | })
|
626 |
|
627 | describe('when package-lock.json does not exist', () => {
|
628 | beforeEach(() => {
|
629 | return fs.removeSync(path.join(codeDirectory, 'package-lock.json'))
|
630 | })
|
631 |
|
632 | it('should use "npm install"', () => {
|
633 | const beforeAwsSdkStat = fs.statSync(path.join(codeDirectory, 'node_modules', 'aws-sdk'))
|
634 | return lambda._npmInstall(program, codeDirectory).then(() => {
|
635 | const contents = fs.readdirSync(path.join(codeDirectory, 'node_modules'))
|
636 | assert.include(contents, 'dotenv')
|
637 |
|
638 |
|
639 |
|
640 | const afterAwsSdkStat = fs.statSync(path.join(codeDirectory, 'node_modules', 'aws-sdk'))
|
641 | assert.equal(beforeAwsSdkStat.ctimeMs, afterAwsSdkStat.ctimeMs)
|
642 |
|
643 |
|
644 | assert.isFalse(fs.existsSync(nodeModulesMocha))
|
645 | })
|
646 | })
|
647 | })
|
648 | })
|
649 |
|
650 | describe('_npmInstall (When codeDirectory contains characters to be escaped)', () => {
|
651 | beforeEach(() => {
|
652 |
|
653 | const directoryName = process.platform === 'win32'
|
654 | ? 'hoge fuga\' piyo'
|
655 | : 'hoge "fuga\' \\piyo'
|
656 | codeDirectory = path.join(os.tmpdir(), directoryName)
|
657 | return lambda._cleanDirectory(codeDirectory).then(() => {
|
658 | return lambda._fileCopy(program, '.', codeDirectory, true)
|
659 | })
|
660 | })
|
661 |
|
662 | afterEach(() => {
|
663 | fs.removeSync(codeDirectory)
|
664 | codeDirectory = lambda._codeDirectory()
|
665 | })
|
666 |
|
667 | it('_npm adds node_modules', function () {
|
668 | _timeout({ this: this, sec: 30 })
|
669 |
|
670 | return lambda._npmInstall(program, codeDirectory).then(() => {
|
671 | const contents = fs.readdirSync(codeDirectory)
|
672 | assert.include(contents, 'node_modules')
|
673 | })
|
674 | })
|
675 | })
|
676 |
|
677 | describe('_postInstallScript', () => {
|
678 | if (process.platform === 'win32') {
|
679 | return it('`_postInstallScript` test does not support Windows.')
|
680 | }
|
681 |
|
682 | const postInstallScriptPath = path.join(codeDirectory, 'post_install.sh')
|
683 | let hook
|
684 | |
685 |
|
686 |
|
687 | const captureStream = function (stream) {
|
688 | const oldWrite = stream.write
|
689 | let buf = ''
|
690 | stream.write = function (chunk, encoding, callback) {
|
691 | buf += chunk.toString()
|
692 | oldWrite.apply(stream, arguments)
|
693 | }
|
694 |
|
695 | return {
|
696 | unhook: () => {
|
697 | stream.write = oldWrite
|
698 | },
|
699 | captured: () => buf
|
700 | }
|
701 | }
|
702 | beforeEach(() => {
|
703 | hook = captureStream(process.stdout)
|
704 | })
|
705 | afterEach(() => {
|
706 | hook.unhook()
|
707 | if (fs.existsSync(postInstallScriptPath)) {
|
708 | fs.unlinkSync(postInstallScriptPath)
|
709 | }
|
710 | })
|
711 |
|
712 | it('should not throw any errors if no script', () => {
|
713 | return lambda._postInstallScript(program, codeDirectory).then((dummy) => {
|
714 | assert.isUndefined(dummy)
|
715 | })
|
716 | })
|
717 |
|
718 | it('should throw any errors if script fails', () => {
|
719 | fs.writeFileSync(postInstallScriptPath, '___fails___')
|
720 | return lambda._postInstallScript(program, codeDirectory).catch((err) => {
|
721 | assert.instanceOf(err, Error)
|
722 | assert.match(err.message, /^Error: Command failed:/)
|
723 | })
|
724 | })
|
725 |
|
726 | it('running script gives expected output', () => {
|
727 | fs.writeFileSync(
|
728 | postInstallScriptPath,
|
729 | fs.readFileSync(path.join('test', 'post_install.sh'))
|
730 | )
|
731 | fs.chmodSync(path.join(codeDirectory, 'post_install.sh'), '755')
|
732 | return lambda._postInstallScript(program, codeDirectory).then((dummy) => {
|
733 | assert.isUndefined(dummy)
|
734 | }).catch((err) => {
|
735 | assert.isNull(err)
|
736 | assert.equal(
|
737 | `=> Running post install script post_install.sh\n\t\tYour environment is ${program.environment}\n`,
|
738 | hook.captured()
|
739 | )
|
740 | })
|
741 | })
|
742 | })
|
743 |
|
744 | describe('_zip', () => {
|
745 | beforeEach(function () {
|
746 | _timeout({ this: this, sec: 30 })
|
747 | return Promise.resolve().then(() => {
|
748 | return lambda._cleanDirectory(codeDirectory)
|
749 | }).then(() => {
|
750 | return lambda._fileCopy(program, '.', codeDirectory, true)
|
751 | }).then(() => {
|
752 | return lambda._npmInstall(program, codeDirectory)
|
753 | }).then(() => {
|
754 | if (process.platform !== 'win32') {
|
755 | fs.symlinkSync(
|
756 | path.join(__dirname, '..', 'bin', 'node-lambda'),
|
757 | path.join(codeDirectory, 'node-lambda-link')
|
758 | )
|
759 | }
|
760 | })
|
761 | })
|
762 |
|
763 | it('Compress the file. `index.js` and `bin/node-lambda` are included and the permission is also preserved.', function () {
|
764 | _timeout({ this: this, sec: 30 })
|
765 |
|
766 | return lambda._zip(program, codeDirectory).then((data) => {
|
767 | const archive = new Zip(data)
|
768 | assert.include(archive.files['index.js'].name, 'index.js')
|
769 | assert.include(archive.files['bin/node-lambda'].name, 'bin/node-lambda')
|
770 |
|
771 | if (process.platform !== 'win32') {
|
772 | const indexJsStat = fs.lstatSync('index.js')
|
773 | const binNodeLambdaStat = fs.lstatSync(path.join('bin', 'node-lambda'))
|
774 | assert.equal(
|
775 | archive.files['index.js'].unixPermissions,
|
776 | indexJsStat.mode
|
777 | )
|
778 | assert.equal(
|
779 | archive.files['bin/node-lambda'].unixPermissions,
|
780 | binNodeLambdaStat.mode
|
781 | )
|
782 |
|
783 |
|
784 | assert.include(archive.files['node-lambda-link'].name, 'node-lambda-link')
|
785 | assert.equal(
|
786 | archive.files['node-lambda-link'].unixPermissions & fs.constants.S_IFMT,
|
787 | fs.constants.S_IFLNK
|
788 | )
|
789 | }
|
790 | })
|
791 | })
|
792 | })
|
793 |
|
794 | describe('_archive', () => {
|
795 |
|
796 | it('installs and zips with an index.js file and node_modules/aws-sdk (It is also a test of `_buildAndArchive`)', function () {
|
797 | _timeout({ this: this, sec: 30 })
|
798 |
|
799 | return lambda._archive(program).then((data) => {
|
800 | const archive = new Zip(data)
|
801 | const contents = Object.keys(archive.files).map((k) => {
|
802 | return archive.files[k].name.toString()
|
803 | })
|
804 | assert.include(contents, 'index.js')
|
805 | assert.include(contents, 'node_modules/aws-sdk/lib/aws.js')
|
806 | })
|
807 | })
|
808 |
|
809 | it('packages a prebuilt module without installing (It is also a test of `_archivePrebuilt`)', function () {
|
810 | _timeout({ this: this, sec: 30 })
|
811 | const buildDir = '.build_' + Date.now()
|
812 | after(() => fs.removeSync(buildDir))
|
813 |
|
814 | fs.mkdirSync(buildDir)
|
815 | fs.mkdirSync(path.join(buildDir, 'd'))
|
816 | fs.mkdirSync(path.join(buildDir, 'node_modules'))
|
817 | fs.writeFileSync(path.join(buildDir, 'node_modules', 'a'), '...')
|
818 | fs.writeFileSync(path.join(buildDir, 'testa'), '...')
|
819 | fs.writeFileSync(path.join(buildDir, 'd', 'testb'), '...')
|
820 |
|
821 | program.prebuiltDirectory = buildDir
|
822 | return lambda._archive(program).then((data) => {
|
823 | const archive = new Zip(data)
|
824 | const contents = Object.keys(archive.files).map((k) => {
|
825 | return archive.files[k].name.toString()
|
826 | });
|
827 | [
|
828 | 'testa',
|
829 | 'd/testb',
|
830 | 'node_modules/a'
|
831 | ].forEach((needle) => {
|
832 | assert.include(contents, needle, `Target: "${needle}"`)
|
833 | })
|
834 | })
|
835 | })
|
836 | })
|
837 |
|
838 | describe('_readArchive', () => {
|
839 | const testZipFile = path.join(os.tmpdir(), 'node-lambda-test.zip')
|
840 | let bufferExpected = null
|
841 | before(function () {
|
842 | _timeout({ this: this, sec: 30 })
|
843 |
|
844 | return lambda._zip(program, codeDirectory).then((data) => {
|
845 | bufferExpected = data
|
846 | fs.writeFileSync(testZipFile, data)
|
847 | })
|
848 | })
|
849 |
|
850 | after(() => fs.unlinkSync(testZipFile))
|
851 |
|
852 | it('_readArchive fails (undefined)', () => {
|
853 | return lambda._readArchive(program).then((data) => {
|
854 | assert.isUndefined(data)
|
855 | }).catch((err) => {
|
856 | assert.instanceOf(err, Error)
|
857 | assert.equal(err.message, 'No such Zipfile [undefined]')
|
858 | })
|
859 | })
|
860 |
|
861 | it('_readArchive fails (does not exists file)', () => {
|
862 | const filePath = path.join(path.resolve('/aaaa'), 'bbbb')
|
863 | const _program = Object.assign({ deployZipfile: filePath }, program)
|
864 | return lambda._readArchive(_program).then((data) => {
|
865 | assert.isUndefined(data)
|
866 | }).catch((err) => {
|
867 | assert.instanceOf(err, Error)
|
868 | assert.equal(err.message, `No such Zipfile [${filePath}]`)
|
869 | })
|
870 | })
|
871 |
|
872 | it('_readArchive reads the contents of the zipfile', () => {
|
873 | const _program = Object.assign({ deployZipfile: testZipFile }, program)
|
874 | return lambda._readArchive(_program).then((data) => {
|
875 | assert.deepEqual(data, bufferExpected)
|
876 | })
|
877 | })
|
878 |
|
879 | describe('If value is set in `deployZipfile`, _readArchive is executed in _archive', () => {
|
880 | it('`deployZipfile` is a invalid value. Process from creation of zip file', function () {
|
881 | const filePath = path.join(path.resolve('/aaaa'), 'bbbb')
|
882 | const _program = Object.assign({ deployZipfile: filePath }, program)
|
883 | _timeout({ this: this, sec: 30 })
|
884 | return lambda._archive(_program).then((data) => {
|
885 |
|
886 | const archive = new Zip(data)
|
887 | const contents = Object.keys(archive.files).map((k) => {
|
888 | return archive.files[k].name.toString()
|
889 | })
|
890 | assert.include(contents, 'index.js')
|
891 | assert.include(contents, 'node_modules/aws-sdk/lib/aws.js')
|
892 | })
|
893 | })
|
894 |
|
895 | it('`deployZipfile` is a valid value._archive reads the contents of the zipfile', () => {
|
896 | const _program = Object.assign({ deployZipfile: testZipFile }, program)
|
897 | return lambda._archive(_program).then((data) => {
|
898 | assert.deepEqual(data, bufferExpected)
|
899 | })
|
900 | })
|
901 | })
|
902 | })
|
903 |
|
904 | describe('environment variable injection at runtime', () => {
|
905 | beforeEach(() => {
|
906 |
|
907 | fs.writeFileSync('tmp.env', 'FOO=bar\nBAZ=bing\n')
|
908 | })
|
909 |
|
910 | afterEach(() => fs.unlinkSync('tmp.env'))
|
911 |
|
912 | it('should inject environment variables at runtime', () => {
|
913 |
|
914 | lambda._setRunTimeEnvironmentVars({
|
915 | configFile: 'tmp.env'
|
916 | }, process.cwd())
|
917 |
|
918 | assert.equal(process.env.FOO, 'bar')
|
919 | assert.equal(process.env.BAZ, 'bing')
|
920 | })
|
921 | })
|
922 |
|
923 | describe('create sample files', () => {
|
924 | const targetFiles = [
|
925 | '.env',
|
926 | 'context.json',
|
927 | 'event.json',
|
928 | 'deploy.env',
|
929 | 'event_sources.json'
|
930 | ]
|
931 |
|
932 | after(() => {
|
933 | targetFiles.forEach((file) => fs.unlinkSync(file))
|
934 | program.eventSourceFile = ''
|
935 | })
|
936 |
|
937 | it('should create sample files', () => {
|
938 | lambda.setup(program)
|
939 |
|
940 | const libPath = path.join(__dirname, '..', 'lib')
|
941 | targetFiles.forEach((targetFile) => {
|
942 | const boilerplateFile = path.join(libPath, `${targetFile}.example`)
|
943 |
|
944 | assert.equal(
|
945 | fs.readFileSync(targetFile).toString(),
|
946 | fs.readFileSync(boilerplateFile).toString(),
|
947 | targetFile
|
948 | )
|
949 | })
|
950 | })
|
951 |
|
952 | describe('_eventSourceList', () => {
|
953 | it('program.eventSourceFile is empty value', () => {
|
954 | program.eventSourceFile = ''
|
955 | assert.deepEqual(
|
956 | lambda._eventSourceList(program),
|
957 | {
|
958 | EventSourceMappings: null,
|
959 | ScheduleEvents: null,
|
960 | S3Events: null
|
961 | }
|
962 | )
|
963 | })
|
964 |
|
965 | it('program.eventSourceFile is invalid value', () => {
|
966 | const dirPath = path.join(path.resolve('/hoge'), 'fuga')
|
967 | program.eventSourceFile = dirPath
|
968 | assert.throws(
|
969 | () => { lambda._eventSourceList(program) },
|
970 | Error,
|
971 | `ENOENT: no such file or directory, open '${dirPath}'`
|
972 | )
|
973 | })
|
974 |
|
975 | describe('program.eventSourceFile is valid value', () => {
|
976 | before(() => {
|
977 | fs.writeFileSync('only_EventSourceMappings.json', JSON.stringify({
|
978 | EventSourceMappings: [{ test: 1 }]
|
979 | }))
|
980 | fs.writeFileSync('only_ScheduleEvents.json', JSON.stringify({
|
981 | ScheduleEvents: [{ test: 2 }]
|
982 | }))
|
983 | fs.writeFileSync('only_S3Events.json', JSON.stringify({
|
984 | S3Events: [{ test: 3 }]
|
985 | }))
|
986 | })
|
987 |
|
988 | after(() => {
|
989 | fs.unlinkSync('only_EventSourceMappings.json')
|
990 | fs.unlinkSync('only_ScheduleEvents.json')
|
991 | fs.unlinkSync('only_S3Events.json')
|
992 | })
|
993 |
|
994 | it('only EventSourceMappings', () => {
|
995 | program.eventSourceFile = 'only_EventSourceMappings.json'
|
996 | const expected = {
|
997 | EventSourceMappings: [{ test: 1 }],
|
998 | ScheduleEvents: [],
|
999 | S3Events: []
|
1000 | }
|
1001 | assert.deepEqual(lambda._eventSourceList(program), expected)
|
1002 | })
|
1003 |
|
1004 | it('only ScheduleEvents', () => {
|
1005 | program.eventSourceFile = 'only_ScheduleEvents.json'
|
1006 | const expected = {
|
1007 | EventSourceMappings: [],
|
1008 | ScheduleEvents: [{ test: 2 }],
|
1009 | S3Events: []
|
1010 | }
|
1011 | assert.deepEqual(lambda._eventSourceList(program), expected)
|
1012 | })
|
1013 |
|
1014 | it('only S3Events', () => {
|
1015 | program.eventSourceFile = 'only_S3Events.json'
|
1016 | const expected = {
|
1017 | EventSourceMappings: [],
|
1018 | ScheduleEvents: [],
|
1019 | S3Events: [{ test: 3 }]
|
1020 | }
|
1021 | assert.deepEqual(lambda._eventSourceList(program), expected)
|
1022 | })
|
1023 |
|
1024 | it('EventSourceMappings & ScheduleEvents', () => {
|
1025 | program.eventSourceFile = 'event_sources.json'
|
1026 | const expected = {
|
1027 | EventSourceMappings: [{
|
1028 | BatchSize: 100,
|
1029 | Enabled: true,
|
1030 | EventSourceArn: 'your event source arn',
|
1031 | StartingPosition: 'LATEST'
|
1032 | }],
|
1033 | ScheduleEvents: [{
|
1034 | ScheduleName: 'node-lambda-test-schedule',
|
1035 | ScheduleState: 'ENABLED',
|
1036 | ScheduleExpression: 'rate(1 hour)',
|
1037 | Input: {
|
1038 | key1: 'value',
|
1039 | key2: 'value'
|
1040 | }
|
1041 | }],
|
1042 | S3Events: [{
|
1043 | Bucket: 'BUCKET_NAME',
|
1044 | Events: [
|
1045 | 's3:ObjectCreated:*'
|
1046 | ],
|
1047 | Filter: {
|
1048 | Key: {
|
1049 | FilterRules: [{
|
1050 | Name: 'prefix',
|
1051 | Value: 'STRING_VALUE'
|
1052 | }]
|
1053 | }
|
1054 | }
|
1055 | }]
|
1056 | }
|
1057 | assert.deepEqual(lambda._eventSourceList(program), expected)
|
1058 | })
|
1059 | })
|
1060 |
|
1061 | describe('old style event_sources.json', () => {
|
1062 | const oldStyleValue = [{
|
1063 | BatchSize: 100,
|
1064 | Enabled: true,
|
1065 | EventSourceArn: 'your event source arn',
|
1066 | StartingPosition: 'LATEST'
|
1067 | }]
|
1068 | const fileName = 'event_sources_old_style.json'
|
1069 |
|
1070 | before(() => fs.writeFileSync(fileName, JSON.stringify(oldStyleValue)))
|
1071 | after(() => fs.unlinkSync(fileName))
|
1072 |
|
1073 | it('program.eventSourceFile is valid value', () => {
|
1074 | program.eventSourceFile = fileName
|
1075 | const expected = {
|
1076 | EventSourceMappings: oldStyleValue,
|
1077 | ScheduleEvents: [],
|
1078 | S3Events: []
|
1079 | }
|
1080 | assert.deepEqual(lambda._eventSourceList(program), expected)
|
1081 | })
|
1082 | })
|
1083 | })
|
1084 | })
|
1085 |
|
1086 | describe('_listEventSourceMappings', () => {
|
1087 | it('simple test with mock', () => {
|
1088 | return lambda._listEventSourceMappings(
|
1089 | awsLambda,
|
1090 | { FunctionName: 'test-func' }
|
1091 | ).then((results) => {
|
1092 | assert.deepEqual(
|
1093 | results,
|
1094 | lambdaMockSettings.listEventSourceMappings.EventSourceMappings
|
1095 | )
|
1096 | })
|
1097 | })
|
1098 | })
|
1099 |
|
1100 | describe('_getStartingPosition', () => {
|
1101 | it('null in SQS', () => {
|
1102 | assert.isNull(lambda._getStartingPosition({
|
1103 | EventSourceArn: 'arn:aws:sqs:us-east-1:sqs-queuename1'
|
1104 | }))
|
1105 | })
|
1106 |
|
1107 | it('When there is no setting', () => {
|
1108 | assert.equal(
|
1109 | lambda._getStartingPosition({
|
1110 | EventSourceArn: 'arn:aws:kinesis:test'
|
1111 | }),
|
1112 | 'LATEST'
|
1113 | )
|
1114 | })
|
1115 |
|
1116 | it('With StartingPosition', () => {
|
1117 | assert.equal(
|
1118 | lambda._getStartingPosition({
|
1119 | EventSourceArn: 'arn:aws:kinesis:test',
|
1120 | StartingPosition: 'test position'
|
1121 | }),
|
1122 | 'test position'
|
1123 | )
|
1124 | })
|
1125 | })
|
1126 |
|
1127 | describe('_updateEventSources', () => {
|
1128 | const eventSourcesJsonValue = {
|
1129 | EventSourceMappings: [{
|
1130 | EventSourceArn: lambdaMockSettings
|
1131 | .listEventSourceMappings
|
1132 | .EventSourceMappings[0]
|
1133 | .EventSourceArn,
|
1134 | StartingPosition: 'LATEST',
|
1135 | BatchSize: 100,
|
1136 | Enabled: true
|
1137 | }]
|
1138 | }
|
1139 |
|
1140 | before(() => {
|
1141 | fs.writeFileSync(
|
1142 | 'event_sources.json',
|
1143 | JSON.stringify(eventSourcesJsonValue)
|
1144 | )
|
1145 | })
|
1146 |
|
1147 | after(() => fs.unlinkSync('event_sources.json'))
|
1148 |
|
1149 | it('program.eventSourceFile is empty value', () => {
|
1150 | program.eventSourceFile = ''
|
1151 | const eventSourceList = lambda._eventSourceList(program)
|
1152 | return lambda._updateEventSources(
|
1153 | awsLambda,
|
1154 | '',
|
1155 | [],
|
1156 | eventSourceList.EventSourceMappings
|
1157 | ).then((results) => {
|
1158 | assert.deepEqual(results, [])
|
1159 | })
|
1160 | })
|
1161 |
|
1162 | it('simple test with mock (In case of new addition)', () => {
|
1163 | program.eventSourceFile = 'event_sources.json'
|
1164 | const eventSourceList = lambda._eventSourceList(program)
|
1165 | return lambda._updateEventSources(
|
1166 | awsLambda,
|
1167 | 'functionName',
|
1168 | [],
|
1169 | eventSourceList.EventSourceMappings
|
1170 | ).then((results) => {
|
1171 | assert.deepEqual(results, [lambdaMockSettings.createEventSourceMapping])
|
1172 | })
|
1173 | })
|
1174 |
|
1175 | it('simple test with mock (In case of deletion)', () => {
|
1176 | return lambda._updateEventSources(
|
1177 | awsLambda,
|
1178 | 'functionName',
|
1179 | lambdaMockSettings.listEventSourceMappings.EventSourceMappings,
|
1180 | {}
|
1181 | ).then((results) => {
|
1182 | assert.deepEqual(results, [lambdaMockSettings.deleteEventSourceMapping])
|
1183 | })
|
1184 | })
|
1185 |
|
1186 | it('simple test with mock (In case of update)', () => {
|
1187 | program.eventSourceFile = 'event_sources.json'
|
1188 | const eventSourceList = lambda._eventSourceList(program)
|
1189 | return lambda._updateEventSources(
|
1190 | awsLambda,
|
1191 | 'functionName',
|
1192 | lambdaMockSettings.listEventSourceMappings.EventSourceMappings,
|
1193 | eventSourceList.EventSourceMappings
|
1194 | ).then((results) => {
|
1195 | assert.deepEqual(results, [lambdaMockSettings.updateEventSourceMapping])
|
1196 | })
|
1197 | })
|
1198 | })
|
1199 |
|
1200 | describe('_updateScheduleEvents', () => {
|
1201 | const ScheduleEvents = require(path.join('..', 'lib', 'schedule_events'))
|
1202 | const eventSourcesJsonValue = {
|
1203 | ScheduleEvents: [{
|
1204 | ScheduleName: 'node-lambda-test-schedule',
|
1205 | ScheduleState: 'ENABLED',
|
1206 | ScheduleExpression: 'rate(1 hour)',
|
1207 | ScheduleDescription: 'Run node-lambda-test-function once per hour'
|
1208 | }]
|
1209 | }
|
1210 |
|
1211 | let schedule = null
|
1212 |
|
1213 | before(() => {
|
1214 | fs.writeFileSync(
|
1215 | 'event_sources.json',
|
1216 | JSON.stringify(eventSourcesJsonValue)
|
1217 | )
|
1218 | schedule = new ScheduleEvents(aws)
|
1219 | })
|
1220 |
|
1221 | after(() => fs.unlinkSync('event_sources.json'))
|
1222 |
|
1223 | it('program.eventSourceFile is empty value', () => {
|
1224 | program.eventSourceFile = ''
|
1225 | const eventSourceList = lambda._eventSourceList(program)
|
1226 | return lambda._updateScheduleEvents(
|
1227 | schedule,
|
1228 | '',
|
1229 | eventSourceList.ScheduleEvents
|
1230 | ).then((results) => {
|
1231 | assert.deepEqual(results, [])
|
1232 | })
|
1233 | })
|
1234 |
|
1235 | it('simple test with mock', () => {
|
1236 | program.eventSourceFile = 'event_sources.json'
|
1237 | const eventSourceList = lambda._eventSourceList(program)
|
1238 | const functionArn = 'arn:aws:lambda:us-west-2:XXX:function:node-lambda-test-function'
|
1239 | return lambda._updateScheduleEvents(
|
1240 | schedule,
|
1241 | functionArn,
|
1242 | eventSourceList.ScheduleEvents
|
1243 | ).then((results) => {
|
1244 | const expected = [Object.assign(
|
1245 | eventSourcesJsonValue.ScheduleEvents[0],
|
1246 | { FunctionArn: functionArn }
|
1247 | )]
|
1248 | assert.deepEqual(results, expected)
|
1249 | })
|
1250 | })
|
1251 | })
|
1252 |
|
1253 | describe('_updateS3Events', () => {
|
1254 | const S3Events = require(path.join('..', 'lib', 's3_events'))
|
1255 | const eventSourcesJsonValue = {
|
1256 | S3Events: [{
|
1257 | Bucket: 'node-lambda-test-bucket',
|
1258 | Events: ['s3:ObjectCreated:*'],
|
1259 | Filter: null
|
1260 | }]
|
1261 | }
|
1262 |
|
1263 | let s3Events = null
|
1264 |
|
1265 | before(() => {
|
1266 | fs.writeFileSync(
|
1267 | 'event_sources.json',
|
1268 | JSON.stringify(eventSourcesJsonValue)
|
1269 | )
|
1270 | s3Events = new S3Events(aws)
|
1271 | })
|
1272 |
|
1273 | after(() => fs.unlinkSync('event_sources.json'))
|
1274 |
|
1275 | it('program.eventSourceFile is empty value', () => {
|
1276 | program.eventSourceFile = ''
|
1277 | const eventSourceList = lambda._eventSourceList(program)
|
1278 | return lambda._updateS3Events(
|
1279 | s3Events,
|
1280 | '',
|
1281 | eventSourceList.S3Events
|
1282 | ).then(results => {
|
1283 | assert.deepEqual(results, [])
|
1284 | })
|
1285 | })
|
1286 |
|
1287 | it('simple test with mock', () => {
|
1288 | program.eventSourceFile = 'event_sources.json'
|
1289 | const eventSourceList = lambda._eventSourceList(program)
|
1290 | const functionArn = 'arn:aws:lambda:us-west-2:XXX:function:node-lambda-test-function'
|
1291 | return lambda._updateS3Events(
|
1292 | s3Events,
|
1293 | functionArn,
|
1294 | eventSourceList.S3Events
|
1295 | ).then(results => {
|
1296 | const expected = [Object.assign(
|
1297 | eventSourcesJsonValue.S3Events[0],
|
1298 | { FunctionArn: functionArn }
|
1299 | )]
|
1300 | assert.deepEqual(results, expected)
|
1301 | })
|
1302 | })
|
1303 | })
|
1304 |
|
1305 | describe('_uploadNew', () => {
|
1306 | it('simple test with mock', () => {
|
1307 | const params = lambda._params(program, null)
|
1308 | return lambda._uploadNew(awsLambda, params, (results) => {
|
1309 | assert.deepEqual(results, lambdaMockSettings.createFunction)
|
1310 | })
|
1311 | })
|
1312 | })
|
1313 |
|
1314 | describe('_uploadExisting', () => {
|
1315 | it('simple test with mock', () => {
|
1316 | const params = lambda._params(program, null)
|
1317 | return lambda._uploadExisting(awsLambda, params).then((results) => {
|
1318 | assert.deepEqual(results, lambdaMockSettings.updateFunctionConfiguration)
|
1319 | })
|
1320 | })
|
1321 | })
|
1322 |
|
1323 | describe('_setLogsRetentionPolicy', () => {
|
1324 | const CloudWatchLogs = require(path.join('..', 'lib', 'cloudwatch_logs'))
|
1325 | it('simple test with mock', () => {
|
1326 | const params = lambda._params(program, null)
|
1327 | return lambda._setLogsRetentionPolicy(
|
1328 | new CloudWatchLogs(aws),
|
1329 | program,
|
1330 | params.FunctionName
|
1331 | ).then((results) => {
|
1332 | assert.deepEqual(results, { retentionInDays: program.retentionInDays })
|
1333 | })
|
1334 | })
|
1335 | })
|
1336 |
|
1337 | describe('check env vars before create sample files', () => {
|
1338 | const filesCreatedBySetup = [
|
1339 | '.env',
|
1340 | 'deploy.env',
|
1341 | 'event_sources.json'
|
1342 | ]
|
1343 |
|
1344 | beforeEach(() => {
|
1345 | fs.writeFileSync('newContext.json', '{"FOO"="bar"\n"BAZ"="bing"\n}')
|
1346 | fs.writeFileSync('newEvent.json', '{"FOO"="bar"}')
|
1347 | })
|
1348 |
|
1349 | afterEach(() => {
|
1350 | fs.unlinkSync('newContext.json')
|
1351 | fs.unlinkSync('newEvent.json')
|
1352 | filesCreatedBySetup.forEach((file) => fs.unlinkSync(file))
|
1353 | })
|
1354 |
|
1355 | it('should use existing sample files', () => {
|
1356 | program.eventFile = 'newEvent.json'
|
1357 | program.contextFile = 'newContext.json'
|
1358 |
|
1359 | lambda.setup(program)
|
1360 |
|
1361 | assert.equal(fs.readFileSync('newContext.json').toString(), '{"FOO"="bar"\n"BAZ"="bing"\n}')
|
1362 | assert.equal(fs.readFileSync('newEvent.json').toString(), '{"FOO"="bar"}')
|
1363 |
|
1364 | const libPath = path.join(__dirname, '..', 'lib')
|
1365 | filesCreatedBySetup.forEach((targetFile) => {
|
1366 | const boilerplateFile = path.join(libPath, `${targetFile}.example`)
|
1367 |
|
1368 | assert.equal(
|
1369 | fs.readFileSync(targetFile).toString(),
|
1370 | fs.readFileSync(boilerplateFile).toString(),
|
1371 | targetFile
|
1372 | )
|
1373 | })
|
1374 | })
|
1375 | })
|
1376 |
|
1377 | describe('Lambda.prototype._deployToRegion()', () => {
|
1378 | it('simple test with mock', () => {
|
1379 | const params = lambda._params(program, null)
|
1380 | return lambda._deployToRegion(program, params, 'us-east-1').then((result) => {
|
1381 | assert.deepEqual(
|
1382 | result,
|
1383 | [
|
1384 | [[], [], []],
|
1385 | [],
|
1386 | { retentionInDays: 30 }
|
1387 | ]
|
1388 | )
|
1389 | })
|
1390 | })
|
1391 | })
|
1392 |
|
1393 | describe('Lambda.prototype.deploy()', () => {
|
1394 | it('simple test with mock', function () {
|
1395 | _timeout({ this: this, sec: 30 })
|
1396 | return lambda.deploy(program).then((result) => {
|
1397 | assert.isUndefined(result)
|
1398 | })
|
1399 | })
|
1400 | })
|
1401 |
|
1402 | describe('Lambda.prototype._updateTags()', () => {
|
1403 | it('simple test with mock', () => {
|
1404 | return lambda._updateTags(
|
1405 | awsLambda,
|
1406 | 'arn:aws:lambda:eu-central-1:1234567:function:test',
|
1407 | { tagKey: 'tagValue' }).then((result) => {
|
1408 | assert.deepEqual(
|
1409 | result, {}
|
1410 | )
|
1411 | })
|
1412 | })
|
1413 | })
|
1414 | })
|