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.
- checksums.yaml +4 -4
- data/js/package-lock.json +2787 -0
- data/js/package.json +9 -5
- data/js/request.js +47 -52
- data/js/startup.js +2 -3
- data/lib/lambda_runner.rb +23 -4
- data/spec/lambdarunner_runner_spec.rb +15 -6
- metadata +4 -3
data/js/package.json
CHANGED
@@ -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": "^
|
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
|
}
|
data/js/request.js
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
|
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
|
-
|
32
|
+
return process.env.AWS_DEFAULT_REGION || process.env.AWS_REGION || process.env.AMAZON_REGION || "xx-dummy-0";
|
32
33
|
};
|
33
34
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
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
|
-
|
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
|
-
|
68
|
-
|
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
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
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.
|
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
|
-
|
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
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
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
|
-
(
|
158
|
-
|
159
|
-
|
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
|
-
|
163
|
-
|
158
|
+
// non-standard stringification of undefined
|
159
|
+
if (answer.data === undefined) answer.data = null;
|
164
160
|
|
165
|
-
|
166
|
-
|
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
|
|
data/js/startup.js
CHANGED
@@ -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();
|
data/lib/lambda_runner.rb
CHANGED
@@ -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("
|
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 '
|
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 = [
|
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
|
-
|
4
|
+
|
5
|
+
shared_examples "AWS Lambda: " do |lambda_file|
|
5
6
|
|
6
7
|
before(:all) do
|
7
|
-
test_js = File.expand_path(
|
8
|
-
@under_test = LambdaRunner::Runner.new(test_js, "
|
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
|
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
|
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:
|
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:
|
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.
|
181
|
+
rubygems_version: 2.5.2.2
|
181
182
|
signing_key:
|
182
183
|
specification_version: 4
|
183
184
|
summary: AWS Lambda testing helper
|