fake_sqs 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/MIT-LICENSE.txt +22 -0
- data/README.md +89 -0
- data/Rakefile +6 -0
- data/bin/fake_sqs +41 -0
- data/fake_sqs.gemspec +32 -0
- data/lib/fake_sqs.rb +35 -0
- data/lib/fake_sqs/message.rb +21 -0
- data/lib/fake_sqs/queue.rb +67 -0
- data/lib/fake_sqs/queue_factory.rb +16 -0
- data/lib/fake_sqs/queues.rb +57 -0
- data/lib/fake_sqs/responder.rb +22 -0
- data/lib/fake_sqs/server.rb +172 -0
- data/lib/fake_sqs/show_output.rb +18 -0
- data/lib/fake_sqs/version.rb +3 -0
- data/lib/fake_sqs/web_interface.rb +45 -0
- data/spec/acceptance/message_actions_spec.rb +59 -0
- data/spec/acceptance/queue_actions_spec.rb +44 -0
- data/spec/support/aws.rb +99 -0
- data/spec/unit/message_spec.rb +36 -0
- data/spec/unit/queue_factory_spec.rb +13 -0
- data/spec/unit/queue_spec.rb +147 -0
- data/spec/unit/queues_spec.rb +102 -0
- data/spec/unit/responder_spec.rb +44 -0
- data/spec/unit/show_output_spec.rb +22 -0
- metadata +243 -0
@@ -0,0 +1,172 @@
|
|
1
|
+
module FakeSQS
|
2
|
+
class Server
|
3
|
+
|
4
|
+
attr_reader :port, :host, :queues, :responder
|
5
|
+
|
6
|
+
def initialize(options = {})
|
7
|
+
@host = options.fetch(:host)
|
8
|
+
@port = options.fetch(:port)
|
9
|
+
@queues = options.fetch(:queues)
|
10
|
+
@responder = options.fetch(:responder)
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(action, *args)
|
14
|
+
public_send(action, *args)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Actions for Queues
|
18
|
+
|
19
|
+
def create_queue(params)
|
20
|
+
name = params.fetch("QueueName")
|
21
|
+
queue = queues.create(name, params)
|
22
|
+
respond :CreateQueue do |xml|
|
23
|
+
xml.QueueUrl url_for(queue.name)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def delete_queue(name, params)
|
28
|
+
queues.delete(name, params)
|
29
|
+
respond :DeleteQueue
|
30
|
+
end
|
31
|
+
|
32
|
+
def list_queues(params)
|
33
|
+
found = queues.list(params)
|
34
|
+
respond :ListQueues do |xml|
|
35
|
+
found.each do |queue|
|
36
|
+
xml.QueueUrl url_for(queue.name)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def get_queue_url(params)
|
42
|
+
name = params.fetch("QueueName")
|
43
|
+
queue = queues.get(name, params)
|
44
|
+
respond :GetQueueUrl do |xml|
|
45
|
+
xml.QueueUrl url_for(queue.name)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def get_queue_attributes(name, params)
|
50
|
+
end
|
51
|
+
|
52
|
+
def set_queue_attributes(name, params)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Actions for Access Control on Queues
|
56
|
+
|
57
|
+
def add_permission(name, params)
|
58
|
+
end
|
59
|
+
|
60
|
+
def remove_persmission(name, params)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Actions for Messages
|
64
|
+
|
65
|
+
def send_message(name, params)
|
66
|
+
queue = queues.get(name)
|
67
|
+
message = queue.send_message(params)
|
68
|
+
respond :SendMessage do |xml|
|
69
|
+
xml.MD5OfMessageBody message.md5
|
70
|
+
xml.MessageId message.id
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def receive_message(name, params)
|
75
|
+
queue = queues.get(name)
|
76
|
+
messages = queue.receive_message(params)
|
77
|
+
respond :ReceiveMessage do |xml|
|
78
|
+
messages.each do |receipt, message|
|
79
|
+
xml.Message do
|
80
|
+
xml.MessageId message.id
|
81
|
+
xml.ReceiptHandle receipt
|
82
|
+
xml.MD5OfMessageBody message.md5
|
83
|
+
xml.Body message.body
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def delete_message(name, params)
|
90
|
+
queue = queues.get(name)
|
91
|
+
|
92
|
+
receipt = params.fetch("ReceiptHandle")
|
93
|
+
queue.delete_message(receipt)
|
94
|
+
respond :DeleteMessage
|
95
|
+
end
|
96
|
+
|
97
|
+
def delete_message_batch(name, params)
|
98
|
+
queue = queues.get(name)
|
99
|
+
receipts = params.select { |k,v| k =~ /DeleteMessageBatchRequestEntry\.\d+\.ReceiptHandle/ }
|
100
|
+
|
101
|
+
deleted = []
|
102
|
+
|
103
|
+
receipts.each do |key, value|
|
104
|
+
id = key.split('.')[1]
|
105
|
+
queue.delete_message(value)
|
106
|
+
deleted << params.fetch("DeleteMessageBatchRequestEntry.#{id}.Id")
|
107
|
+
end
|
108
|
+
|
109
|
+
respond :DeleteMessageBatch do |xml|
|
110
|
+
deleted.each do |id|
|
111
|
+
xml.DeleteMessageBatchResultEntry do
|
112
|
+
xml.Id id
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def send_message_batch(name, params)
|
119
|
+
queue = queues.get(name)
|
120
|
+
|
121
|
+
messages = params.select { |k,v| k =~ /SendMessageBatchRequestEntry\.\d+\.MessageBody/ }
|
122
|
+
|
123
|
+
results = {}
|
124
|
+
|
125
|
+
messages.each do |key, value|
|
126
|
+
id = key.split('.')[1]
|
127
|
+
msg_id = params.fetch("SendMessageBatchRequestEntry.#{id}.Id")
|
128
|
+
delay = params["SendMessageBatchRequestEntry.#{id}.DelaySeconds"]
|
129
|
+
message = queue.send_message("MessageBody" => value, "DelaySeconds" => delay)
|
130
|
+
results[msg_id] = message
|
131
|
+
end
|
132
|
+
|
133
|
+
respond :SendMessageBatch do |xml|
|
134
|
+
results.each do |msg_id, message|
|
135
|
+
xml.SendMessageBatchResultEntry do
|
136
|
+
xml.Id msg_id
|
137
|
+
xml.MessageId message.id
|
138
|
+
xml.MD5OfMessageBody message.md5
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
|
145
|
+
def change_message_visibility(name, params)
|
146
|
+
end
|
147
|
+
|
148
|
+
def change_message_visibility_batch(name, params)
|
149
|
+
end
|
150
|
+
|
151
|
+
# Fake actions
|
152
|
+
|
153
|
+
def reset
|
154
|
+
queues.reset
|
155
|
+
end
|
156
|
+
|
157
|
+
def expire
|
158
|
+
queues.expire
|
159
|
+
end
|
160
|
+
|
161
|
+
private
|
162
|
+
|
163
|
+
def respond(*args, &block)
|
164
|
+
responder.call(*args, &block)
|
165
|
+
end
|
166
|
+
|
167
|
+
def url_for(id)
|
168
|
+
"http://#{host}:#{port}/#{id}"
|
169
|
+
end
|
170
|
+
|
171
|
+
end
|
172
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module FakeSQS
|
2
|
+
class ShowOutput
|
3
|
+
|
4
|
+
def initialize(app)
|
5
|
+
@app = app
|
6
|
+
end
|
7
|
+
|
8
|
+
def call(env)
|
9
|
+
request = Rack::Request.new(env)
|
10
|
+
result = @app.call(env)
|
11
|
+
puts request.params.to_yaml
|
12
|
+
puts
|
13
|
+
puts *result.last
|
14
|
+
result
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
|
3
|
+
module FakeSQS
|
4
|
+
class WebInterface < Sinatra::Base
|
5
|
+
|
6
|
+
configure do
|
7
|
+
set :sqs, FakeSQS.server(port: settings.port, host: settings.bind)
|
8
|
+
end
|
9
|
+
|
10
|
+
helpers do
|
11
|
+
|
12
|
+
def action
|
13
|
+
underscore(params.fetch("Action"))
|
14
|
+
end
|
15
|
+
|
16
|
+
def underscore(string)
|
17
|
+
string.gsub(/([A-Z])/) { |m| "_#{m[0]}".downcase }.sub(/^_/, '')
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
get "/" do
|
23
|
+
200
|
24
|
+
end
|
25
|
+
|
26
|
+
delete "/" do
|
27
|
+
settings.sqs.reset
|
28
|
+
200
|
29
|
+
end
|
30
|
+
|
31
|
+
put "/" do
|
32
|
+
settings.sqs.expire
|
33
|
+
200
|
34
|
+
end
|
35
|
+
|
36
|
+
post "/" do
|
37
|
+
settings.sqs.call(action, params)
|
38
|
+
end
|
39
|
+
|
40
|
+
post "/:queue" do |queue|
|
41
|
+
settings.sqs.call(action, queue, params)
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'support/aws'
|
2
|
+
|
3
|
+
describe "Actions for Messages", :acceptance do
|
4
|
+
|
5
|
+
before do
|
6
|
+
sqs.queues.create("test")
|
7
|
+
end
|
8
|
+
|
9
|
+
let(:sqs) { AWS::SQS.new }
|
10
|
+
let(:queue) { sqs.queues.named("test") }
|
11
|
+
|
12
|
+
specify "SendMessage" do
|
13
|
+
msg = "this is my message"
|
14
|
+
result = queue.send_message(msg)
|
15
|
+
result.md5.should eq Digest::MD5.hexdigest(msg)
|
16
|
+
end
|
17
|
+
|
18
|
+
specify "ReceiveMessage" do
|
19
|
+
body = "test 123"
|
20
|
+
queue.send_message(body)
|
21
|
+
message = queue.receive_message
|
22
|
+
message.body.should eq body
|
23
|
+
end
|
24
|
+
|
25
|
+
specify "DeleteMessage" do
|
26
|
+
queue.send_message("test")
|
27
|
+
|
28
|
+
message1 = queue.receive_message
|
29
|
+
message1.delete
|
30
|
+
|
31
|
+
let_messages_in_flight_expire
|
32
|
+
|
33
|
+
message2 = queue.receive_message
|
34
|
+
message2.should be_nil
|
35
|
+
end
|
36
|
+
|
37
|
+
specify "DeleteMessageBatch" do
|
38
|
+
queue.send_message("test1")
|
39
|
+
queue.send_message("test2")
|
40
|
+
|
41
|
+
message1 = queue.receive_message
|
42
|
+
message2 = queue.receive_message
|
43
|
+
queue.batch_delete(message1, message2)
|
44
|
+
|
45
|
+
let_messages_in_flight_expire
|
46
|
+
|
47
|
+
message3 = queue.receive_message
|
48
|
+
message3.should be_nil
|
49
|
+
end
|
50
|
+
|
51
|
+
specify "SendMessageBatch" do
|
52
|
+
bodies = %w(a b c)
|
53
|
+
queue.batch_send(*bodies)
|
54
|
+
|
55
|
+
messages = queue.receive_message(:limit => 10)
|
56
|
+
messages.map(&:body).should match_array bodies
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'support/aws'
|
2
|
+
|
3
|
+
describe "Actions for Queues", :acceptance do
|
4
|
+
|
5
|
+
let(:sqs) { AWS::SQS.new }
|
6
|
+
|
7
|
+
specify "CreateQueue" do
|
8
|
+
queue = sqs.queues.create("test-create-queue")
|
9
|
+
queue.url.should eq "http://0.0.0.0:4567/test-create-queue"
|
10
|
+
end
|
11
|
+
|
12
|
+
specify "GetQueueUrl" do
|
13
|
+
sqs.queues.create("test-get-queue-url")
|
14
|
+
queue = sqs.queues.named("test-get-queue-url")
|
15
|
+
queue.url.should eq "http://0.0.0.0:4567/test-get-queue-url"
|
16
|
+
end
|
17
|
+
|
18
|
+
specify "ListQueues" do
|
19
|
+
sqs.queues.create("test-list-1")
|
20
|
+
sqs.queues.create("test-list-2")
|
21
|
+
queues = sqs.queues.map(&:url).should eq [
|
22
|
+
"http://0.0.0.0:4567/test-list-1",
|
23
|
+
"http://0.0.0.0:4567/test-list-2"
|
24
|
+
]
|
25
|
+
end
|
26
|
+
|
27
|
+
specify "ListQueues with prefix" do
|
28
|
+
sqs.queues.create("test-list-1")
|
29
|
+
sqs.queues.create("test-list-2")
|
30
|
+
sqs.queues.create("other-list-3")
|
31
|
+
queues = sqs.queues.with_prefix("test").map(&:url).should eq [
|
32
|
+
"http://0.0.0.0:4567/test-list-1",
|
33
|
+
"http://0.0.0.0:4567/test-list-2"
|
34
|
+
]
|
35
|
+
end
|
36
|
+
|
37
|
+
specify "DeleteQueue" do
|
38
|
+
url = sqs.queues.create("test-delete").url
|
39
|
+
sqs.should have(1).queues
|
40
|
+
sqs.queues[url].delete
|
41
|
+
sqs.should have(0).queues
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
data/spec/support/aws.rb
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'aws-sdk'
|
2
|
+
require 'fake_sqs'
|
3
|
+
require 'faraday'
|
4
|
+
require 'uri'
|
5
|
+
require 'thin'
|
6
|
+
|
7
|
+
Thread.abort_on_exception = true
|
8
|
+
|
9
|
+
ENV['RACK_ENV'] = 'test'
|
10
|
+
|
11
|
+
require 'webmock/rspec'
|
12
|
+
WebMock.disable_net_connect!(:allow_localhost => true)
|
13
|
+
|
14
|
+
Thin::Logging.silent = true
|
15
|
+
|
16
|
+
class FakeServer
|
17
|
+
|
18
|
+
attr_reader :url
|
19
|
+
|
20
|
+
def initialize(url = "http://localhost:4567")
|
21
|
+
@url = url
|
22
|
+
end
|
23
|
+
|
24
|
+
def uri
|
25
|
+
@uri ||= URI.parse(url)
|
26
|
+
end
|
27
|
+
|
28
|
+
def port
|
29
|
+
uri.port
|
30
|
+
end
|
31
|
+
|
32
|
+
def host
|
33
|
+
uri.host
|
34
|
+
end
|
35
|
+
|
36
|
+
def ssl?
|
37
|
+
uri.scheme == "https"
|
38
|
+
end
|
39
|
+
|
40
|
+
def start
|
41
|
+
return if @started
|
42
|
+
@started = true
|
43
|
+
@fake_sqs_thread = Thread.new {
|
44
|
+
load File.expand_path('../../../bin/fake_sqs', __FILE__)
|
45
|
+
Sinatra::Application.run!
|
46
|
+
}
|
47
|
+
wait_until_up
|
48
|
+
end
|
49
|
+
|
50
|
+
def stop
|
51
|
+
@fake_sqs_thread.kill
|
52
|
+
end
|
53
|
+
|
54
|
+
def reset
|
55
|
+
Faraday.delete(url)
|
56
|
+
end
|
57
|
+
|
58
|
+
def expire_messages_in_flight
|
59
|
+
Faraday.put(url)
|
60
|
+
end
|
61
|
+
|
62
|
+
def wait_until_up(tries = 0)
|
63
|
+
fail "Server didn't start in time" if tries > 200
|
64
|
+
response = Faraday.get(url)
|
65
|
+
if response.status != 200
|
66
|
+
wait_until_up(tries + 1)
|
67
|
+
end
|
68
|
+
rescue Faraday::Error::ConnectionFailed
|
69
|
+
wait_until_up(tries + 1)
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
$fake_server = FakeServer.new
|
75
|
+
|
76
|
+
module FakeServerHelper
|
77
|
+
|
78
|
+
def let_messages_in_flight_expire
|
79
|
+
$fake_server.expire_messages_in_flight
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
AWS.config(
|
85
|
+
:use_ssl => $fake_server.ssl?,
|
86
|
+
:sqs_endpoint => $fake_server.host,
|
87
|
+
:sqs_port => $fake_server.port,
|
88
|
+
:access_key_id => "access key id",
|
89
|
+
:secret_access_key => "secret access key"
|
90
|
+
)
|
91
|
+
|
92
|
+
|
93
|
+
RSpec.configure do |config|
|
94
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
95
|
+
config.before(:suite) { $fake_server.start }
|
96
|
+
config.after(:suite) { $fake_server.stop }
|
97
|
+
config.before(:each, :acceptance) { $fake_server.reset }
|
98
|
+
config.include FakeServerHelper
|
99
|
+
end
|