message-driver 0.1.0 → 0.2.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/.travis.yml +18 -7
  4. data/CHANGELOG.md +12 -2
  5. data/Gemfile +17 -0
  6. data/Guardfile +8 -4
  7. data/README.md +14 -5
  8. data/Rakefile +44 -11
  9. data/examples/basic_producer_and_consumer/Gemfile +5 -0
  10. data/examples/basic_producer_and_consumer/common.rb +17 -0
  11. data/examples/basic_producer_and_consumer/consumer.rb +24 -0
  12. data/examples/basic_producer_and_consumer/producer.rb +33 -0
  13. data/features/.nav +8 -0
  14. data/features/CHANGELOG.md +12 -2
  15. data/features/amqp_specific_features/binding_amqp_destinations.feature +7 -7
  16. data/features/amqp_specific_features/declaring_amqp_exchanges.feature +3 -3
  17. data/features/amqp_specific_features/nack_redelivered_messages.feature +92 -0
  18. data/features/amqp_specific_features/requeueing_on_nack.feature +44 -0
  19. data/features/amqp_specific_features/server_named_destinations.feature +5 -5
  20. data/features/client_acks.feature +92 -0
  21. data/features/destination_metadata.feature +9 -11
  22. data/features/dynamic_destinations.feature +7 -7
  23. data/features/error_handling.feature +11 -9
  24. data/features/logging.feature +14 -0
  25. data/features/message_consumers/auto_ack_consumers.feature +79 -0
  26. data/features/message_consumers/manual_ack_consumers.feature +95 -0
  27. data/features/message_consumers/transactional_ack_consumers.feature +77 -0
  28. data/features/message_consumers.feature +54 -0
  29. data/features/publishing_a_message.feature +6 -10
  30. data/features/publishing_with_transactions.feature +10 -14
  31. data/features/rabbitmq_specific_features/dead_letter_queueing.feature +116 -0
  32. data/features/step_definitions/dynamic_destinations_steps.rb +3 -3
  33. data/features/step_definitions/error_handling_steps.rb +4 -2
  34. data/features/step_definitions/logging_steps.rb +28 -0
  35. data/features/step_definitions/message_consumers_steps.rb +29 -0
  36. data/features/step_definitions/steps.rb +60 -9
  37. data/features/support/broker_config_helper.rb +19 -0
  38. data/features/support/env.rb +1 -0
  39. data/features/support/firewall_helper.rb +8 -11
  40. data/features/support/message_table_matcher.rb +21 -5
  41. data/features/support/test_runner.rb +39 -16
  42. data/lib/message_driver/adapters/base.rb +51 -4
  43. data/lib/message_driver/adapters/bunny_adapter.rb +251 -127
  44. data/lib/message_driver/adapters/in_memory_adapter.rb +97 -18
  45. data/lib/message_driver/adapters/stomp_adapter.rb +127 -0
  46. data/lib/message_driver/broker.rb +23 -24
  47. data/lib/message_driver/client.rb +157 -0
  48. data/lib/message_driver/destination.rb +7 -4
  49. data/lib/message_driver/errors.rb +27 -0
  50. data/lib/message_driver/logging.rb +11 -0
  51. data/lib/message_driver/message.rb +8 -0
  52. data/lib/message_driver/subscription.rb +18 -0
  53. data/lib/message_driver/vendor/.document +0 -0
  54. data/lib/message_driver/vendor/nesty/nested_error.rb +26 -0
  55. data/lib/message_driver/vendor/nesty.rb +1 -0
  56. data/lib/message_driver/version.rb +1 -1
  57. data/lib/message_driver.rb +4 -2
  58. data/message-driver.gemspec +4 -4
  59. data/spec/integration/{amqp_integration_spec.rb → bunny/amqp_integration_spec.rb} +29 -28
  60. data/spec/integration/bunny/bunny_adapter_spec.rb +339 -0
  61. data/spec/integration/in_memory/in_memory_adapter_spec.rb +126 -0
  62. data/spec/integration/stomp/stomp_adapter_spec.rb +142 -0
  63. data/spec/spec_helper.rb +5 -2
  64. data/spec/support/shared/adapter_examples.rb +17 -0
  65. data/spec/support/shared/client_ack_examples.rb +18 -0
  66. data/spec/support/shared/context_examples.rb +14 -0
  67. data/spec/support/shared/destination_examples.rb +4 -5
  68. data/spec/support/shared/subscription_examples.rb +146 -0
  69. data/spec/support/shared/transaction_examples.rb +43 -0
  70. data/spec/support/utils.rb +14 -0
  71. data/spec/units/message_driver/adapters/base_spec.rb +38 -19
  72. data/spec/units/message_driver/broker_spec.rb +71 -18
  73. data/spec/units/message_driver/client_spec.rb +375 -0
  74. data/spec/units/message_driver/destination_spec.rb +9 -0
  75. data/spec/units/message_driver/logging_spec.rb +18 -0
  76. data/spec/units/message_driver/message_spec.rb +36 -0
  77. data/spec/units/message_driver/subscription_spec.rb +24 -0
  78. data/test_lib/broker_config.rb +50 -20
  79. metadata +83 -45
  80. data/.rbenv-version +0 -1
  81. data/lib/message_driver/exceptions.rb +0 -18
  82. data/lib/message_driver/message_publisher.rb +0 -15
  83. data/spec/integration/message_driver/adapters/bunny_adapter_spec.rb +0 -301
  84. data/spec/units/message_driver/adapters/in_memory_adapter_spec.rb +0 -43
  85. 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 :no_travis if ENV['TRAVIS']=='true' && ENV['ADAPTER']=='bunny'
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
- c.filter_run BrokerConfig.current_adapter
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
- let!(:message) { destination.pop_message }
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 eq(headers) }
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
- #FIXME this example fails on travis with the bunny adapter :(
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
@@ -0,0 +1,14 @@
1
+ module Utils
2
+ def pause_if_needed(seconds=0.1)
3
+ seconds *= 10 if ENV['CI'] == 'true'
4
+ case BrokerConfig.current_adapter
5
+ when :in_memory
6
+ else
7
+ sleep seconds
8
+ end
9
+ end
10
+ end
11
+
12
+ RSpec.configure do |config|
13
+ config.include Utils
14
+ end
@@ -2,43 +2,62 @@ require 'spec_helper'
2
2
 
3
3
  module MessageDriver::Adapters
4
4
  describe Base do
5
- class TestAdapter < described_class
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 "#pop_message" do
11
+ describe "#new_context" do
21
12
  it "raises an error" do
22
13
  expect {
23
- subject.pop_message(:destination)
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 "#create_destination" do
37
- it "raises an error" do
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
- subject(:broker) { described_class.new(adapter: :in_memory) }
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 = stub(described_class)
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 "#publish" do
66
- it "needs some real tests"
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
- it "raises an error"
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
- context "when the destination can't be found" do
76
- it "raises an error"
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 "#destination" do
81
- it "needs some real tests"
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