fake_servicebus 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.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.rspec +4 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/LICENSE.md +20 -0
- data/README.md +41 -0
- data/Rakefile +31 -0
- data/bin/fake_servicebus +65 -0
- data/fake_servicebus.gemspec +33 -0
- data/lib/fake_servicebus.rb +90 -0
- data/lib/fake_servicebus/actions/create_queue.rb +64 -0
- data/lib/fake_servicebus/actions/delete_message.rb +19 -0
- data/lib/fake_servicebus/actions/delete_queue.rb +18 -0
- data/lib/fake_servicebus/actions/get_queue.rb +20 -0
- data/lib/fake_servicebus/actions/list_queues.rb +28 -0
- data/lib/fake_servicebus/actions/receive_message.rb +44 -0
- data/lib/fake_servicebus/actions/renew_lock_message.rb +19 -0
- data/lib/fake_servicebus/actions/send_message.rb +22 -0
- data/lib/fake_servicebus/actions/unlock_message.rb +19 -0
- data/lib/fake_servicebus/api.rb +71 -0
- data/lib/fake_servicebus/catch_errors.rb +19 -0
- data/lib/fake_servicebus/collection_view.rb +20 -0
- data/lib/fake_servicebus/daemonize.rb +30 -0
- data/lib/fake_servicebus/databases/file.rb +129 -0
- data/lib/fake_servicebus/databases/memory.rb +30 -0
- data/lib/fake_servicebus/error_response.rb +55 -0
- data/lib/fake_servicebus/error_responses.yml +32 -0
- data/lib/fake_servicebus/message.rb +59 -0
- data/lib/fake_servicebus/queue.rb +201 -0
- data/lib/fake_servicebus/queue_factory.rb +16 -0
- data/lib/fake_servicebus/queues.rb +72 -0
- data/lib/fake_servicebus/responder.rb +41 -0
- data/lib/fake_servicebus/server.rb +19 -0
- data/lib/fake_servicebus/show_output.rb +21 -0
- data/lib/fake_servicebus/test_integration.rb +122 -0
- data/lib/fake_servicebus/version.rb +3 -0
- data/lib/fake_servicebus/web_interface.rb +74 -0
- data/spec/acceptance/message_actions_spec.rb +452 -0
- data/spec/acceptance/queue_actions_spec.rb +82 -0
- data/spec/integration_spec_helper.rb +23 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/unit/api_spec.rb +76 -0
- data/spec/unit/catch_errors_spec.rb +43 -0
- data/spec/unit/collection_view_spec.rb +41 -0
- data/spec/unit/error_response_spec.rb +65 -0
- data/spec/unit/message_spec.rb +76 -0
- data/spec/unit/queue_factory_spec.rb +13 -0
- data/spec/unit/queue_spec.rb +204 -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
- data/spec/unit/web_interface_spec.rb +15 -0
- metadata +266 -0
@@ -0,0 +1,82 @@
|
|
1
|
+
require "integration_spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe "Actions for Queues", :sqs do
|
4
|
+
|
5
|
+
let(:sqs) { Aws::SQS::Client.new }
|
6
|
+
before do
|
7
|
+
sqs.config.endpoint = $fake_sqs.uri
|
8
|
+
end
|
9
|
+
|
10
|
+
specify "CreateQueue" do
|
11
|
+
response = sqs.create_queue(queue_name: "test-create-queue")
|
12
|
+
expect(response.queue_url).to eq "http://0.0.0.0:4568/test-create-queue"
|
13
|
+
response2 = sqs.get_queue_attributes(queue_url: response.queue_url)
|
14
|
+
expect(response2.attributes.fetch("QueueArn")).to match %r"arn:aws:sqs:us-east-1:.+:test-create-queue"
|
15
|
+
end
|
16
|
+
|
17
|
+
specify "GetQueueUrl" do
|
18
|
+
sqs.create_queue(queue_name: "test-get-queue-url")
|
19
|
+
response = sqs.get_queue_url(queue_name: "test-get-queue-url")
|
20
|
+
expect(response.queue_url).to eq "http://0.0.0.0:4568/test-get-queue-url"
|
21
|
+
end
|
22
|
+
|
23
|
+
specify "ListQueues" do
|
24
|
+
sqs.create_queue(queue_name: "test-list-1")
|
25
|
+
sqs.create_queue(queue_name: "test-list-2")
|
26
|
+
expect(sqs.list_queues.queue_urls).to eq [
|
27
|
+
"http://0.0.0.0:4568/test-list-1",
|
28
|
+
"http://0.0.0.0:4568/test-list-2"
|
29
|
+
]
|
30
|
+
end
|
31
|
+
|
32
|
+
specify "ListQueues with prefix" do
|
33
|
+
sqs.create_queue(queue_name: "test-list-1")
|
34
|
+
sqs.create_queue(queue_name: "test-list-2")
|
35
|
+
sqs.create_queue(queue_name: "other-list-3")
|
36
|
+
expect(sqs.list_queues(queue_name_prefix: "test").queue_urls).to eq [
|
37
|
+
"http://0.0.0.0:4568/test-list-1",
|
38
|
+
"http://0.0.0.0:4568/test-list-2",
|
39
|
+
]
|
40
|
+
end
|
41
|
+
|
42
|
+
specify "ListDeadLetterSourceQueues" do
|
43
|
+
dlq_queue_url = sqs.create_queue(queue_name: "source-list-DLQ").queue_url
|
44
|
+
dlq_arn = sqs.get_queue_attributes(queue_url: dlq_queue_url).attributes.fetch("QueueArn")
|
45
|
+
source_queue_urls = []
|
46
|
+
2.times do |time|
|
47
|
+
queue_url = sqs.create_queue(queue_name: "source-list-#{time}").queue_url
|
48
|
+
sqs.set_queue_attributes(queue_url: queue_url,
|
49
|
+
attributes: {
|
50
|
+
"RedrivePolicy" => "{\"deadLetterTargetArn\":\"#{dlq_arn}\",\"maxReceiveCount\":10}"
|
51
|
+
}
|
52
|
+
)
|
53
|
+
source_queue_urls << queue_url
|
54
|
+
end
|
55
|
+
expect(sqs.list_dead_letter_source_queues(queue_url: dlq_queue_url).queue_urls).to eq source_queue_urls
|
56
|
+
end
|
57
|
+
|
58
|
+
specify "DeleteQueue" do
|
59
|
+
url = sqs.create_queue(queue_name: "test-delete").queue_url
|
60
|
+
expect(sqs.list_queues.queue_urls.size).to eq 1
|
61
|
+
sqs.delete_queue(queue_url: url)
|
62
|
+
expect(sqs.list_queues.queue_urls.size).to eq 0
|
63
|
+
end
|
64
|
+
|
65
|
+
specify "SetQueueAttributes / GetQueueAttributes" do
|
66
|
+
queue_url = sqs.create_queue(queue_name: "my-queue").queue_url
|
67
|
+
|
68
|
+
|
69
|
+
sqs.set_queue_attributes(
|
70
|
+
queue_url: queue_url,
|
71
|
+
attributes: {
|
72
|
+
"DelaySeconds" => "900"
|
73
|
+
}
|
74
|
+
)
|
75
|
+
|
76
|
+
response = sqs.get_queue_attributes(
|
77
|
+
queue_url: queue_url,
|
78
|
+
)
|
79
|
+
expect(response.attributes.fetch("DelaySeconds")).to eq "900"
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require "aws-sdk"
|
2
|
+
require "fake_sqs/test_integration"
|
3
|
+
|
4
|
+
Aws.config.update(
|
5
|
+
region: "us-east-1",
|
6
|
+
credentials: Aws::Credentials.new("fake", "fake"),
|
7
|
+
)
|
8
|
+
|
9
|
+
db = ENV["SQS_DATABASE"] || ":memory:"
|
10
|
+
puts "\n\e[34mRunning specs with database \e[33m#{db}\e[0m"
|
11
|
+
|
12
|
+
$fake_sqs = FakeSQS::TestIntegration.new(
|
13
|
+
database: db,
|
14
|
+
sqs_endpoint: "0.0.0.0",
|
15
|
+
sqs_port: 4568,
|
16
|
+
start_timeout: 2,
|
17
|
+
)
|
18
|
+
|
19
|
+
RSpec.configure do |config|
|
20
|
+
config.before(:each, :sqs) { $fake_sqs.start }
|
21
|
+
config.before(:each, :sqs) { $fake_sqs.reset }
|
22
|
+
config.after(:suite) { $fake_sqs.stop }
|
23
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'fake_sqs/api'
|
2
|
+
|
3
|
+
class FakeSQS::Actions::ImmediateAction
|
4
|
+
|
5
|
+
def initialize(options)
|
6
|
+
@options = options
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(params)
|
10
|
+
{ :options => @options, :params => params }
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
class FakeSQS::Actions::PollingAction
|
16
|
+
|
17
|
+
def initialize(options)
|
18
|
+
@options = options
|
19
|
+
@call_count = 0
|
20
|
+
end
|
21
|
+
|
22
|
+
def call(params)
|
23
|
+
@call_count += 1
|
24
|
+
end
|
25
|
+
|
26
|
+
def satisfied?
|
27
|
+
@call_count >= 3
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
RSpec.describe FakeSQS::API do
|
32
|
+
|
33
|
+
it "delegates actions to classes" do
|
34
|
+
queues = double :queues
|
35
|
+
allow(queues).to receive(:transaction).and_yield
|
36
|
+
api = FakeSQS::API.new(:queues => queues)
|
37
|
+
|
38
|
+
response = api.call("ImmediateAction", {}, {:foo => "bar"})
|
39
|
+
|
40
|
+
expect(response[:options]).to eq :queues => queues, :request => {}
|
41
|
+
expect(response[:params]).to eq :foo => "bar"
|
42
|
+
end
|
43
|
+
|
44
|
+
it "attempts a polling action until it's satisfied" do
|
45
|
+
queues = double :queues
|
46
|
+
allow(queues).to receive(:transaction).and_yield
|
47
|
+
api = FakeSQS::API.new(:queues => queues)
|
48
|
+
|
49
|
+
call_count = api.call("PollingAction", {}, {})
|
50
|
+
expect(call_count).to eq 3
|
51
|
+
end
|
52
|
+
|
53
|
+
it "raises InvalidAction for unknown actions" do
|
54
|
+
api = FakeSQS::API.new(:queues => [])
|
55
|
+
|
56
|
+
expect {
|
57
|
+
api.call("SomethingDifferentAndUnknown", {:foo => "bar"})
|
58
|
+
}.to raise_error(FakeSQS::InvalidAction)
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
it "resets queues" do
|
63
|
+
queues = double :queues
|
64
|
+
api = FakeSQS::API.new(:queues => queues)
|
65
|
+
expect(queues).to receive(:reset)
|
66
|
+
api.reset
|
67
|
+
end
|
68
|
+
|
69
|
+
it "expires messages in queues" do
|
70
|
+
queues = double :queues
|
71
|
+
api = FakeSQS::API.new(:queues => queues)
|
72
|
+
expect(queues).to receive(:expire)
|
73
|
+
api.expire
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'fake_sqs/catch_errors'
|
2
|
+
|
3
|
+
RSpec.describe FakeSQS::CatchErrors do
|
4
|
+
|
5
|
+
let(:app) { double :app }
|
6
|
+
let(:error_response) { double :error_response, :status => 500, :body => "X" }
|
7
|
+
let(:response) { double :response, :new => error_response }
|
8
|
+
subject(:catch_errors) { FakeSQS::CatchErrors.new(app, response: response) }
|
9
|
+
|
10
|
+
context "when the app behaves normally" do
|
11
|
+
|
12
|
+
let(:normal_response) { double :normal_response }
|
13
|
+
before { allow(app).to receive(:call).and_return(normal_response) }
|
14
|
+
|
15
|
+
it "doesn't modify normal responses" do
|
16
|
+
expect(catch_errors.call({})).to eq normal_response
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
context "when the app raises an exception" do
|
22
|
+
|
23
|
+
let(:error) { RuntimeError.new("it went wrong") }
|
24
|
+
before { allow(app).to receive(:call).and_raise(error) }
|
25
|
+
|
26
|
+
it "cathes and processes errors" do
|
27
|
+
expect(response).to receive(:new).with(error)
|
28
|
+
catch_errors.call({})
|
29
|
+
end
|
30
|
+
|
31
|
+
it "sets the status determined by the error response" do
|
32
|
+
allow(error_response).to receive(:status).and_return(123)
|
33
|
+
expect(catch_errors.call({}).fetch(0)).to eq 123
|
34
|
+
end
|
35
|
+
|
36
|
+
it "set the body determined by the error response" do
|
37
|
+
allow(error_response).to receive(:body).and_return("foobar")
|
38
|
+
expect(catch_errors.call({}).fetch(2)).to eq ["foobar"]
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'fake_sqs/collection_view'
|
2
|
+
|
3
|
+
RSpec.describe FakeSQS::CollectionView do
|
4
|
+
|
5
|
+
def wrap(collection)
|
6
|
+
FakeSQS::CollectionView.new(collection)
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'should correctly wrap an array' do
|
10
|
+
array = %w{one two three four}
|
11
|
+
view = wrap(array)
|
12
|
+
expect(view[0]).to eq 'one'
|
13
|
+
expect(view[1]).to eq 'two'
|
14
|
+
expect(view[2]).to eq 'three'
|
15
|
+
expect(view[3]).to eq 'four'
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should correctly wrap a hash' do
|
19
|
+
hash = { :one => 1, :two => 2, :three => 3 }
|
20
|
+
view = wrap(hash)
|
21
|
+
expect(view[:one]).to eq 1
|
22
|
+
expect(view[:two]).to eq 2
|
23
|
+
expect(view[:three]).to eq 3
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should respond to empty correctly' do
|
27
|
+
expect(wrap([])).to be_empty
|
28
|
+
expect(wrap({'one' => 1})).to_not be_empty
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should be enumerable' do
|
32
|
+
result = wrap([1, 2, 3]).map { |i| i * i }
|
33
|
+
expect(result).to eq [1, 4, 9]
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should respond to size/length' do
|
37
|
+
expect(wrap([1, 2, 3]).size).to eq 3
|
38
|
+
expect(wrap([]).size).to eq 0
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'fake_sqs/error_response'
|
2
|
+
require 'active_support/core_ext/hash'
|
3
|
+
require 'verbose_hash_fetch'
|
4
|
+
|
5
|
+
RSpec.describe FakeSQS::ErrorResponse do
|
6
|
+
|
7
|
+
module FakeSQS
|
8
|
+
MissingCredentials = Class.new(RuntimeError)
|
9
|
+
end
|
10
|
+
ErrorUnknownToSQS = Class.new(RuntimeError)
|
11
|
+
|
12
|
+
describe "#status" do
|
13
|
+
|
14
|
+
it "picks the right error status" do
|
15
|
+
error = FakeSQS::MissingCredentials.new("message")
|
16
|
+
response = FakeSQS::ErrorResponse.new(error)
|
17
|
+
expect(response.status).to eq 401
|
18
|
+
end
|
19
|
+
|
20
|
+
it "uses 400 as default status" do
|
21
|
+
error = ErrorUnknownToSQS.new("message")
|
22
|
+
response = FakeSQS::ErrorResponse.new(error)
|
23
|
+
expect(response.status).to eq 500
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "#body" do
|
29
|
+
|
30
|
+
let(:error) { FakeSQS::MissingCredentials.new("the message") }
|
31
|
+
let(:response) { FakeSQS::ErrorResponse.new(error) }
|
32
|
+
let(:data) { Hash.from_xml(response.body) }
|
33
|
+
|
34
|
+
it "uses the error class name as error code" do
|
35
|
+
expect(data.fetch("ErrorResponse").fetch("Error").fetch("Code")).to eq "MissingCredentials"
|
36
|
+
end
|
37
|
+
|
38
|
+
it "uses InternalError as code for unknown errors" do
|
39
|
+
error = ErrorUnknownToSQS.new("the message")
|
40
|
+
response = FakeSQS::ErrorResponse.new(error)
|
41
|
+
data = Hash.from_xml(response.body)
|
42
|
+
expect(data.fetch("ErrorResponse").fetch("Error").fetch("Code")).to eq "InternalError"
|
43
|
+
end
|
44
|
+
|
45
|
+
it "uses the to_s of the error as message" do
|
46
|
+
expect(data.fetch("ErrorResponse").fetch("Error").fetch("Message")).to eq "the message"
|
47
|
+
end
|
48
|
+
|
49
|
+
it "has a request id" do
|
50
|
+
expect(data.fetch("ErrorResponse").fetch("RequestId").size).to eq 36
|
51
|
+
end
|
52
|
+
|
53
|
+
it "uses Sender as type for 4xx responses" do
|
54
|
+
allow(response).to receive(:status).and_return(400)
|
55
|
+
expect(data.fetch("ErrorResponse").fetch("Error").fetch("Type")).to eq "Sender"
|
56
|
+
end
|
57
|
+
|
58
|
+
it "uses Receiver as type for 5xx responses" do
|
59
|
+
allow(response).to receive(:status).and_return(500)
|
60
|
+
expect(data.fetch("ErrorResponse").fetch("Error").fetch("Type")).to eq "Receiver"
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'fake_sqs/message'
|
2
|
+
|
3
|
+
RSpec.describe FakeSQS::Message do
|
4
|
+
|
5
|
+
describe "#body" do
|
6
|
+
|
7
|
+
it "is extracted from the MessageBody" do
|
8
|
+
message = create_message("MessageBody" => "abc")
|
9
|
+
expect(message.body).to eq "abc"
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "#md5" do
|
15
|
+
|
16
|
+
it "is calculated from body" do
|
17
|
+
message = create_message("MessageBody" => "abc")
|
18
|
+
expect(message.md5).to eq "900150983cd24fb0d6963f7d28e17f72"
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "#id" do
|
24
|
+
|
25
|
+
it "is generated" do
|
26
|
+
message = create_message
|
27
|
+
expect(message.id.size).to eq 36
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "#delay_seconds" do
|
33
|
+
|
34
|
+
it "is generated" do
|
35
|
+
message = create_message({"DelaySeconds" => 10})
|
36
|
+
expect(message.delay_seconds).to eq 10
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
describe 'visibility_timeout' do
|
42
|
+
|
43
|
+
let :message do
|
44
|
+
create_message
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should default to nil' do
|
48
|
+
expect(message.visibility_timeout).to eq nil
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'should be expired when it is nil' do
|
52
|
+
expect(message).to be_expired
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should be expired if set to a previous time' do
|
56
|
+
message.visibility_timeout = Time.now - 1
|
57
|
+
expect(message).to be_expired
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'should not be expired at a future date' do
|
61
|
+
message.visibility_timeout = Time.now + 1
|
62
|
+
expect(message).not_to be_expired
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'should not be expired when set to expire at a future date' do
|
66
|
+
message.expire_at(5)
|
67
|
+
expect(message.visibility_timeout).to be >=(Time.now + 4)
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
def create_message(options = {})
|
73
|
+
FakeSQS::Message.new({"MessageBody" => "test"}.merge(options))
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'fake_sqs/queue_factory'
|
2
|
+
|
3
|
+
RSpec.describe FakeSQS::QueueFactory do
|
4
|
+
|
5
|
+
it "builds queues with a message factory" do
|
6
|
+
message_factory = double :message_factory
|
7
|
+
queue = double :queue
|
8
|
+
queue_factory = FakeSQS::QueueFactory.new(message_factory: message_factory, queue: queue)
|
9
|
+
expect(queue).to receive(:new).with(message_factory: message_factory, name: "Foo")
|
10
|
+
queue_factory.new(name: "Foo")
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
@@ -0,0 +1,204 @@
|
|
1
|
+
require 'fake_sqs/queue'
|
2
|
+
require 'fake_sqs/message'
|
3
|
+
|
4
|
+
RSpec.describe FakeSQS::Queue do
|
5
|
+
|
6
|
+
class MessageFactory
|
7
|
+
def new(options = {})
|
8
|
+
FakeSQS::Message.new({'MessageBody' => 'sample-body'}.merge(options))
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:message_factory) { MessageFactory.new }
|
13
|
+
subject(:queue) { FakeSQS::Queue.new(:message_factory => message_factory, "QueueName" => "test-queue") }
|
14
|
+
|
15
|
+
describe "#send_message" do
|
16
|
+
|
17
|
+
it "adds a message" do
|
18
|
+
expect(queue.messages.size).to eq 0
|
19
|
+
send_message
|
20
|
+
expect(queue.messages.size).to eq 1
|
21
|
+
end
|
22
|
+
|
23
|
+
it "returns the message" do
|
24
|
+
message = double.as_null_object
|
25
|
+
allow(message_factory).to receive(:new).and_return(message)
|
26
|
+
expect(send_message).to eq message
|
27
|
+
end
|
28
|
+
|
29
|
+
it "uses the message factory" do
|
30
|
+
options = { "MessageBody" => "abc" }
|
31
|
+
expect(message_factory).to receive(:new).with(options)
|
32
|
+
send_message(options)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should set the message's SentTimestamp attribute" do
|
36
|
+
expect(send_message.attributes["SentTimestamp"]).to eq (Time.now.to_i * 1000)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should set the SenderId of the sender" do
|
40
|
+
sender_id = send_message.attributes["SenderId"]
|
41
|
+
expect(sender_id).to be_a String
|
42
|
+
expect(sender_id.length).to eq 21
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "#receive_message" do
|
47
|
+
|
48
|
+
it "gets the message" do
|
49
|
+
sent = send_message
|
50
|
+
received = receive_message
|
51
|
+
expect(received.values.first).to eq sent
|
52
|
+
end
|
53
|
+
|
54
|
+
it "gets the message with 'DelaySeconds' option" do
|
55
|
+
delay_seconds = 3
|
56
|
+
sent = send_message({ "DelaySeconds" => delay_seconds })
|
57
|
+
received = receive_message
|
58
|
+
expect(received.values.first).to be_nil
|
59
|
+
|
60
|
+
allow(Time).to receive(:now).and_return(Time.now + delay_seconds)
|
61
|
+
received = receive_message
|
62
|
+
expect(received.values.first).to eq sent
|
63
|
+
end
|
64
|
+
|
65
|
+
it "gets you a random message" do
|
66
|
+
indexes = { :first => 0, :second => 0 }
|
67
|
+
sample_group = 1_000
|
68
|
+
half_sample_group = sample_group / 2
|
69
|
+
ten_percent = half_sample_group / 0.1
|
70
|
+
|
71
|
+
sample_group.times do
|
72
|
+
sent_first = send_message
|
73
|
+
_ = send_message
|
74
|
+
message = receive_message.values.first
|
75
|
+
if message == sent_first
|
76
|
+
indexes[:first] += 1
|
77
|
+
else
|
78
|
+
indexes[:second] += 1
|
79
|
+
end
|
80
|
+
reset_queue
|
81
|
+
end
|
82
|
+
|
83
|
+
expect(indexes[:first] + indexes[:second]).to eq sample_group
|
84
|
+
|
85
|
+
expect(indexes[:first]).to be_within(ten_percent).of(half_sample_group)
|
86
|
+
expect(indexes[:second]).to be_within(ten_percent).of(half_sample_group)
|
87
|
+
end
|
88
|
+
|
89
|
+
it "cannot get received messages" do
|
90
|
+
sample_group = 1_000
|
91
|
+
|
92
|
+
sample_group.times do
|
93
|
+
sent_first = send_message
|
94
|
+
sent_second = send_message
|
95
|
+
received_first = receive_message.values.first
|
96
|
+
|
97
|
+
if received_first == sent_first
|
98
|
+
expect(receive_message.values.first).to eq sent_second
|
99
|
+
else
|
100
|
+
expect(receive_message.values.first).to eq sent_first
|
101
|
+
end
|
102
|
+
reset_queue
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
it "keeps track of sent messages" do
|
107
|
+
|
108
|
+
send_message
|
109
|
+
|
110
|
+
expect(queue.messages_in_flight.size).to eq 0
|
111
|
+
expect(queue.attributes["ApproximateNumberOfMessagesNotVisible"]).to eq 0
|
112
|
+
expect(queue.attributes["ApproximateNumberOfMessages"]).to eq 1
|
113
|
+
|
114
|
+
receive_message
|
115
|
+
|
116
|
+
expect(queue.messages_in_flight.size).to eq 1
|
117
|
+
expect(queue.attributes["ApproximateNumberOfMessagesNotVisible"]).to eq 1
|
118
|
+
expect(queue.attributes["ApproximateNumberOfMessages"]).to eq 0
|
119
|
+
end
|
120
|
+
|
121
|
+
it "gets multiple message" do
|
122
|
+
sent_first = send_message
|
123
|
+
sent_second = send_message
|
124
|
+
messages = receive_message("MaxNumberOfMessages" => "2")
|
125
|
+
expect(messages.size).to eq 2
|
126
|
+
expect(messages.values).to match_array [ sent_first, sent_second ]
|
127
|
+
end
|
128
|
+
|
129
|
+
it "won't accept more than 10 message" do
|
130
|
+
expect {
|
131
|
+
receive_message("MaxNumberOfMessages" => "11")
|
132
|
+
}.to raise_error(FakeSQS::ReadCountOutOfRange, "11")
|
133
|
+
end
|
134
|
+
|
135
|
+
it "won't error on empty queues" do
|
136
|
+
expect(receive_message).to eq({})
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should increment the ApproximateReceiveCount" do
|
140
|
+
sent_message = send_message
|
141
|
+
expect(sent_message.attributes["ApproximateReceiveCount"]).to eq 0
|
142
|
+
queue.change_message_visibility(receive_message.keys.first, 0)
|
143
|
+
expect(sent_message.attributes["ApproximateReceiveCount"]).to eq 1
|
144
|
+
receive_message
|
145
|
+
expect(sent_message.attributes["ApproximateReceiveCount"]).to eq 2
|
146
|
+
end
|
147
|
+
|
148
|
+
it "should set the ApproximateFirstReceiveTimestamp only when the message is first received" do
|
149
|
+
sent_message = send_message
|
150
|
+
expect(sent_message.attributes["ApproximateFirstReceiveTimestamp"]).to eq nil
|
151
|
+
receive_time = (Time.now.to_i * 1000)
|
152
|
+
queue.change_message_visibility(receive_message.keys.first, 0)
|
153
|
+
expect(sent_message.attributes["ApproximateFirstReceiveTimestamp"]).to eq receive_time
|
154
|
+
sleep 1
|
155
|
+
receive_message
|
156
|
+
expect(sent_message.attributes["ApproximateFirstReceiveTimestamp"]).to eq receive_time
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
describe "#delete_message" do
|
161
|
+
|
162
|
+
it "deletes by the receipt" do
|
163
|
+
send_message
|
164
|
+
receipt = receive_message.keys.first
|
165
|
+
|
166
|
+
expect(queue.messages_in_flight.size).to eq 1
|
167
|
+
queue.delete_message(receipt)
|
168
|
+
expect(queue.messages_in_flight.size).to eq 0
|
169
|
+
expect(queue.messages.size).to eq 0
|
170
|
+
end
|
171
|
+
|
172
|
+
it "won't raise if the receipt is unknown" do
|
173
|
+
queue.delete_message("abc")
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
177
|
+
|
178
|
+
describe "#add_queue_attributes" do
|
179
|
+
|
180
|
+
it "adds to it's queue attributes" do
|
181
|
+
queue.add_queue_attributes("foo" => "bar")
|
182
|
+
expect(queue.attributes).to eq(
|
183
|
+
"foo" => "bar",
|
184
|
+
"QueueArn" => queue.arn,
|
185
|
+
"ApproximateNumberOfMessages" => 0,
|
186
|
+
"ApproximateNumberOfMessagesNotVisible" => 0
|
187
|
+
)
|
188
|
+
end
|
189
|
+
|
190
|
+
end
|
191
|
+
|
192
|
+
def send_message(options = {})
|
193
|
+
queue.send_message(options)
|
194
|
+
end
|
195
|
+
|
196
|
+
def receive_message(options = {})
|
197
|
+
queue.receive_message(options)
|
198
|
+
end
|
199
|
+
|
200
|
+
def reset_queue
|
201
|
+
queue.reset
|
202
|
+
end
|
203
|
+
|
204
|
+
end
|