fake_sqs 0.0.2
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.
- 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
|