aws-lambda-runner 1.8.0 → 2.0.0

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.
@@ -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