message-driver 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +7 -17
  3. data/CHANGELOG.md +6 -1
  4. data/Guardfile +3 -3
  5. data/Rakefile +0 -2
  6. data/ci/reset_vhost +5 -0
  7. data/ci/travis_setup +10 -0
  8. data/features/.nav +5 -2
  9. data/features/CHANGELOG.md +6 -1
  10. data/features/amqp_specific_features/declaring_amqp_exchanges.feature +3 -3
  11. data/features/amqp_specific_features/nack_redelivered_messages.feature +2 -2
  12. data/features/amqp_specific_features/server_named_destinations.feature +3 -4
  13. data/features/connecting_to_multiple_brokers.feature +51 -0
  14. data/features/destination_metadata.feature +2 -2
  15. data/features/dynamic_destinations.feature +2 -2
  16. data/features/error_handling.feature +2 -4
  17. data/features/logging.feature +3 -2
  18. data/features/message_consumers/auto_ack_consumers.feature +4 -4
  19. data/features/{message_consumers.feature → message_consumers/basics.feature} +2 -2
  20. data/features/message_consumers/manual_ack_consumers.feature +5 -5
  21. data/features/message_consumers/prefetch_size.feature +4 -4
  22. data/features/message_consumers/transactional_ack_consumers.feature +7 -4
  23. data/features/rabbitmq_specific_features/dead_letter_queueing.feature +3 -3
  24. data/features/step_definitions/dynamic_destinations_steps.rb +2 -2
  25. data/features/step_definitions/logging_steps.rb +5 -1
  26. data/features/step_definitions/message_consumers_steps.rb +1 -1
  27. data/features/step_definitions/steps.rb +13 -4
  28. data/features/support/env.rb +1 -1
  29. data/features/support/test_runner.rb +6 -1
  30. data/lib/message_driver/adapters/base.rb +7 -1
  31. data/lib/message_driver/adapters/bunny_adapter.rb +22 -57
  32. data/lib/message_driver/adapters/in_memory_adapter.rb +3 -2
  33. data/lib/message_driver/adapters/stomp_adapter.rb +6 -6
  34. data/lib/message_driver/broker.rb +80 -19
  35. data/lib/message_driver/client.rb +50 -29
  36. data/lib/message_driver/destination.rb +2 -2
  37. data/lib/message_driver/errors.rb +2 -0
  38. data/lib/message_driver/logging.rb +7 -1
  39. data/lib/message_driver/message.rb +15 -4
  40. data/lib/message_driver/version.rb +1 -1
  41. data/lib/message_driver.rb +12 -5
  42. data/spec/integration/bunny/amqp_integration_spec.rb +15 -20
  43. data/spec/integration/bunny/bunny_adapter_spec.rb +13 -13
  44. data/spec/integration/in_memory/in_memory_adapter_spec.rb +2 -1
  45. data/spec/integration/stomp/stomp_adapter_spec.rb +6 -8
  46. data/spec/spec_helper.rb +9 -0
  47. data/spec/support/shared/adapter_examples.rb +6 -0
  48. data/spec/support/shared/context_examples.rb +2 -0
  49. data/spec/support/shared/destination_examples.rb +2 -0
  50. data/spec/units/message_driver/adapters/base_spec.rb +0 -8
  51. data/spec/units/message_driver/broker_spec.rb +240 -109
  52. data/spec/units/message_driver/client_spec.rb +69 -62
  53. data/spec/units/message_driver/message_spec.rb +59 -22
  54. data/test_lib/broker_config.rb +2 -1
  55. metadata +8 -7
  56. data/lib/bunny/session_patch.rb +0 -19
  57. data/spec/units/message_driver/logging_spec.rb +0 -18
@@ -3,38 +3,120 @@ require 'message_driver/adapters/in_memory_adapter'
3
3
 
4
4
  module MessageDriver
5
5
  describe Broker do
6
+ let(:broker_name) { described_class::DEFAULT_BROKER_NAME }
6
7
  let(:options) { { adapter: :in_memory } }
7
- before do
8
- described_class.configure(options)
9
- end
10
- subject(:broker) { described_class.instance }
11
8
 
12
- describe ".configure" do
9
+ describe ".configure and .broker" do
13
10
  it "calls new, passing in the options and saves the instance" do
14
11
  options = {foo: :bar}
15
- result = double(described_class)
16
- described_class.should_receive(:new).with(options).and_return(result)
12
+ result = double(described_class).as_null_object
13
+ described_class.should_receive(:new).with(described_class::DEFAULT_BROKER_NAME, options).and_return(result)
17
14
 
18
15
  described_class.configure(options)
19
16
 
20
- expect(described_class.instance).to be result
17
+ expect(described_class.broker).to be result
18
+ expect(described_class.broker(described_class::DEFAULT_BROKER_NAME)).to be result
19
+ end
20
+
21
+ it "doesn't allow you to configure the same broker twice" do
22
+ described_class.configure(broker_name, options)
23
+ expect {
24
+ described_class.configure(broker_name, options)
25
+ }.to raise_error MessageDriver::BrokerAlreadyConfigured, match("default")
26
+ end
27
+
28
+ context "when configurating multiple brokers" do
29
+ it "allows you to fetch each configured broker through .broker" do
30
+ options1 = {foo: :bar}
31
+ options2 = {bar: :baz}
32
+ result1 = double("result1").as_null_object
33
+ result2 = double("result2").as_null_object
34
+ allow(described_class).to receive(:new).with(:result1, options1).and_return(result1)
35
+ allow(described_class).to receive(:new).with(:result2, options2).and_return(result2)
36
+
37
+ described_class.configure(:result1, options1)
38
+ described_class.configure(:result2, options2)
39
+
40
+ expect(described_class.broker(:result1)).to be(result1)
41
+ expect(described_class.broker(:result2)).to be(result2)
42
+ end
43
+ end
44
+
45
+ context "when you try to access a broker that isn't configured" do
46
+ it "should raise an error" do
47
+ expect {
48
+ described_class.broker(:not_an_adapter)
49
+ }.to raise_error BrokerNotConfigured
50
+ end
21
51
  end
22
52
  end
23
53
 
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
54
+ describe ".reset" do
55
+ it "stops and removes all the brokers" do
56
+ broker1 = described_class.configure(:broker1, adapter: :in_memory)
57
+ broker2 = described_class.configure(:broker2, adapter: :in_memory)
58
+
59
+ allow(broker1).to receive(:stop).and_call_original
60
+ allow(broker2).to receive(:stop).and_call_original
61
+
62
+ described_class.reset
63
+
64
+ expect(broker1).to have_received(:stop)
65
+ expect(broker2).to have_received(:stop)
66
+
67
+ expect {
68
+ described_class.broker(:broker1)
69
+ }.to raise_error BrokerNotConfigured
70
+
71
+ expect {
72
+ described_class.broker(:broker2)
73
+ }.to raise_error BrokerNotConfigured
29
74
  end
30
75
 
31
- context "configuring the logger" do
32
- let(:logger) { double(Logger).as_null_object }
33
- let(:options) { { adapter: :in_memory, logger: logger } }
76
+ context "when one of the brokers raises and error" do
77
+ it "still stops all the brokers" do
78
+ broker1 = described_class.configure(:broker1, adapter: :in_memory)
79
+ broker2 = described_class.configure(:broker2, adapter: :in_memory)
80
+
81
+ allow(broker1).to receive(:stop).and_raise "error stopping broker1!"
82
+ allow(broker2).to receive(:stop).and_call_original
83
+
84
+ expect {
85
+ described_class.reset
86
+ }.not_to raise_error
87
+
88
+ expect(broker1).to have_received(:stop)
89
+ expect(broker2).to have_received(:stop)
34
90
 
35
- it "returns the provided logger" do
36
- actual = subject.logger
37
- expect(actual).to be logger
91
+ expect {
92
+ described_class.broker(:broker1)
93
+ }.to raise_error BrokerNotConfigured
94
+
95
+ expect {
96
+ described_class.broker(:broker2)
97
+ }.to raise_error BrokerNotConfigured
98
+ end
99
+ end
100
+ end
101
+
102
+ describe ".client" do
103
+ let(:broker_name) { described_class::DEFAULT_BROKER_NAME }
104
+ it "returns a module that extends MessageDriver::Client for the specified broker" do
105
+ expect(described_class.client(broker_name)).to be_kind_of MessageDriver::Client
106
+ expect(described_class.client(broker_name).broker_name).to eq(broker_name)
107
+ end
108
+
109
+ it "caches the modules" do
110
+ first = described_class.client(broker_name)
111
+ second = described_class.client(broker_name)
112
+ expect(second).to be first
113
+ end
114
+
115
+ context "when the broker has a non-default name" do
116
+ let(:broker_name) { :my_cool_broker }
117
+ it "returns a module that extends MessageDriver::Client that knows it's broker" do
118
+ expect(described_class.client(broker_name)).to be_kind_of MessageDriver::Client
119
+ expect(described_class.client(broker_name).broker_name).to eq(broker_name)
38
120
  end
39
121
  end
40
122
  end
@@ -81,128 +163,177 @@ module MessageDriver
81
163
  instance = described_class.new(adapter: adapter)
82
164
  expect(instance).not_to be_stopped
83
165
  end
84
- end
85
166
 
86
- describe "#stop" do
87
- let(:adapter) { broker.adapter }
88
- it "calls stop on the adapter" do
89
- allow(adapter).to receive(:stop).and_call_original
90
-
91
- subject.stop
167
+ it "has a default name of :default" do
168
+ adapter = :in_memory
92
169
 
93
- expect(adapter).to have_received(:stop)
170
+ instance = described_class.new(adapter: adapter)
171
+ expect(instance.name).to eq(:default)
94
172
  end
95
173
 
96
- it "marks the broker as stopped" do
97
- expect {
98
- subject.stop
99
- }.to change { subject.stopped? }.from(false).to(true)
100
- end
174
+ it "let's you override the name in the initializer" do
175
+ adapter = :in_memory
176
+ name = :my_vhost
101
177
 
102
- it "invalidates the contexts" do
103
- my_ctx = double("context", invalidate: nil)
104
- adapter.contexts << my_ctx
105
- subject.stop
106
- expect(adapter.contexts).to be_empty
107
- expect(my_ctx).to have_received(:invalidate)
178
+ instance = described_class.new(name, adapter: adapter)
179
+ expect(instance.name).to eq(name)
108
180
  end
109
181
  end
110
182
 
111
- describe "#restart" do
112
- let!(:original_adapter) { subject.adapter }
113
- before do
114
- allow(original_adapter).to receive(:stop).and_call_original
115
- end
116
183
 
117
- it "reconfigures the adapter" do
118
- expect {
119
- subject.restart
120
- }.to change { subject.adapter }
121
- end
184
+ context do
185
+ subject!(:broker) { described_class.configure(broker_name, options) }
122
186
 
123
- it "stops the adapter if it hasn't already been stopped" do
124
- subject.restart
125
- expect(original_adapter).to have_received(:stop).once
187
+ describe "#stop" do
188
+ let(:adapter) { broker.adapter }
189
+ it "calls stop on the adapter" do
190
+ allow(adapter).to receive(:stop).and_call_original
191
+
192
+ subject.stop
193
+
194
+ expect(adapter).to have_received(:stop)
195
+ end
196
+
197
+ it "marks the broker as stopped" do
198
+ expect {
199
+ subject.stop
200
+ }.to change { subject.stopped? }.from(false).to(true)
201
+ end
202
+
203
+ it "invalidates the contexts" do
204
+ my_ctx = double("context", invalidate: nil)
205
+ adapter.contexts << my_ctx
206
+ subject.stop
207
+ expect(adapter.contexts).to be_empty
208
+ expect(my_ctx).to have_received(:invalidate)
209
+ end
126
210
  end
127
211
 
128
- it "does not stop the adapter again if it has already been stopped" do
129
- expect(subject.adapter).to be original_adapter
130
- subject.stop
131
- expect {
212
+ describe "#restart" do
213
+ let!(:original_adapter) { subject.adapter }
214
+ before do
215
+ allow(original_adapter).to receive(:stop).and_call_original
216
+ end
217
+
218
+ it "reconfigures the adapter" do
219
+ expect {
220
+ subject.restart
221
+ }.to change { subject.adapter }
222
+ end
223
+
224
+ it "stops the adapter if it hasn't already been stopped" do
132
225
  subject.restart
133
- }.to change { subject.stopped? }.from(true).to(false)
134
- expect(original_adapter).to have_received(:stop).once
135
- end
136
- end
226
+ expect(original_adapter).to have_received(:stop).once
227
+ end
137
228
 
138
- describe "#configuration" do
139
- it "returns the configuration hash you passed to .configure" do
140
- config = {adapter: :in_memory, foo: :bar, baz: :boz}
141
- instance = described_class.new(config)
142
- expect(instance.configuration).to be config
229
+ it "does not stop the adapter again if it has already been stopped" do
230
+ expect(subject.adapter).to be original_adapter
231
+ subject.stop
232
+ expect {
233
+ subject.restart
234
+ }.to change { subject.stopped? }.from(true).to(false)
235
+ expect(original_adapter).to have_received(:stop).once
236
+ end
143
237
  end
144
- end
145
238
 
146
- describe "#destination" do
147
- it "returns the destination" do
148
- destination = broker.destination(:my_queue, "my_queue", exclusive: true)
149
- expect(destination).to be_a MessageDriver::Destination::Base
239
+ describe "#configuration" do
240
+ it "returns the configuration hash you passed to .configure" do
241
+ config = {adapter: :in_memory, foo: :bar, baz: :boz}
242
+ instance = described_class.new(config)
243
+ expect(instance.configuration).to be config
244
+ end
150
245
  end
151
- end
152
246
 
153
- describe "#find_destination" do
154
- it "finds the previously defined destination" do
155
- my_destination = broker.destination(:my_queue, "my_queue", exclusive: true)
156
- expect(broker.find_destination(:my_queue)).to be(my_destination)
247
+ describe "#destination" do
248
+ it "returns the destination" do
249
+ destination = broker.destination(:my_queue, "my_queue", exclusive: true)
250
+ expect(destination).to be_a MessageDriver::Destination::Base
251
+ end
157
252
  end
158
253
 
159
- context "when the destination can't be found" do
160
- let(:bad_dest_name) { :not_a_queue }
161
- it "raises a MessageDriver:NoSuchDestinationError" do
162
- expect {
163
- broker.find_destination(bad_dest_name)
164
- }.to raise_error(MessageDriver::NoSuchDestinationError, /#{bad_dest_name}/)
254
+ describe "#find_destination" do
255
+ it "finds the previously defined destination" do
256
+ my_destination = broker.destination(:my_queue, "my_queue", exclusive: true)
257
+ expect(broker.find_destination(:my_queue)).to be(my_destination)
165
258
  end
166
- end
167
- end
168
259
 
169
- describe "#consumer" do
170
- let(:consumer_double) { lambda do |m| end }
171
- it "saves the provided consumer" do
172
- broker.consumer(:my_consumer, &consumer_double)
173
- expect(broker.consumers[:my_consumer]).to be(consumer_double)
260
+ context "when the destination can't be found" do
261
+ let(:bad_dest_name) { :not_a_queue }
262
+ it "raises a MessageDriver:NoSuchDestinationError" do
263
+ expect {
264
+ broker.find_destination(bad_dest_name)
265
+ }.to raise_error(MessageDriver::NoSuchDestinationError, /#{bad_dest_name}/)
266
+ end
267
+ end
174
268
  end
175
269
 
176
- context "when no consumer is provided" do
177
- it "raises an error" do
178
- expect {
179
- broker.consumer(:my_consumer)
180
- }.to raise_error(MessageDriver::Error, "you must provide a block")
270
+ describe "#consumer" do
271
+ let(:consumer_double) { lambda do |m| end }
272
+ it "saves the provided consumer" do
273
+ broker.consumer(:my_consumer, &consumer_double)
274
+ expect(broker.consumers[:my_consumer]).to be(consumer_double)
275
+ end
276
+
277
+ context "when no consumer is provided" do
278
+ it "raises an error" do
279
+ expect {
280
+ broker.consumer(:my_consumer)
281
+ }.to raise_error(MessageDriver::Error, "you must provide a block")
282
+ end
181
283
  end
182
284
  end
183
- end
184
285
 
185
- describe "#find_consumer" do
186
- let(:consumer_double) { lambda do |m| end }
187
- it "finds the previously defined consumer" do
188
- my_consumer = broker.consumer(:my_consumer, &consumer_double)
189
- expect(broker.find_consumer(:my_consumer)).to be(my_consumer)
286
+ describe "#find_consumer" do
287
+ let(:consumer_double) { lambda do |m| end }
288
+ it "finds the previously defined consumer" do
289
+ my_consumer = broker.consumer(:my_consumer, &consumer_double)
290
+ expect(broker.find_consumer(:my_consumer)).to be(my_consumer)
291
+ end
292
+
293
+ context "when the consumer can't be found" do
294
+ let(:bad_consumer_name) { :not_a_queue }
295
+ it "raises a MessageDriver:NoSuchConsumerError" do
296
+ expect {
297
+ broker.find_consumer(bad_consumer_name)
298
+ }.to raise_error(MessageDriver::NoSuchConsumerError, /#{bad_consumer_name}/)
299
+ end
300
+ end
190
301
  end
191
302
 
192
- context "when the consumer can't be found" do
193
- let(:bad_consumer_name) { :not_a_queue }
194
- it "raises a MessageDriver:NoSuchConsumerError" do
195
- expect {
196
- broker.find_consumer(bad_consumer_name)
197
- }.to raise_error(MessageDriver::NoSuchConsumerError, /#{bad_consumer_name}/)
303
+ describe "#dynamic_destination" do
304
+ it "returns the destination" do
305
+ destination = broker.dynamic_destination("my_queue", exclusive: true)
306
+ expect(destination).to be_a MessageDriver::Destination::Base
198
307
  end
199
308
  end
200
- end
201
309
 
202
- describe "#dynamic_destination" do
203
- it "returns the destination" do
204
- destination = broker.dynamic_destination("my_queue", exclusive: true)
205
- expect(destination).to be_a MessageDriver::Destination::Base
310
+ describe "#client" do
311
+ let(:broker_name) { described_class::DEFAULT_BROKER_NAME }
312
+ it "returns a module that extends MessageDriver::Client that knows it's broker" do
313
+ expect(broker.client).to be_kind_of MessageDriver::Client
314
+ expect(broker.client.broker_name).to eq(broker_name)
315
+ expect(broker.client.broker).to be(broker)
316
+ end
317
+
318
+ it "caches the modules" do
319
+ first = broker.client
320
+ second = broker.client
321
+ expect(second).to be first
322
+ end
323
+
324
+ it "returns the same module as .client" do
325
+ expect(broker.client).to be described_class.client(broker.name)
326
+ end
327
+
328
+ context "when the broker has a non-default name" do
329
+ let(:broker_name) { :my_cool_broker }
330
+ it "returns a module that extends MessageDriver::Client that knows it's broker" do
331
+ expect(broker.name).to eq(broker_name)
332
+ expect(broker.client).to be_kind_of MessageDriver::Client
333
+ expect(broker.client.broker_name).to eq(broker_name)
334
+ expect(broker.client.broker).to be(broker)
335
+ end
336
+ end
206
337
  end
207
338
  end
208
339
 
@@ -8,15 +8,19 @@ module MessageDriver
8
8
  include Client
9
9
  end
10
10
 
11
- let(:adapter) { Adapters::InMemoryAdapter.new({}) }
11
+ let(:logger) { MessageDriver.logger }
12
+ let(:broker_name) { Broker::DEFAULT_BROKER_NAME }
13
+ let!(:broker) { Broker.configure(broker_name, adapter: Adapters::InMemoryAdapter, logger: logger) }
14
+ let(:adapter) { broker.adapter }
12
15
  let(:adapter_context) { adapter.new_context }
13
- let(:logger) { double(Logger).as_null_object }
14
-
15
- before do
16
- MessageDriver.configure(adapter: adapter, logger: logger)
17
- end
18
16
 
19
17
  shared_examples "a Client" do
18
+ describe "#broker" do
19
+ it "returns the broker_name" do
20
+ expect(subject.broker_name).to eq(broker_name)
21
+ end
22
+ end
23
+
20
24
  describe "#current_adapter_context" do
21
25
  before { subject.clear_context }
22
26
 
@@ -37,7 +41,7 @@ module MessageDriver
37
41
  end
38
42
 
39
43
  context "with a given adapter_context" do
40
- around do |example|
44
+ around(:each) do |example|
41
45
  subject.with_adapter_context(adapter_context, &example)
42
46
  end
43
47
 
@@ -66,7 +70,7 @@ module MessageDriver
66
70
  end
67
71
 
68
72
  describe "#publish" do
69
- let(:destination) { Broker.destination(:my_queue, "my_queue", exclusive: true) }
73
+ let(:destination) { broker.destination(:my_queue, "my_queue", exclusive: true) }
70
74
  let(:body) { "my message" }
71
75
  let(:headers) { {foo: :bar} }
72
76
  let(:properties) { {bar: :baz} }
@@ -103,7 +107,7 @@ module MessageDriver
103
107
 
104
108
  describe "#pop_message" do
105
109
  let(:expected) { double(MessageDriver::Message) }
106
- let(:destination) { Broker.destination(:my_queue, "my_queue", exclusive: true) }
110
+ let(:destination) { broker.destination(:my_queue, "my_queue", exclusive: true) }
107
111
  let(:options) { {foo: :bar} }
108
112
  before do
109
113
  adapter_context.stub(:pop_message)
@@ -180,6 +184,7 @@ module MessageDriver
180
184
 
181
185
  context "and the the rollback raises an error" do
182
186
  it "logs the error from the rollback and raises the original error" do
187
+ allow(logger).to receive(:error)
183
188
  adapter_context.stub(:rollback_transaction).and_raise("rollback failed!")
184
189
  expect {
185
190
  subject.with_message_transaction do
@@ -232,6 +237,7 @@ module MessageDriver
232
237
  adapter_context.should_not have_received(:rollback_transaction)
233
238
  end
234
239
  it "logs a warning" do
240
+ allow(logger).to receive(:debug)
235
241
  expect { |blk|
236
242
  subject.with_message_transaction(&blk)
237
243
  }.to yield_control
@@ -244,33 +250,15 @@ module MessageDriver
244
250
  let(:message) { double("message") }
245
251
  let(:options) { {foo: :bar} }
246
252
  before do
247
- adapter_context.stub(:ack_message)
253
+ allow(message).to receive(:ack)
248
254
  end
249
- context "when the adapter supports client acks" do
250
- before do
251
- adapter_context.stub(:supports_client_acks?) { true }
252
- end
253
- it "calls #ack_message with the message" do
254
- subject.ack_message(message)
255
- adapter_context.should have_received(:ack_message).with(message, {})
256
- end
257
- it "passes the supplied options to ack_message" do
258
- subject.ack_message(message, options)
259
- adapter_context.should have_received(:ack_message).with(message, options)
260
- end
255
+ it "calls #ack on the message" do
256
+ subject.ack_message(message)
257
+ expect(message).to have_received(:ack).with({})
261
258
  end
262
- context "when the adapter doesn't support client acks" do
263
- before do
264
- adapter_context.stub(:supports_client_acks?) { false }
265
- end
266
- it "doesn't call #ack_message" do
267
- subject.ack_message(message)
268
- adapter_context.should_not have_received(:ack_message)
269
- end
270
- it "logs a warning" do
271
- subject.ack_message(message)
272
- expect(logger).to have_received(:debug).with("this adapter does not support client acks")
273
- end
259
+ it "calls #ack on the message and passes the supplied options" do
260
+ subject.ack_message(message, options)
261
+ expect(message).to have_received(:ack).with(options)
274
262
  end
275
263
  end
276
264
 
@@ -278,43 +266,25 @@ module MessageDriver
278
266
  let(:message) { double("message") }
279
267
  let(:options) { {foo: :bar} }
280
268
  before do
281
- adapter_context.stub(:nack_message)
269
+ allow(message).to receive(:nack)
282
270
  end
283
- context "when the adapter supports client acks" do
284
- before do
285
- adapter_context.stub(:supports_client_acks?) { true }
286
- end
287
- it "calls #nack_message with the message" do
288
- subject.nack_message(message)
289
- adapter_context.should have_received(:nack_message).with(message, {})
290
- end
291
- it "passes the supplied options to nack_message" do
292
- subject.nack_message(message, options)
293
- adapter_context.should have_received(:nack_message).with(message, options)
294
- end
271
+ it "calls #nack on the message" do
272
+ subject.nack_message(message)
273
+ expect(message).to have_received(:nack).with({})
295
274
  end
296
- context "when the adapter doesn't support client acks" do
297
- before do
298
- adapter_context.stub(:supports_client_acks?) { false }
299
- end
300
- it "doesn't call #nack_message" do
301
- subject.nack_message(message)
302
- adapter_context.should_not have_received(:nack_message)
303
- end
304
- it "logs a warning" do
305
- subject.nack_message(message)
306
- expect(logger).to have_received(:debug).with("this adapter does not support client acks")
307
- end
275
+ it "calls #nack on the message and passes the supplied options" do
276
+ subject.nack_message(message, options)
277
+ expect(message).to have_received(:nack).with(options)
308
278
  end
309
279
  end
310
280
 
311
281
  describe "#subscribe" do
312
- let(:destination) { Broker.destination(:my_queue, "my_queue", exclusive: true) }
282
+ let(:destination) { broker.destination(:my_queue, "my_queue", exclusive: true) }
313
283
  let(:consumer_double) { lambda do |m| end }
314
284
 
315
285
  before do
316
286
  adapter_context.stub(:subscribe)
317
- Broker.consumer(:my_consumer, &consumer_double)
287
+ broker.consumer(:my_consumer, &consumer_double)
318
288
  end
319
289
 
320
290
  it "delegates to the adapter_context" do
@@ -361,7 +331,7 @@ module MessageDriver
361
331
  end
362
332
 
363
333
  describe "#subscribe_with" do
364
- let(:destination) { Broker.destination(:my_queue, "my_queue", exclusive: true) }
334
+ let(:destination) { broker.destination(:my_queue, "my_queue", exclusive: true) }
365
335
  let(:consumer_double) { lambda do |m| end }
366
336
 
367
337
  before do
@@ -412,5 +382,42 @@ module MessageDriver
412
382
  subject { described_class }
413
383
  it_behaves_like "a Client"
414
384
  end
385
+
386
+ describe ".for_broker" do
387
+ let(:broker_name) { :my_cool_broker }
388
+ let(:client) { described_class.for_broker(broker_name) }
389
+ it "produces a module that extends #{described_class.name}" do
390
+ expect(client).to be_a Module
391
+ expect(client).to be_kind_of described_class
392
+ end
393
+
394
+ it "knows it's broker" do
395
+ expect(client.broker_name).to eq(broker_name)
396
+ expect(client.broker).to be(broker)
397
+ end
398
+
399
+ context "when the resulting module is used as an included module" do
400
+ subject! do
401
+ clz = Class.new
402
+ clz.send :include, client
403
+ clz.new
404
+ end
405
+ it_behaves_like "a Client"
406
+ end
407
+
408
+ context "when the resulting module is used directly" do
409
+ it_behaves_like "a Client" do
410
+ subject! { client }
411
+ end
412
+ end
413
+ end
414
+
415
+ describe ".[]" do
416
+ it "grabs the client for the given broker" do
417
+ expected = double("client")
418
+ allow(Broker).to receive(:client).with(:test_broker).and_return(expected)
419
+ expect(described_class[:test_broker]).to be expected
420
+ end
421
+ end
415
422
  end
416
423
  end