faux-lambda 0.5.1 → 0.6.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.
- checksums.yaml +4 -4
- data/bin/faux-lambda +9 -87
- data/lib/faux_lambda.rb +59 -0
- data/lib/faux_lambda/cli_handler.rb +78 -0
- data/lib/faux_lambda/version.rb +2 -2
- metadata +4 -7
- data/.gitignore +0 -2
- data/Gemfile +0 -4
- data/Gemfile.lock +0 -19
- data/README.md +0 -78
- data/faux-lambda.gemspec +0 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b3624a8f9bbfff9b594edf213d4f9879c1b38cba
|
4
|
+
data.tar.gz: ecc9b19c5c464d049ec7fc6b3281fda34d1b56d1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c585de977a32487ef44156bda0feeca5b195b58b2b7966c231ac7f366241f4f2240f0d56338f6ae492651c81c22775530b548f999c751eff824912304948cc18
|
7
|
+
data.tar.gz: 24a329756a002fc97ed78127248f90df81e68b059c074535295c20c71e268143bc5cdf2c4cbc8c85cbea550f106641b4d3bb220a150f7275db9df5ab8ac3f567
|
data/bin/faux-lambda
CHANGED
@@ -1,92 +1,14 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require '
|
4
|
-
require '
|
5
|
-
require 'optparse'
|
6
|
-
require_relative '../lib/faux_lambda/version'
|
3
|
+
require 'faux_lambda'
|
4
|
+
require 'faux_lambda/cli_handler'
|
7
5
|
|
8
|
-
|
9
|
-
|
10
|
-
bind: '127.0.0.1',
|
11
|
-
}
|
6
|
+
cli_handler = FauxLambda::CliHandler.new
|
7
|
+
cli_handler.parse_options(ARGV)
|
12
8
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
}
|
19
|
-
|
20
|
-
current_function = :default
|
21
|
-
parser = OptionParser.new do |opts|
|
22
|
-
opts.banner = "AWS Lambda debugging endpoint, version #{FauxLambda::VERSION}."
|
23
|
-
opts.separator('')
|
24
|
-
opts.separator('Usage: faux-lambda --reply "Hello world!"')
|
25
|
-
opts.separator('Query specifiers:')
|
26
|
-
opts.on('--function name', '-f name', 'Name of function to expect, optionally with :<qualifier>') do |function_name|
|
27
|
-
current_function = function_name
|
28
|
-
functions[current_function] = {replies: []}
|
29
|
-
end
|
30
|
-
opts.separator('Reply specifiers:')
|
31
|
-
opts.on('--reply payload', '-r payload', 'Data to respond with') do |payload|
|
32
|
-
functions[current_function][:replies] << payload
|
33
|
-
end
|
34
|
-
opts.on('--fail', 'AWS Lambda framework gives 400') do
|
35
|
-
functions[current_function][:replies] << :fail
|
36
|
-
end
|
37
|
-
end
|
38
|
-
parser.parse!
|
39
|
-
|
40
|
-
def reply_from(replies)
|
41
|
-
if replies.size > 1
|
42
|
-
replies.shift
|
43
|
-
elsif replies.size == 1
|
44
|
-
replies.last
|
45
|
-
else
|
46
|
-
nil
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
def function_data(functions, function_name, qualifier)
|
51
|
-
qualified_function_name = if qualifier
|
52
|
-
"#{function_name}:#{qualifier}"
|
53
|
-
end
|
54
|
-
functions[qualified_function_name] || functions[function_name] || functions[:default]
|
55
|
-
end
|
56
|
-
|
57
|
-
def log(function_name, qualifier, payload, status_code, reply)
|
58
|
-
qualifier ||= "$LATEST"
|
59
|
-
puts "#{function_name}:#{qualifier} called with #{payload}, replying #{status_code}: #{reply}"
|
60
|
-
end
|
61
|
-
|
62
|
-
app = Proc.new do |env|
|
63
|
-
_, version, _, function_name, _ = env['REQUEST_PATH'].split('/')
|
64
|
-
raise "Unknown version #{version}" unless version == '2015-03-31'
|
65
|
-
qs = Rack::Utils.parse_nested_query(env["QUERY_STRING"])
|
66
|
-
qualifier = qs["Qualifier"]
|
67
|
-
payload = env['rack.input'].read
|
68
|
-
|
69
|
-
data = function_data(functions, function_name, qualifier)
|
70
|
-
reply = reply_from(data[:replies])
|
71
|
-
if reply.nil?
|
72
|
-
status_code = '404'
|
73
|
-
reply = 'Not found'
|
74
|
-
elsif reply == :fail
|
75
|
-
status_code = '400'
|
76
|
-
reply = 'Failed'
|
77
|
-
else
|
78
|
-
status_code = '200'
|
79
|
-
end
|
80
|
-
|
81
|
-
log(function_name, qualifier, payload, status_code, reply)
|
82
|
-
headers = {'Content-Type' => 'application/octet-stream'}
|
83
|
-
[status_code, headers, [reply]]
|
9
|
+
begin
|
10
|
+
faux = FauxLambda.new(cli_handler.options)
|
11
|
+
faux.handle(&cli_handler.method(:handler))
|
12
|
+
rescue Interrupt
|
13
|
+
exit 130
|
84
14
|
end
|
85
|
-
|
86
|
-
Rack::Handler::WEBrick.run(
|
87
|
-
app,
|
88
|
-
Port: options[:port],
|
89
|
-
BindAddress: options[:bind],
|
90
|
-
Logger: WEBrick::Log.new($stderr, WEBrick::Log::ERROR),
|
91
|
-
AccessLog: [['/dev/null', WEBrick::AccessLog::COMMON_LOG_FORMAT]]
|
92
|
-
)
|
data/lib/faux_lambda.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'rack'
|
2
|
+
require 'webrick'
|
3
|
+
|
4
|
+
class FauxLambda
|
5
|
+
Call = Struct.new(
|
6
|
+
:function_name,
|
7
|
+
:qualifier,
|
8
|
+
:payload
|
9
|
+
)
|
10
|
+
|
11
|
+
def initialize(options)
|
12
|
+
@bind = options[:bind] || '127.0.0.1'
|
13
|
+
@port = options[:port] || 9123
|
14
|
+
end
|
15
|
+
|
16
|
+
def handle(&block)
|
17
|
+
Rack::Handler::WEBrick.run(
|
18
|
+
lambda do |env|
|
19
|
+
_, version, _, function_name, _ = env['REQUEST_PATH'].split('/')
|
20
|
+
raise "Unknown version #{version}" unless version == '2015-03-31'
|
21
|
+
qs = Rack::Utils.parse_nested_query(env["QUERY_STRING"])
|
22
|
+
qualifier = qs["Qualifier"]
|
23
|
+
payload = env['rack.input'].read
|
24
|
+
|
25
|
+
call = Call.new(function_name, qualifier, payload)
|
26
|
+
begin
|
27
|
+
reply = block.call(call)
|
28
|
+
if reply.nil?
|
29
|
+
status_code = '404'
|
30
|
+
reply = 'Not found'
|
31
|
+
elsif reply == :fail
|
32
|
+
status_code = '400'
|
33
|
+
reply = 'Failed'
|
34
|
+
else
|
35
|
+
status_code = '200'
|
36
|
+
end
|
37
|
+
log(function_name, qualifier, payload, status_code, reply)
|
38
|
+
rescue => e
|
39
|
+
reply = ''
|
40
|
+
log(function_name, qualifier, payload, '200', e)
|
41
|
+
end
|
42
|
+
|
43
|
+
headers = {'Content-Type' => 'application/octet-stream'}
|
44
|
+
[status_code, headers, [reply]]
|
45
|
+
end,
|
46
|
+
Host: @bind,
|
47
|
+
Port: @port,
|
48
|
+
Logger: WEBrick::Log.new($stderr, WEBrick::Log::ERROR),
|
49
|
+
AccessLog: [['/dev/null', WEBrick::AccessLog::COMMON_LOG_FORMAT]]
|
50
|
+
)
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def log(function_name, qualifier, payload, status_code, reply)
|
56
|
+
qualifier ||= "$LATEST"
|
57
|
+
puts "#{function_name}:#{qualifier} called with '#{payload}', replying #{status_code}: '#{reply}'"
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
class FauxLambda::CliHandler
|
4
|
+
attr_reader :options
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@functions = {
|
8
|
+
default: {
|
9
|
+
invocation_type: nil,
|
10
|
+
replies: []
|
11
|
+
}
|
12
|
+
}
|
13
|
+
@options = {}
|
14
|
+
end
|
15
|
+
|
16
|
+
def parse_options(argv)
|
17
|
+
current_function = :default
|
18
|
+
parser = OptionParser.new do |opts|
|
19
|
+
opts.banner = "AWS Lambda debugging endpoint, version #{FauxLambda::VERSION}."
|
20
|
+
opts.separator('')
|
21
|
+
opts.separator('Usage: faux-lambda --reply "Hello world!"')
|
22
|
+
opts.separator('Query specifiers:')
|
23
|
+
opts.on('--function name', '-f name', 'Name of function to expect, optionally with :<qualifier>') do |function_name|
|
24
|
+
current_function = function_name
|
25
|
+
@functions[current_function] = {replies: []}
|
26
|
+
end
|
27
|
+
opts.separator('Reply specifiers:')
|
28
|
+
opts.on('--reply payload', '-r payload', 'Data to respond with') do |payload|
|
29
|
+
@functions[current_function][:replies] << lambda {|_| payload }
|
30
|
+
end
|
31
|
+
opts.on('--handler script.rb', '-h script.rb', 'Ruby script is eval:ed to produce reply') do |script|
|
32
|
+
@functions[current_function][:replies] << make_handler(script)
|
33
|
+
end
|
34
|
+
opts.on('--fail', 'AWS Lambda framework gives 400') do
|
35
|
+
@functions[current_function][:replies] << lambda {|_| :fail }
|
36
|
+
end
|
37
|
+
opts.separator('Control options')
|
38
|
+
opts.on('--port port', 'TCP port to bind, 9123 by default') do |port|
|
39
|
+
@options[:port] = port
|
40
|
+
end
|
41
|
+
opts.on('--bind address', 'Interface to bind to, localhost by default') do |bindaddress|
|
42
|
+
@options[:bind] = bindaddress
|
43
|
+
end
|
44
|
+
end
|
45
|
+
parser.parse!(argv)
|
46
|
+
end
|
47
|
+
|
48
|
+
def handler(call)
|
49
|
+
data = function_data(call)
|
50
|
+
reply_from(data[:replies], call)
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def make_handler(script)
|
56
|
+
code = File.read(script)
|
57
|
+
lambda do |call|
|
58
|
+
eval(code, binding(), script)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def reply_from(replies, call)
|
63
|
+
if replies.size > 1
|
64
|
+
replies.shift.call(call)
|
65
|
+
elsif replies.size == 1
|
66
|
+
replies.last.call(call)
|
67
|
+
else
|
68
|
+
nil
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def function_data(call)
|
73
|
+
qualified_function_name = if call.qualifier
|
74
|
+
"#{call.function_name}:#{call.qualifier}"
|
75
|
+
end
|
76
|
+
@functions[qualified_function_name] || @functions[call.function_name] || @functions[:default]
|
77
|
+
end
|
78
|
+
end
|
data/lib/faux_lambda/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
|
2
|
-
VERSION = '0.
|
1
|
+
class FauxLambda
|
2
|
+
VERSION = '0.6.0'
|
3
3
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: faux-lambda
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Anders Qvist
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-11-
|
11
|
+
date: 2017-11-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -33,12 +33,9 @@ executables:
|
|
33
33
|
extensions: []
|
34
34
|
extra_rdoc_files: []
|
35
35
|
files:
|
36
|
-
- ".gitignore"
|
37
|
-
- Gemfile
|
38
|
-
- Gemfile.lock
|
39
|
-
- README.md
|
40
36
|
- bin/faux-lambda
|
41
|
-
-
|
37
|
+
- lib/faux_lambda.rb
|
38
|
+
- lib/faux_lambda/cli_handler.rb
|
42
39
|
- lib/faux_lambda/version.rb
|
43
40
|
homepage: https://github.com/bittrance/faux-lambda
|
44
41
|
licenses:
|
data/.gitignore
DELETED
data/Gemfile
DELETED
data/Gemfile.lock
DELETED
data/README.md
DELETED
@@ -1,78 +0,0 @@
|
|
1
|
-
# Faux Lambda server for testing
|
2
|
-
|
3
|
-
Lambda service mock implementation for testing and exploration. It starts a simple web server (default is http://localhost:9123) and processes Lambda invocation requests. It can be used both programmatically and as a command line tool.
|
4
|
-
|
5
|
-
## As a command line tool
|
6
|
-
|
7
|
-
In its simplest form:
|
8
|
-
```
|
9
|
-
gem install faux-lambda
|
10
|
-
faux-lambda --reply='{}' &
|
11
|
-
aws --endpoint http://localhost:9123 lambda invoke --function-name whatever /dev/stdout
|
12
|
-
```
|
13
|
-
|
14
|
-
The CLI can also simulate specific scenarios:
|
15
|
-
```
|
16
|
-
$ faux-lambda --function=foo --reply='{}' --function=bar --reply='{}' --reply='{}' --fail &
|
17
|
-
$ aws --endpoint http://localhost:12345 lambda invoke --function-name foo /dev/stdout
|
18
|
-
Called foo with ...
|
19
|
-
{}
|
20
|
-
```
|
21
|
-
Here, each call to function `foo` gets reply `{}`, first call to function `bar` gets `{}`, second gets `{}` and third will fail.
|
22
|
-
|
23
|
-
You can also pipe in replies from `stdin`, one reply per object (may contain newlines):
|
24
|
-
```
|
25
|
-
faux-lambda --function=foo <<<EOF
|
26
|
-
{}
|
27
|
-
{}
|
28
|
-
EOF
|
29
|
-
```
|
30
|
-
In this mode, the CLI will accept only one function, but may prove useful where there are numerous or large replies.
|
31
|
-
|
32
|
-
```
|
33
|
-
Usage: faux-lambda [options]
|
34
|
-
Query specifiers:
|
35
|
-
--function-name=regex
|
36
|
-
--async Require invocation to be async
|
37
|
-
--sync Require invocation to be sync
|
38
|
-
Reply specifiers:
|
39
|
-
--reply=json Send this reply
|
40
|
-
--fail ...
|
41
|
-
Various:
|
42
|
-
--quiet Don't log sent and received messages
|
43
|
-
--version
|
44
|
-
```
|
45
|
-
|
46
|
-
## faux-lambda as a library
|
47
|
-
|
48
|
-
You can use `faux-lambda` programmatically too, like so:
|
49
|
-
```
|
50
|
-
require `faux-lambda`
|
51
|
-
lambda = FauxLambda.new(port: 12345).handle do |call|
|
52
|
-
return if call.async
|
53
|
-
if call.function_name == 'foo'
|
54
|
-
'{}'
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
Aws::Lambda.new(endpoint: lambda.endpoint).invoke(...)
|
59
|
-
```
|
60
|
-
|
61
|
-
## faux-lambda in your specs
|
62
|
-
|
63
|
-
Or in your specs as if FauxLambda were an `rspec-mocks` double:
|
64
|
-
```
|
65
|
-
let(:lambda) { FauxLambda.new }
|
66
|
-
before do
|
67
|
-
allow(lambda).to receive(:incrementer).and_return(43)
|
68
|
-
end
|
69
|
-
|
70
|
-
subject do
|
71
|
-
ThingUnderTest.new(lambda.endpoint).do_math(42)
|
72
|
-
end
|
73
|
-
|
74
|
-
it 'invokes lambda and returns its value' do
|
75
|
-
expect(subject).to equal(43)
|
76
|
-
expect(lambda).to have_received(:incrementer).with(value: 42)
|
77
|
-
end
|
78
|
-
```
|
data/faux-lambda.gemspec
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
require File.expand_path('../lib/faux_lambda/version', __FILE__)
|
2
|
-
|
3
|
-
Gem::Specification.new do |spec|
|
4
|
-
spec.name = 'faux-lambda'
|
5
|
-
spec.version = FauxLambda::VERSION
|
6
|
-
spec.summary = 'faux-lambda provides a simple tool to mock AWS Lambda endpoint'
|
7
|
-
spec.description = 'faux-lambda is a toolbox to make it easier to develop client that call AWS Lambda functions. A simple CLI lets you mock AWS Lambda and specify replies for specific function as well as simulate AWS Lambda framework failures.'
|
8
|
-
spec.authors = ['Anders Qvist']
|
9
|
-
spec.email = 'quest@lysator.liu.se'
|
10
|
-
spec.homepage = 'https://github.com/bittrance/faux-lambda'
|
11
|
-
spec.license = 'MIT'
|
12
|
-
|
13
|
-
spec.executables = ['faux-lambda']
|
14
|
-
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(/^spec/) }
|
15
|
-
|
16
|
-
spec.required_ruby_version = '>= 2.0.0'
|
17
|
-
|
18
|
-
spec.add_runtime_dependency 'rack', '~> 2.0'
|
19
|
-
end
|