aws-lambda-runner 1.8.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,26 +1,30 @@
1
1
  {
2
2
  "name": "lambda-helper",
3
3
  "version": "1.0.0",
4
- "description": "",
4
+ "description": "lambda-helper",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/bbc/aws-lambda-runner.git"
8
+ },
5
9
  "main": "startup.js",
6
10
  "scripts": {
7
11
  "test": "mocha"
8
12
  },
9
13
  "author": "",
10
- "license": " ",
14
+ "license": "Apache-2.0",
11
15
  "devDependencies": {
12
16
  "assert": "^1.4.1",
13
17
  "jshint": "^2.9.4",
14
- "mocha": "^3.3.0",
18
+ "mocha": "^5.2.0",
15
19
  "mocha-jshint": "^2.3.1",
16
20
  "mock-res": "^0.4.1",
17
21
  "should": "^11.2.1"
18
22
  },
19
23
  "dependencies": {
24
+ "always-done": "^1.1.0",
20
25
  "aws-sdk": "*",
21
- "istanbul": "^0.4.5",
22
- "merge": "^1.2.0",
23
26
  "mock-req": "^0.2.0",
27
+ "nyc": "^13.1.0",
24
28
  "stdio": "^0.2.7"
25
29
  }
26
30
  }
@@ -1,5 +1,6 @@
1
- var merge = require('merge');
1
+ /* istanbul ignore file */
2
2
  var url = require('url');
3
+ const alwaysDone = require('always-done');
3
4
 
4
5
  var next_id = 0;
5
6
  // FIXME: this object grows forever - entries are never removed. Should they
@@ -28,24 +29,22 @@ Job.prototype.doTimedOut = function () {
28
29
  };
29
30
 
30
31
  var region = function () {
31
- return process.env.AWS_DEFAULT_REGION || process.env.AWS_REGION || process.env.AMAZON_REGION || "xx-dummy-0";
32
+ return process.env.AWS_DEFAULT_REGION || process.env.AWS_REGION || process.env.AMAZON_REGION || "xx-dummy-0";
32
33
  };
33
34
 
34
- var defaultContextObject = function () {
35
- return {
36
- // Fixed, but reasonably representative
37
- functionName: "via-aws-lambda-runner",
38
- functionVersion: "$LATEST",
39
- invokedFunctionArn: "arn:aws:lambda:" + region() + ":000000000000:function:via-aws-lambda-runner:$LATEST",
40
- memoryLimitInMB: 100,
41
- awsRequestId: "00000000-0000-0000-0000-000000000000",
42
- logGroupName: "/aws/lambda/via-aws-lambda-runner",
43
- logStreamName: "some-log-stream-name",
44
- };
45
- };
35
+ const defaultContextObject = () => ({
36
+ // Fixed, but reasonably representative
37
+ functionName: "via-aws-lambda-runner",
38
+ functionVersion: "$LATEST",
39
+ invokedFunctionArn: "arn:aws:lambda:" + region() + ":000000000000:function:via-aws-lambda-runner:$LATEST",
40
+ memoryLimitInMB: 100,
41
+ awsRequestId: "00000000-0000-0000-0000-000000000000",
42
+ logGroupName: "/aws/lambda/via-aws-lambda-runner",
43
+ logStreamName: "some-log-stream-name",
44
+ });
46
45
 
47
46
  var makeContextObject = function (timeout, overrides) {
48
- var context = merge(true, defaultContextObject(), overrides);
47
+ const context = Object.assign(defaultContextObject(), overrides);
49
48
 
50
49
  var approximateEndTime = (new Date().getTime()) + timeout;
51
50
 
@@ -64,19 +63,24 @@ var startJob = function (job, requestObject, handler, opts) {
64
63
  var event = requestObject.event;
65
64
 
66
65
  var context = makeContextObject(opts.timeout, requestObject.context || {});
67
- context.done = function (err, result) {
68
- job.doCompletion(err, result);
66
+
67
+ const done = (err, res) => {
69
68
  if (err) {
70
69
  console.warn('Error:', err);
70
+ job.doError(err);
71
+ } else {
72
+ job.doCompletion(err, res);
71
73
  }
72
74
  };
73
75
 
74
- try {
75
- handler(event, context, context.done);
76
- } catch (e) {
77
- console.log("Handler crashed", e);
78
- job.doError(e);
79
- }
76
+ context.done = done;
77
+
78
+ const options = {
79
+ args: [event, context]
80
+ };
81
+
82
+ alwaysDone(handler, options, done);
83
+
80
84
  };
81
85
 
82
86
  var doCreateJob = function (req, res, opts, handler) {
@@ -112,17 +116,12 @@ var getJobStatus = function (result) {
112
116
  var status = null;
113
117
  var responseBody = null;
114
118
 
115
- if (result.completionValues) {
116
- if (result.completionValues[0] !== null && result.completionValues[0] !== undefined) {
117
- status = 502;
118
- responseBody = result.completionValues[0];
119
- } else {
120
- status = 201;
121
- responseBody = result.completionValues[1];
122
- }
123
- } else if (result.threw) {
119
+ if (result.threw) {
124
120
  status = 500;
125
- responseBody = result.threw.toString();
121
+ responseBody = result.threw instanceof Error ? `Error: ${result.threw.message}` : JSON.stringify(result.threw);
122
+ } else if (result.completionValues) {
123
+ status = 201;
124
+ responseBody = result.completionValues[1];
126
125
  } else if (result.timedOut) {
127
126
  status = 504;
128
127
  } else {
@@ -141,30 +140,26 @@ exports.request = function(req, res, opts, handler, server) {
141
140
 
142
141
  } else if (req.method === 'DELETE') {
143
142
 
144
- (function () {
145
- // FIXME untested
146
- res.writeHead(202, {'Content-Type': 'text/plain'});
147
- var terminationMessage = 'Terminating server at http://[localhost]:' + opts.port + ' for ' + opts['module-path'] + ' / ' + opts.handler;
148
- res.end(terminationMessage + '\n');
149
- console.info(terminationMessage);
150
- if (server) {
151
- server.close();
152
- }
153
- })();
143
+ // FIXME untested
144
+ res.writeHead(202, {'Content-Type': 'text/plain'});
145
+ var terminationMessage = 'Terminating server at http://[localhost]:' + opts.port + ' for ' + opts['module-path'] + ' / ' + opts.handler;
146
+ res.end(terminationMessage + '\n');
147
+ console.info(terminationMessage);
148
+ if (server) {
149
+ server.close();
150
+ }
154
151
 
155
152
  } else if (req.method === 'GET') {
156
153
 
157
- (function () {
158
- var request_id = parseInt(url.parse(req.url, true).query.id);
159
- var result = jobs[request_id];
160
- var answer = result ? getJobStatus(result) : { status: 404, data: null };
154
+ var request_id = parseInt(url.parse(req.url, true).query.id);
155
+ var result = jobs[request_id];
156
+ var answer = result ? getJobStatus(result) : { status: 404, data: null };
161
157
 
162
- // non-standard stringification of undefined
163
- if (answer.data === undefined) answer.data = null;
158
+ // non-standard stringification of undefined
159
+ if (answer.data === undefined) answer.data = null;
164
160
 
165
- res.writeHead(answer.status, {'Content-Type': 'application/json'});
166
- res.end(JSON.stringify(answer.data) + '\n');
167
- })();
161
+ res.writeHead(answer.status, {'Content-Type': 'application/json'});
162
+ res.end(JSON.stringify(answer.data) + '\n');
168
163
 
169
164
  } else {
170
165
 
@@ -1,5 +1,4 @@
1
-
2
-
1
+ /* istanbul ignore file */
3
2
  var http = require('http');
4
3
  var stdio = require('stdio');
5
4
  var request = require('./request.js');
@@ -10,7 +9,7 @@ var opts = stdio.getopt({
10
9
  'handler': {mandatory: true, args: 1, key: 'h', description: 'handler function to call'},
11
10
  'timeout': {mandatory: true, args: 1, key: 't', description: 'timeout for handler function'}
12
11
  });
13
- console.info(opts);
12
+ console.info('Startup with options: ', JSON.stringify(opts, null, 2));
14
13
 
15
14
  var module = require(opts['module-path']);
16
15
  var server = http.createServer();
@@ -16,10 +16,10 @@ module LambdaRunner
16
16
 
17
17
  def install_deps
18
18
  @npm_cwd = File.expand_path('../../js/', __FILE__)
19
- STDOUT.puts("trying to use npm install in #{@npm_cwd}")
19
+ STDOUT.puts("Trying to use npm install in #{@npm_cwd}")
20
20
  npm_install_pid = spawn('npm', 'install', chdir: @npm_cwd)
21
21
  Process.wait(npm_install_pid)
22
- fail 'failed to install the lambda startup' if ($CHILD_STATUS.exitstatus != 0)
22
+ fail 'Failed to install the lambda startup' if ($CHILD_STATUS.exitstatus != 0)
23
23
  end
24
24
 
25
25
  def add_aws_sdk
@@ -31,6 +31,7 @@ module LambdaRunner
31
31
  if opts[:timeout] == nil
32
32
  opts[:timeout] = '30000'
33
33
  end
34
+ @cover = opts[:cover]
34
35
  install_deps
35
36
  #copy over aws sdk only if it is not already there
36
37
  if !File.directory?("#{File.dirname(@module_path)}/node_modules/aws-sdk")
@@ -38,9 +39,17 @@ module LambdaRunner
38
39
  end
39
40
  # start node in a way that emulates how it's run in production
40
41
  cmd = ['node']
41
- cmd = [File.join(@npm_cwd, 'node_modules/.bin/istanbul'), 'cover', '--root', File.dirname(@module_path), '--'] if opts[:cover]
42
+ cmd = [
43
+ File.join(@npm_cwd, 'node_modules/.bin/nyc'),
44
+ '--cwd ', File.dirname(@module_path),
45
+ '--reporter=lcov',
46
+ '--report-dir ', File.join(Dir.pwd, 'coverage'),
47
+ '--temp-dir ', File.join(Dir.pwd, 'coverage', 'temp'),
48
+ 'node'
49
+ ] if opts[:cover]
42
50
  cmd += [File.join(@npm_cwd, 'startup.js'), '-p', @port.to_s, '-m', @module_path, '-h', @name, '-t', opts[:timeout]]
43
51
  @proc = ProcessHelper::ProcessHelper.new(print_lines: true)
52
+ puts cmd.join(' ')
44
53
  @proc.start(cmd, 'Server running at http')
45
54
  end
46
55
 
@@ -59,7 +68,6 @@ module LambdaRunner
59
68
  when 200 then sleep(0.1)
60
69
  when 201 then return data
61
70
  when 500 then fail data
62
- when 502 then fail data
63
71
  when 504 then fail 'timeout'
64
72
  else fail "unknown response #{response.code}"
65
73
  end
@@ -67,7 +75,18 @@ module LambdaRunner
67
75
  end
68
76
 
69
77
  def stop
78
+ puts "Stopping Lambda Server"
70
79
  RestClient.delete(url)
80
+ @proc.kill
81
+
82
+ # TODO currently coverage is not working on other projects
83
+ cmd = [
84
+ File.join(@npm_cwd, 'node_modules/.bin/nyc'),
85
+ 'report',
86
+ '--report-dir ', File.join(Dir.pwd, 'coverage'),
87
+ '--temp-dir ', File.join(Dir.pwd, 'coverage', 'temp'),
88
+ ]
89
+ system(cmd.join(' ')) if @cover
71
90
  end
72
91
  end
73
92
 
@@ -1,11 +1,12 @@
1
1
  require 'rspec'
2
2
  require_relative '../lib/lambda_runner'
3
3
 
4
- describe LambdaRunner::Runner do
4
+
5
+ shared_examples "AWS Lambda: " do |lambda_file|
5
6
 
6
7
  before(:all) do
7
- test_js = File.expand_path("test.js", File.dirname(__FILE__))
8
- @under_test = LambdaRunner::Runner.new(test_js, "node_4_3_handler")
8
+ test_js = File.expand_path(lambda_file, File.dirname(__FILE__))
9
+ @under_test = LambdaRunner::Runner.new(test_js, "handler")
9
10
  @under_test.start
10
11
  end
11
12
 
@@ -13,15 +14,23 @@ describe LambdaRunner::Runner do
13
14
  @under_test.stop
14
15
  end
15
16
 
16
- it "should emulate AWS Lambda (node.js v4.3) - success" do
17
+ it "should emulate - success" do
17
18
  r = @under_test.process_event({ succeed: { delay: 50, result: "ohai" } })
18
19
  expect(r).to eq("ohai")
19
20
  end
20
21
 
21
- it "should emulate AWS Lambda (node.js v4.3) - failure" do
22
+ it "should emulate - failure" do
22
23
  expect {
23
24
  @under_test.process_event({ fail: { delay: 50, err: "oh noes" } })
24
- }.to raise_error("oh noes")
25
+ }.to raise_error("Error: oh noes")
25
26
  end
26
27
 
27
28
  end
29
+
30
+ describe LambdaRunner::Runner do
31
+
32
+ it_should_behave_like "AWS Lambda: ", "test_callback.js"
33
+ it_should_behave_like "AWS Lambda: ", "test_promise.js"
34
+ it_should_behave_like "AWS Lambda: ", "test_async.js"
35
+
36
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aws-lambda-runner
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - andrew wheat
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2017-07-25 00:00:00.000000000 Z
14
+ date: 2018-11-21 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: process-helper
@@ -145,6 +145,7 @@ executables: []
145
145
  extensions: []
146
146
  extra_rdoc_files: []
147
147
  files:
148
+ - js/package-lock.json
148
149
  - js/package.json
149
150
  - js/request.js
150
151
  - js/startup.js
@@ -177,7 +178,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
177
178
  version: '0'
178
179
  requirements: []
179
180
  rubyforge_project:
180
- rubygems_version: 2.5.1
181
+ rubygems_version: 2.5.2.2
181
182
  signing_key:
182
183
  specification_version: 4
183
184
  summary: AWS Lambda testing helper