message-driver 0.1.0 → 0.2.0.rc1
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 +1 -0
- data/.travis.yml +18 -7
- data/CHANGELOG.md +12 -2
- data/Gemfile +17 -0
- data/Guardfile +8 -4
- data/README.md +14 -5
- data/Rakefile +44 -11
- data/examples/basic_producer_and_consumer/Gemfile +5 -0
- data/examples/basic_producer_and_consumer/common.rb +17 -0
- data/examples/basic_producer_and_consumer/consumer.rb +24 -0
- data/examples/basic_producer_and_consumer/producer.rb +33 -0
- data/features/.nav +8 -0
- data/features/CHANGELOG.md +12 -2
- data/features/amqp_specific_features/binding_amqp_destinations.feature +7 -7
- data/features/amqp_specific_features/declaring_amqp_exchanges.feature +3 -3
- data/features/amqp_specific_features/nack_redelivered_messages.feature +92 -0
- data/features/amqp_specific_features/requeueing_on_nack.feature +44 -0
- data/features/amqp_specific_features/server_named_destinations.feature +5 -5
- data/features/client_acks.feature +92 -0
- data/features/destination_metadata.feature +9 -11
- data/features/dynamic_destinations.feature +7 -7
- data/features/error_handling.feature +11 -9
- data/features/logging.feature +14 -0
- data/features/message_consumers/auto_ack_consumers.feature +79 -0
- data/features/message_consumers/manual_ack_consumers.feature +95 -0
- data/features/message_consumers/transactional_ack_consumers.feature +77 -0
- data/features/message_consumers.feature +54 -0
- data/features/publishing_a_message.feature +6 -10
- data/features/publishing_with_transactions.feature +10 -14
- data/features/rabbitmq_specific_features/dead_letter_queueing.feature +116 -0
- data/features/step_definitions/dynamic_destinations_steps.rb +3 -3
- data/features/step_definitions/error_handling_steps.rb +4 -2
- data/features/step_definitions/logging_steps.rb +28 -0
- data/features/step_definitions/message_consumers_steps.rb +29 -0
- data/features/step_definitions/steps.rb +60 -9
- data/features/support/broker_config_helper.rb +19 -0
- data/features/support/env.rb +1 -0
- data/features/support/firewall_helper.rb +8 -11
- data/features/support/message_table_matcher.rb +21 -5
- data/features/support/test_runner.rb +39 -16
- data/lib/message_driver/adapters/base.rb +51 -4
- data/lib/message_driver/adapters/bunny_adapter.rb +251 -127
- data/lib/message_driver/adapters/in_memory_adapter.rb +97 -18
- data/lib/message_driver/adapters/stomp_adapter.rb +127 -0
- data/lib/message_driver/broker.rb +23 -24
- data/lib/message_driver/client.rb +157 -0
- data/lib/message_driver/destination.rb +7 -4
- data/lib/message_driver/errors.rb +27 -0
- data/lib/message_driver/logging.rb +11 -0
- data/lib/message_driver/message.rb +8 -0
- data/lib/message_driver/subscription.rb +18 -0
- data/lib/message_driver/vendor/.document +0 -0
- data/lib/message_driver/vendor/nesty/nested_error.rb +26 -0
- data/lib/message_driver/vendor/nesty.rb +1 -0
- data/lib/message_driver/version.rb +1 -1
- data/lib/message_driver.rb +4 -2
- data/message-driver.gemspec +4 -4
- data/spec/integration/{amqp_integration_spec.rb → bunny/amqp_integration_spec.rb} +29 -28
- data/spec/integration/bunny/bunny_adapter_spec.rb +339 -0
- data/spec/integration/in_memory/in_memory_adapter_spec.rb +126 -0
- data/spec/integration/stomp/stomp_adapter_spec.rb +142 -0
- data/spec/spec_helper.rb +5 -2
- data/spec/support/shared/adapter_examples.rb +17 -0
- data/spec/support/shared/client_ack_examples.rb +18 -0
- data/spec/support/shared/context_examples.rb +14 -0
- data/spec/support/shared/destination_examples.rb +4 -5
- data/spec/support/shared/subscription_examples.rb +146 -0
- data/spec/support/shared/transaction_examples.rb +43 -0
- data/spec/support/utils.rb +14 -0
- data/spec/units/message_driver/adapters/base_spec.rb +38 -19
- data/spec/units/message_driver/broker_spec.rb +71 -18
- data/spec/units/message_driver/client_spec.rb +375 -0
- data/spec/units/message_driver/destination_spec.rb +9 -0
- data/spec/units/message_driver/logging_spec.rb +18 -0
- data/spec/units/message_driver/message_spec.rb +36 -0
- data/spec/units/message_driver/subscription_spec.rb +24 -0
- data/test_lib/broker_config.rb +50 -20
- metadata +83 -45
- data/.rbenv-version +0 -1
- data/lib/message_driver/exceptions.rb +0 -18
- data/lib/message_driver/message_publisher.rb +0 -15
- data/spec/integration/message_driver/adapters/bunny_adapter_spec.rb +0 -301
- data/spec/units/message_driver/adapters/in_memory_adapter_spec.rb +0 -43
- data/spec/units/message_driver/message_publisher_spec.rb +0 -65
@@ -0,0 +1,142 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'message_driver/adapters/stomp_adapter'
|
4
|
+
|
5
|
+
module MessageDriver::Adapters
|
6
|
+
describe StompAdapter, :stomp, type: :integration do
|
7
|
+
|
8
|
+
let(:valid_connection_attrs) { BrokerConfig.config }
|
9
|
+
|
10
|
+
describe "#initialize" do
|
11
|
+
let(:connection_attrs) { valid_connection_attrs }
|
12
|
+
|
13
|
+
context "differing stomp versions" do
|
14
|
+
shared_examples "raises a stomp error" do
|
15
|
+
it "raises an error" do
|
16
|
+
stub_const("Stomp::Version::STRING", version)
|
17
|
+
expect {
|
18
|
+
described_class.new(connection_attrs)
|
19
|
+
}.to raise_error MessageDriver::Error, "stomp 1.2.10 or a later version of the 1.2.x series is required for the stomp adapter"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
shared_examples "doesn't raise a stomp error" do
|
23
|
+
it "doesn't raise an an error" do
|
24
|
+
stub_const("Stomp::Version::STRING", version)
|
25
|
+
adapter = nil
|
26
|
+
expect {
|
27
|
+
adapter = described_class.new(connection_attrs)
|
28
|
+
}.to_not raise_error
|
29
|
+
end
|
30
|
+
end
|
31
|
+
%w(1.1.0 1.2.9 1.3.0).each do |v|
|
32
|
+
context "stomp version #{v}" do
|
33
|
+
let(:version) { v }
|
34
|
+
include_examples "raises a stomp error"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
%w(1.2.10 1.2.11).each do |v|
|
38
|
+
context "stomp version #{v}" do
|
39
|
+
let(:version) { v }
|
40
|
+
include_examples "doesn't raise a stomp error"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "the resulting config" do
|
46
|
+
let(:connection_attrs) { {hosts: [{host: "my_host"}]} }
|
47
|
+
subject(:config) { described_class.new(connection_attrs).config }
|
48
|
+
|
49
|
+
its([:connect_headers]) { should eq(:"accept-version" => "1.1,1.2") }
|
50
|
+
its([:hosts]) { should eq(connection_attrs[:hosts]) }
|
51
|
+
|
52
|
+
context "when vhost is specified" do
|
53
|
+
let(:connection_attrs) { {hosts: [{host: "my_host"}], vhost: "my_vhost"} }
|
54
|
+
|
55
|
+
it { should_not have_key(:vhost) }
|
56
|
+
its([:connect_headers]) { should eq(:"accept-version" => "1.1,1.2", :"host" => "my_vhost") }
|
57
|
+
end
|
58
|
+
|
59
|
+
context "when there are things in the connect_headers" do
|
60
|
+
let(:connection_attrs) { {hosts: [{host: "my_host"}], connect_headers: {"foo" => "bar"}} }
|
61
|
+
|
62
|
+
its([:connect_headers]) { should eq(:"accept-version" => "1.1,1.2", "foo" => "bar") }
|
63
|
+
|
64
|
+
context "and accept-version is one of the parameters" do
|
65
|
+
let(:connection_attrs) { {hosts: [{host: "my_host"}], connect_headers: {"foo" => "bar", :"accept-version" => "foo!"}} }
|
66
|
+
|
67
|
+
its([:connect_headers]) { should eq(:"accept-version" => "1.1,1.2", "foo" => "bar") }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
shared_context "a connected stomp adapter" do
|
74
|
+
subject(:adapter) { described_class.new(valid_connection_attrs) }
|
75
|
+
|
76
|
+
before do
|
77
|
+
MessageDriver::Broker.configure(adapter: adapter)
|
78
|
+
end
|
79
|
+
|
80
|
+
after do
|
81
|
+
adapter.stop
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
it_behaves_like "an adapter" do
|
86
|
+
include_context "a connected stomp adapter"
|
87
|
+
end
|
88
|
+
|
89
|
+
describe "#new_context" do
|
90
|
+
include_context "a connected stomp adapter"
|
91
|
+
|
92
|
+
it "returns a StompAdapter::StompContext" do
|
93
|
+
expect(adapter.new_context).to be_a StompAdapter::StompContext
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe StompAdapter::StompContext do
|
98
|
+
include_context "a connected stomp adapter"
|
99
|
+
subject(:adapter_context) { adapter.new_context }
|
100
|
+
|
101
|
+
it_behaves_like "an adapter context"
|
102
|
+
it_behaves_like "transactions are not supported"
|
103
|
+
it_behaves_like "client acks are not supported"
|
104
|
+
it_behaves_like "subscriptions are not supported"
|
105
|
+
|
106
|
+
describe "#create_destination" do
|
107
|
+
|
108
|
+
context "the resulting destination" do
|
109
|
+
let(:dest_name) { "/queue/stomp_destination_spec" }
|
110
|
+
subject(:destination) { adapter_context.create_destination(dest_name) }
|
111
|
+
|
112
|
+
it { should be_a StompAdapter::Destination }
|
113
|
+
|
114
|
+
it_behaves_like "a destination"
|
115
|
+
include_examples "doesn't support #message_count"
|
116
|
+
|
117
|
+
describe "pop_message" do
|
118
|
+
context "when there is a message on the queue" do
|
119
|
+
let(:body) { "Testing stomp pop_message" }
|
120
|
+
before do
|
121
|
+
destination.publish(body)
|
122
|
+
end
|
123
|
+
|
124
|
+
it "returns the message" do
|
125
|
+
msg = destination.pop_message
|
126
|
+
expect(msg).to be_a MessageDriver::Adapters::StompAdapter::Message
|
127
|
+
expect(msg.body).to eq(body)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
context "when the queue is empty" do
|
132
|
+
it "returns nil" do
|
133
|
+
msg = destination.pop_message
|
134
|
+
expect(msg).to be_nil
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -11,9 +11,12 @@ RSpec.configure do |c|
|
|
11
11
|
|
12
12
|
c.reporter.message("Acceptance Tests running with broker config: #{BrokerConfig.config}")
|
13
13
|
|
14
|
-
c.filter_run_excluding :
|
14
|
+
c.filter_run_excluding :no_ci if ENV['CI']=='true' && ENV['ADAPTER'] && ENV['ADAPTER'].start_with?('bunny')
|
15
15
|
if c.inclusion_filter[:all_adapters] == true
|
16
|
-
|
16
|
+
BrokerConfig.unconfigured_adapters.each do |a|
|
17
|
+
c.filter_run_excluding a
|
18
|
+
end
|
19
|
+
c.filter_run_including BrokerConfig.current_adapter
|
17
20
|
else
|
18
21
|
c.run_all_when_everything_filtered = true
|
19
22
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
shared_examples "an adapter" do
|
2
|
+
describe "#new_context" do
|
3
|
+
it "returns a MessageDriver::Adapters::ContextBase" do
|
4
|
+
expect(subject.new_context).to be_a MessageDriver::Adapters::ContextBase
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "#stop" do
|
9
|
+
it "invalidates all the adapter contexts" do
|
10
|
+
ctx1 = subject.new_context
|
11
|
+
ctx2 = subject.new_context
|
12
|
+
subject.stop
|
13
|
+
expect(ctx1).to_not be_valid
|
14
|
+
expect(ctx2).to_not be_valid
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
shared_examples "client acks are supported" do
|
2
|
+
describe "#supports_client_acks" do
|
3
|
+
it "returns true" do
|
4
|
+
expect(subject.supports_client_acks?).to eq(true)
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
it { should respond_to :ack_message }
|
9
|
+
it { should respond_to :nack_message }
|
10
|
+
end
|
11
|
+
|
12
|
+
shared_examples "client acks are not supported" do
|
13
|
+
describe "#supports_client_acks" do
|
14
|
+
it "returns false" do
|
15
|
+
expect(subject.supports_client_acks?).to eq(false)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
shared_examples "an adapter context" do
|
2
|
+
it { should be_a MessageDriver::Adapters::ContextBase }
|
3
|
+
|
4
|
+
it "is initially valid" do
|
5
|
+
should be_valid
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "#invalidate" do
|
9
|
+
it "causes the context to become invalid" do
|
10
|
+
subject.invalidate
|
11
|
+
expect(subject).to_not be_valid
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -9,12 +9,11 @@ shared_examples "a destination" do
|
|
9
9
|
end
|
10
10
|
|
11
11
|
context "the result" do
|
12
|
-
|
13
|
-
subject { message }
|
12
|
+
subject(:message) { destination.pop_message }
|
14
13
|
|
15
14
|
it { should be_a MessageDriver::Message::Base }
|
16
15
|
its(:body) { should eq(body) }
|
17
|
-
its(:headers) { should
|
16
|
+
its(:headers) { should include(headers) }
|
18
17
|
its(:properties) { should_not be_nil }
|
19
18
|
end
|
20
19
|
end
|
@@ -31,11 +30,11 @@ shared_examples "doesn't support #message_count" do
|
|
31
30
|
end
|
32
31
|
|
33
32
|
shared_examples "supports #message_count" do
|
34
|
-
|
35
|
-
it "reports it's message_count", :no_travis do
|
33
|
+
it "reports it's message_count" do
|
36
34
|
expect {
|
37
35
|
destination.publish("msg1")
|
38
36
|
destination.publish("msg2")
|
37
|
+
pause_if_needed
|
39
38
|
}.to change{destination.message_count}.by(2)
|
40
39
|
end
|
41
40
|
end
|
@@ -0,0 +1,146 @@
|
|
1
|
+
shared_examples "subscriptions are not supported" do
|
2
|
+
describe "#supports_subscriptions?" do
|
3
|
+
it "returns false" do
|
4
|
+
expect(subject.supports_subscriptions?).to eq(false)
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "#subscribe" do
|
9
|
+
it "raises an error" do
|
10
|
+
destination = double("destination")
|
11
|
+
consumer = lambda do |m| end
|
12
|
+
expect {
|
13
|
+
subject.subscribe(destination, &consumer)
|
14
|
+
}.to raise_error "#subscribe is not supported by #{subject.adapter.class}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
shared_examples "subscriptions are supported" do |subscription_type|
|
20
|
+
describe "#supports_subscriptions?" do
|
21
|
+
it "returns true" do
|
22
|
+
expect(subject.supports_subscriptions?).to eq(true)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
let(:destination) { adapter_context.create_destination("subscriptions_example_queue") }
|
27
|
+
|
28
|
+
let(:message1) { "message 1" }
|
29
|
+
let(:message2) { "message 2" }
|
30
|
+
let(:messages) { [] }
|
31
|
+
let(:consumer) do
|
32
|
+
lambda do |msg|
|
33
|
+
messages << msg
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "#subscribe" do
|
38
|
+
before do
|
39
|
+
if destination.respond_to? :purge
|
40
|
+
destination.purge
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
let(:subscription) { adapter_context.subscribe(destination, &consumer) }
|
45
|
+
after do
|
46
|
+
subscription.unsubscribe
|
47
|
+
end
|
48
|
+
|
49
|
+
it "returns a MessageDriver::Subscription::Base" do
|
50
|
+
expect(subscription).to be_a MessageDriver::Subscription::Base
|
51
|
+
end
|
52
|
+
|
53
|
+
context "the subscription" do
|
54
|
+
subject { subscription }
|
55
|
+
|
56
|
+
it { should be_a MessageDriver::Subscription::Base }
|
57
|
+
it { should be_a subscription_type }
|
58
|
+
its(:adapter) { should be adapter }
|
59
|
+
its(:destination) { should be destination }
|
60
|
+
its(:consumer) { should be consumer }
|
61
|
+
|
62
|
+
describe "#unsubscribe" do
|
63
|
+
it "makes it so messages don't go to the consumer any more" do
|
64
|
+
subscription.unsubscribe
|
65
|
+
expect {
|
66
|
+
destination.publish("should not be consumed")
|
67
|
+
}.to_not change{messages.size}
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context "when there are already messages in the destination" do
|
73
|
+
before do
|
74
|
+
destination.publish(message1)
|
75
|
+
destination.publish(message2)
|
76
|
+
end
|
77
|
+
|
78
|
+
it "plays the messages into the consumer" do
|
79
|
+
expect {
|
80
|
+
subscription
|
81
|
+
pause_if_needed
|
82
|
+
}.to change{messages.size}.from(0).to(2)
|
83
|
+
bodies = messages.map(&:body)
|
84
|
+
expect(bodies).to include(message1)
|
85
|
+
expect(bodies).to include(message2)
|
86
|
+
end
|
87
|
+
|
88
|
+
it "removes the messages from the queue" do
|
89
|
+
pause_if_needed
|
90
|
+
expect {
|
91
|
+
subscription
|
92
|
+
pause_if_needed
|
93
|
+
}.to change{destination.message_count}.from(2).to(0)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context "when a message is published to the destination" do
|
98
|
+
before do
|
99
|
+
subscription
|
100
|
+
end
|
101
|
+
|
102
|
+
it "consumers the message into the consumer instead of putting them on the queue" do
|
103
|
+
expect {
|
104
|
+
expect {
|
105
|
+
subject.publish(destination, message1)
|
106
|
+
pause_if_needed
|
107
|
+
}.to change{messages.length}.from(0).to(1)
|
108
|
+
}.to_not change{destination.message_count}
|
109
|
+
expect(messages[0].body).to eq(message1)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
context "when the consumer raises an error" do
|
114
|
+
let(:error) { RuntimeError.new("oh nos!") }
|
115
|
+
let(:consumer) do
|
116
|
+
lambda do |msg|
|
117
|
+
raise error
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
before do
|
122
|
+
destination.publish(message1)
|
123
|
+
destination.publish(message2)
|
124
|
+
end
|
125
|
+
|
126
|
+
it "keeps processing the messages" do
|
127
|
+
pause_if_needed
|
128
|
+
expect {
|
129
|
+
subscription
|
130
|
+
pause_if_needed
|
131
|
+
}.to change{destination.message_count}.from(2).to(0)
|
132
|
+
end
|
133
|
+
|
134
|
+
context "an error_handler is provided" do
|
135
|
+
let(:error_handler) { double(:error_handler, call: nil) }
|
136
|
+
let(:subscription) { adapter_context.subscribe(destination, error_handler: error_handler, &consumer) }
|
137
|
+
|
138
|
+
it "passes the errors and the messages to the error handler" do
|
139
|
+
subscription
|
140
|
+
pause_if_needed
|
141
|
+
expect(error_handler).to have_received(:call).with(error, kind_of(MessageDriver::Message::Base)).at_least(2).times
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
shared_examples "transactions are not supported" do
|
2
|
+
describe "#supports_transactions?" do
|
3
|
+
it "returns false" do
|
4
|
+
expect(subject.supports_transactions?).to eq(false)
|
5
|
+
end
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
shared_examples "transactions are supported" do
|
10
|
+
describe "#supports_transactions?" do
|
11
|
+
it "returns true" do
|
12
|
+
expect(subject.supports_transactions?).to eq(true)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
it { should respond_to :begin_transaction }
|
17
|
+
it { should respond_to :commit_transaction }
|
18
|
+
it { should respond_to :rollback_transaction }
|
19
|
+
it { should respond_to :in_transaction? }
|
20
|
+
|
21
|
+
describe "#in_transaction?" do
|
22
|
+
it "returns false if you aren't in a transaction" do
|
23
|
+
expect(subject.in_transaction?).to eq(false)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
it "raises a MessageDriver::TransactionError error if you begin two transactions" do
|
28
|
+
subject.begin_transaction
|
29
|
+
expect {
|
30
|
+
subject.begin_transaction
|
31
|
+
}.to raise_error MessageDriver::TransactionError
|
32
|
+
end
|
33
|
+
it "raises a MessageDriver::TransactionError error if you commit outside of a transaction" do
|
34
|
+
expect {
|
35
|
+
subject.commit_transaction
|
36
|
+
}.to raise_error MessageDriver::TransactionError
|
37
|
+
end
|
38
|
+
it "raises a MessageDriver::TransactionError error if you rollback outside of a transaction" do
|
39
|
+
expect {
|
40
|
+
subject.rollback_transaction
|
41
|
+
}.to raise_error MessageDriver::TransactionError
|
42
|
+
end
|
43
|
+
end
|
@@ -2,43 +2,62 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
module MessageDriver::Adapters
|
4
4
|
describe Base do
|
5
|
-
class TestAdapter <
|
5
|
+
class TestAdapter < Base
|
6
6
|
def initialize(configuration)
|
7
|
-
|
8
|
-
end
|
9
|
-
end
|
10
|
-
subject { TestAdapter.new({}) }
|
11
|
-
|
12
|
-
describe "#publish" do
|
13
|
-
it "raises an error" do
|
14
|
-
expect {
|
15
|
-
subject.publish(:destination, {foo: "bar"})
|
16
|
-
}.to raise_error "Must be implemented in subclass"
|
17
7
|
end
|
18
8
|
end
|
9
|
+
subject(:adapter) { TestAdapter.new({}) }
|
19
10
|
|
20
|
-
describe "#
|
11
|
+
describe "#new_context" do
|
21
12
|
it "raises an error" do
|
22
13
|
expect {
|
23
|
-
subject.
|
14
|
+
subject.new_context
|
24
15
|
}.to raise_error "Must be implemented in subclass"
|
25
16
|
end
|
26
17
|
end
|
27
18
|
|
28
19
|
describe "#stop" do
|
29
|
-
it "raises an error" do
|
20
|
+
it "raises an error", pending: "maybe we don't want to do this" do
|
30
21
|
expect {
|
31
22
|
subject.stop
|
32
23
|
}.to raise_error "Must be implemented in subclass"
|
33
24
|
end
|
34
25
|
end
|
35
26
|
|
36
|
-
describe
|
37
|
-
|
38
|
-
expect {
|
39
|
-
subject.create_destination("foo")
|
40
|
-
}.to raise_error "Must be implemented in subclass"
|
27
|
+
describe ContextBase do
|
28
|
+
class TestContext < ContextBase
|
41
29
|
end
|
30
|
+
subject(:adapter_context) { TestContext.new(adapter) }
|
31
|
+
|
32
|
+
it_behaves_like "an adapter context"
|
33
|
+
it_behaves_like "transactions are not supported"
|
34
|
+
it_behaves_like "client acks are not supported"
|
35
|
+
it_behaves_like "subscriptions are not supported"
|
36
|
+
|
37
|
+
describe "#create_destination" do
|
38
|
+
it "raises an error" do
|
39
|
+
expect {
|
40
|
+
subject.create_destination("foo")
|
41
|
+
}.to raise_error "Must be implemented in subclass"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "#publish" do
|
46
|
+
it "raises an error" do
|
47
|
+
expect {
|
48
|
+
subject.publish(:destination, {foo: "bar"})
|
49
|
+
}.to raise_error "Must be implemented in subclass"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "#pop_message" do
|
54
|
+
it "raises an error" do
|
55
|
+
expect {
|
56
|
+
subject.pop_message(:destination)
|
57
|
+
}.to raise_error "Must be implemented in subclass"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
42
61
|
end
|
43
62
|
end
|
44
63
|
end
|
@@ -3,12 +3,16 @@ require 'message_driver/adapters/in_memory_adapter'
|
|
3
3
|
|
4
4
|
module MessageDriver
|
5
5
|
describe Broker do
|
6
|
-
|
6
|
+
let(:options) { { adapter: :in_memory } }
|
7
|
+
before do
|
8
|
+
described_class.configure(options)
|
9
|
+
end
|
10
|
+
subject(:broker) { described_class.instance }
|
7
11
|
|
8
12
|
describe ".configure" do
|
9
13
|
it "calls new, passing in the options and saves the instance" do
|
10
14
|
options = {foo: :bar}
|
11
|
-
result =
|
15
|
+
result = double(described_class)
|
12
16
|
described_class.should_receive(:new).with(options).and_return(result)
|
13
17
|
|
14
18
|
described_class.configure(options)
|
@@ -17,6 +21,24 @@ module MessageDriver
|
|
17
21
|
end
|
18
22
|
end
|
19
23
|
|
24
|
+
describe "#logger" do
|
25
|
+
it "returns the logger, which logs at the info level" do
|
26
|
+
expect(subject.logger).to be_a Logger
|
27
|
+
expect(subject.logger).to be_info
|
28
|
+
expect(subject.logger).to_not be_debug
|
29
|
+
end
|
30
|
+
|
31
|
+
context "configuring the logger" do
|
32
|
+
let(:logger) { double(Logger).as_null_object }
|
33
|
+
let(:options) { { adapter: :in_memory, logger: logger } }
|
34
|
+
|
35
|
+
it "returns the provided logger" do
|
36
|
+
actual = subject.logger
|
37
|
+
expect(actual).to be logger
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
20
42
|
describe "#initialize" do
|
21
43
|
it "raises an error if you don't specify an adapter" do
|
22
44
|
expect {
|
@@ -62,23 +84,60 @@ module MessageDriver
|
|
62
84
|
end
|
63
85
|
end
|
64
86
|
|
65
|
-
describe "#
|
66
|
-
it "
|
87
|
+
describe "#destination" do
|
88
|
+
it "returns the destination" do
|
89
|
+
destination = broker.destination(:my_queue, "my_queue", exclusive: true)
|
90
|
+
expect(destination).to be_a MessageDriver::Destination::Base
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe "#find_destination" do
|
95
|
+
it "finds the previously defined destination" do
|
96
|
+
my_destination = broker.destination(:my_queue, "my_queue", exclusive: true)
|
97
|
+
expect(broker.find_destination(:my_queue)).to be(my_destination)
|
98
|
+
end
|
67
99
|
|
68
100
|
context "when the destination can't be found" do
|
69
|
-
|
101
|
+
let(:bad_dest_name) { :not_a_queue }
|
102
|
+
it "raises a MessageDriver:NoSuchDestinationError" do
|
103
|
+
expect {
|
104
|
+
broker.find_destination(bad_dest_name)
|
105
|
+
}.to raise_error(MessageDriver::NoSuchDestinationError, /#{bad_dest_name}/)
|
106
|
+
end
|
70
107
|
end
|
71
108
|
end
|
72
|
-
describe "#pop_message" do
|
73
|
-
it "needs some real tests"
|
74
109
|
|
75
|
-
|
76
|
-
|
110
|
+
describe "#consumer" do
|
111
|
+
let(:consumer_double) { lambda do |m| end }
|
112
|
+
it "saves the provided consumer" do
|
113
|
+
broker.consumer(:my_consumer, &consumer_double)
|
114
|
+
expect(broker.consumers[:my_consumer]).to be(consumer_double)
|
115
|
+
end
|
116
|
+
|
117
|
+
context "when no consumer is provided" do
|
118
|
+
it "raises an error" do
|
119
|
+
expect {
|
120
|
+
broker.consumer(:my_consumer)
|
121
|
+
}.to raise_error(MessageDriver::Error, "you must provide a block")
|
122
|
+
end
|
77
123
|
end
|
78
124
|
end
|
79
125
|
|
80
|
-
describe "#
|
81
|
-
|
126
|
+
describe "#find_consumer" do
|
127
|
+
let(:consumer_double) { lambda do |m| end }
|
128
|
+
it "finds the previously defined consumer" do
|
129
|
+
my_consumer = broker.consumer(:my_consumer, &consumer_double)
|
130
|
+
expect(broker.find_consumer(:my_consumer)).to be(my_consumer)
|
131
|
+
end
|
132
|
+
|
133
|
+
context "when the consumer can't be found" do
|
134
|
+
let(:bad_consumer_name) { :not_a_queue }
|
135
|
+
it "raises a MessageDriver:NoSuchConsumerError" do
|
136
|
+
expect {
|
137
|
+
broker.find_consumer(bad_consumer_name)
|
138
|
+
}.to raise_error(MessageDriver::NoSuchConsumerError, /#{bad_consumer_name}/)
|
139
|
+
end
|
140
|
+
end
|
82
141
|
end
|
83
142
|
|
84
143
|
describe "#dynamic_destination" do
|
@@ -86,13 +145,7 @@ module MessageDriver
|
|
86
145
|
destination = broker.dynamic_destination("my_queue", exclusive: true)
|
87
146
|
expect(destination).to be_a MessageDriver::Destination::Base
|
88
147
|
end
|
89
|
-
it "doesn't save the destination" do
|
90
|
-
destination = nil
|
91
|
-
expect {
|
92
|
-
destination = broker.dynamic_destination("my_queue", exclusive: true)
|
93
|
-
}.to_not change{broker.destinations.size}
|
94
|
-
expect(broker.destinations.values).to_not include(destination)
|
95
|
-
end
|
96
148
|
end
|
149
|
+
|
97
150
|
end
|
98
151
|
end
|