message-driver 0.6.1 → 0.7.0
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 +4 -4
- data/.rubocop.yml +20 -2
- data/.rubocop_todo.yml +15 -23
- data/.travis.yml +10 -22
- data/CHANGELOG.md +9 -0
- data/Gemfile +34 -24
- data/Guardfile +46 -29
- data/LICENSE +1 -1
- data/Rakefile +14 -6
- data/features/CHANGELOG.md +1 -0
- data/features/step_definitions/logging_steps.rb +3 -2
- data/features/support/firewall_helper.rb +2 -2
- data/features/support/no_error_matcher.rb +1 -1
- data/lib/message_driver/adapters/base.rb +115 -11
- data/lib/message_driver/adapters/bunny_adapter.rb +58 -46
- data/lib/message_driver/adapters/in_memory_adapter.rb +57 -35
- data/lib/message_driver/adapters/stomp_adapter.rb +10 -10
- data/lib/message_driver/broker.rb +16 -19
- data/lib/message_driver/client.rb +3 -7
- data/lib/message_driver/destination.rb +4 -4
- data/lib/message_driver/message.rb +3 -2
- data/lib/message_driver/middleware/block_middleware.rb +1 -1
- data/lib/message_driver/subscription.rb +1 -1
- data/lib/message_driver/version.rb +1 -1
- data/message-driver.gemspec +6 -6
- data/spec/integration/bunny/amqp_integration_spec.rb +6 -4
- data/spec/integration/bunny/bunny_adapter_spec.rb +1 -3
- data/spec/integration/in_memory/in_memory_adapter_spec.rb +46 -6
- data/spec/integration/stomp/stomp_adapter_spec.rb +0 -2
- data/spec/spec_helper.rb +6 -0
- data/spec/support/matchers/override_method_matcher.rb +7 -0
- data/spec/support/shared/adapter_examples.rb +3 -0
- data/spec/support/shared/client_ack_examples.rb +26 -4
- data/spec/support/shared/context_examples.rb +46 -0
- data/spec/support/shared/destination_examples.rb +28 -0
- data/spec/support/shared/subscription_examples.rb +6 -1
- data/spec/support/shared/transaction_examples.rb +35 -4
- data/spec/support/test_adapter.rb +19 -0
- data/spec/support/utils.rb +1 -5
- data/spec/units/message_driver/adapters/base_spec.rb +37 -31
- data/spec/units/message_driver/broker_spec.rb +1 -2
- data/spec/units/message_driver/client_spec.rb +3 -3
- data/spec/units/message_driver/destination_spec.rb +4 -2
- data/spec/units/message_driver/message_spec.rb +9 -3
- data/test_lib/broker_config.rb +0 -2
- data/test_lib/provider/base.rb +2 -6
- data/test_lib/provider/rabbitmq.rb +3 -3
- metadata +18 -16
- data/ci/travis_setup +0 -7
- data/features/CHANGELOG.md +0 -102
@@ -129,7 +129,6 @@ module MessageDriver
|
|
129
129
|
end
|
130
130
|
|
131
131
|
describe '#create_destination' do
|
132
|
-
|
133
132
|
context 'with defaults' do
|
134
133
|
context 'the resulting destination' do
|
135
134
|
let(:dest_name) { 'my_dest' }
|
@@ -327,7 +326,6 @@ module MessageDriver
|
|
327
326
|
adapter_context.create_destination(dest_name, type: :exchange, declare: { auto_delete: true })
|
328
327
|
end.to raise_error MessageDriver::Error, /you must provide a valid exchange type/
|
329
328
|
end
|
330
|
-
|
331
329
|
end
|
332
330
|
|
333
331
|
context 'and bindings are provided' do
|
@@ -363,7 +361,7 @@ module MessageDriver
|
|
363
361
|
it 'raises in an error' do
|
364
362
|
expect do
|
365
363
|
adapter_context.create_destination('my_dest', type: :foo_bar)
|
366
|
-
end.to raise_error MessageDriver::Error,
|
364
|
+
end.to raise_error MessageDriver::Error, 'invalid destination type foo_bar'
|
367
365
|
end
|
368
366
|
end
|
369
367
|
end
|
@@ -5,8 +5,10 @@ require 'message_driver/adapters/in_memory_adapter'
|
|
5
5
|
module MessageDriver
|
6
6
|
module Adapters
|
7
7
|
RSpec.describe InMemoryAdapter, :in_memory, type: :integration do
|
8
|
-
let(:broker) {
|
9
|
-
subject(:adapter) {
|
8
|
+
let(:broker) { Broker.configure(adapter: :in_memory) }
|
9
|
+
subject(:adapter) { broker.adapter }
|
10
|
+
|
11
|
+
it { is_expected.to be_a InMemoryAdapter }
|
10
12
|
|
11
13
|
describe '#new_context' do
|
12
14
|
it 'returns a InMemoryAdapter::InMemoryContext' do
|
@@ -70,9 +72,8 @@ module MessageDriver
|
|
70
72
|
adapter.reset_after_tests
|
71
73
|
|
72
74
|
destinations.each do |destination|
|
73
|
-
expect(destination.
|
75
|
+
expect(destination.subscriptions).to be_empty
|
74
76
|
end
|
75
|
-
|
76
77
|
end
|
77
78
|
end
|
78
79
|
|
@@ -87,7 +88,7 @@ module MessageDriver
|
|
87
88
|
dest1.subscribe(&consumer)
|
88
89
|
end
|
89
90
|
it 'is the same consumer on the other destination' do
|
90
|
-
expect(dest2.
|
91
|
+
expect(dest2.subscriptions.first.consumer).to be(consumer)
|
91
92
|
end
|
92
93
|
end
|
93
94
|
|
@@ -123,7 +124,46 @@ module MessageDriver
|
|
123
124
|
describe 'subscribing a consumer' do
|
124
125
|
let(:destination) { adapter.create_destination(:my_queue) }
|
125
126
|
|
126
|
-
|
127
|
+
context 'when there are already messages on the queue' do
|
128
|
+
it 'sends those initial messages to the first subscription created' do
|
129
|
+
4.times { destination.publish('a message') }
|
130
|
+
msgs1 = []
|
131
|
+
msgs2 = []
|
132
|
+
|
133
|
+
destination.subscribe do |msg|
|
134
|
+
msgs1 << msg
|
135
|
+
end
|
136
|
+
|
137
|
+
destination.subscribe do |msg|
|
138
|
+
msgs2 << msg
|
139
|
+
end
|
140
|
+
|
141
|
+
aggregate_failures do
|
142
|
+
expect(msgs1.size).to eq(4)
|
143
|
+
expect(msgs2.size).to eq(0)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'supports multiple subscriptions on a given destination and distributes the messages between them' do
|
149
|
+
msgs1 = []
|
150
|
+
msgs2 = []
|
151
|
+
|
152
|
+
destination.subscribe do |msg|
|
153
|
+
msgs1 << msg
|
154
|
+
end
|
155
|
+
|
156
|
+
destination.subscribe do |msg|
|
157
|
+
msgs2 << msg
|
158
|
+
end
|
159
|
+
|
160
|
+
4.times { destination.publish('a message') }
|
161
|
+
|
162
|
+
aggregate_failures do
|
163
|
+
expect(msgs1.size).to eq(2)
|
164
|
+
expect(msgs2.size).to eq(2)
|
165
|
+
end
|
166
|
+
end
|
127
167
|
end
|
128
168
|
end
|
129
169
|
end
|
@@ -5,7 +5,6 @@ require 'message_driver/adapters/stomp_adapter'
|
|
5
5
|
module MessageDriver
|
6
6
|
module Adapters
|
7
7
|
RSpec.describe StompAdapter, :stomp, type: :integration do
|
8
|
-
|
9
8
|
let(:valid_connection_attrs) { BrokerConfig.config }
|
10
9
|
|
11
10
|
describe '#initialize' do
|
@@ -113,7 +112,6 @@ module MessageDriver
|
|
113
112
|
it_behaves_like 'subscriptions are not supported'
|
114
113
|
|
115
114
|
describe '#create_destination' do
|
116
|
-
|
117
115
|
context 'the resulting destination' do
|
118
116
|
let(:dest_name) { '/queue/stomp_destination_spec' }
|
119
117
|
subject(:destination) { adapter_context.create_destination(dest_name) }
|
data/spec/spec_helper.rb
CHANGED
@@ -1,18 +1,40 @@
|
|
1
1
|
RSpec.shared_examples 'client acks are supported' do
|
2
|
-
describe '#supports_client_acks' do
|
2
|
+
describe '#supports_client_acks?' do
|
3
3
|
it 'returns true' do
|
4
4
|
expect(subject.supports_client_acks?).to eq(true)
|
5
5
|
end
|
6
6
|
end
|
7
7
|
|
8
|
-
it { is_expected.to
|
9
|
-
it { is_expected.
|
8
|
+
it { is_expected.to override_method :handle_ack_message }
|
9
|
+
it { is_expected.not_to override_method :ack_message }
|
10
|
+
it { is_expected.to override_method :handle_nack_message }
|
11
|
+
it { is_expected.not_to override_method :nack_message }
|
10
12
|
end
|
11
13
|
|
12
14
|
RSpec.shared_examples 'client acks are not supported' do
|
13
|
-
|
15
|
+
it { is_expected.not_to override_method :handle_ack_message }
|
16
|
+
it { is_expected.not_to override_method :handle_nack_message }
|
17
|
+
describe '#supports_client_acks?' do
|
14
18
|
it 'returns false' do
|
15
19
|
expect(subject.supports_client_acks?).to eq(false)
|
16
20
|
end
|
17
21
|
end
|
22
|
+
|
23
|
+
describe '#ack_message' do
|
24
|
+
it 'raises an error' do
|
25
|
+
message = double('message')
|
26
|
+
expect do
|
27
|
+
subject.ack_message(message)
|
28
|
+
end.to raise_error "#ack_message is not supported by #{subject.adapter.class}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#nack_message' do
|
33
|
+
it 'raises an error' do
|
34
|
+
message = double('message')
|
35
|
+
expect do
|
36
|
+
subject.nack_message(message)
|
37
|
+
end.to raise_error "#nack_message is not supported by #{subject.adapter.class}"
|
38
|
+
end
|
39
|
+
end
|
18
40
|
end
|
@@ -5,6 +5,52 @@ RSpec.shared_examples 'an adapter context' do
|
|
5
5
|
it { expect(subject.adapter).to be adapter }
|
6
6
|
end
|
7
7
|
|
8
|
+
describe 'interface' do
|
9
|
+
it { is_expected.to respond_to(:create_destination).with(1..3).arguments }
|
10
|
+
it { is_expected.to respond_to(:handle_create_destination).with(1..3).arguments }
|
11
|
+
|
12
|
+
it { is_expected.to respond_to(:publish).with(2..4).arguments }
|
13
|
+
it { is_expected.to respond_to(:handle_publish).with(2..4).arguments }
|
14
|
+
|
15
|
+
it { is_expected.to respond_to(:pop_message).with(1..2).arguments }
|
16
|
+
it { is_expected.to respond_to(:handle_pop_message).with(1..2).arguments }
|
17
|
+
|
18
|
+
it { is_expected.to respond_to(:subscribe).with(1..2).arguments }
|
19
|
+
it { is_expected.to respond_to(:handle_subscribe).with(1..2).arguments }
|
20
|
+
|
21
|
+
it { is_expected.to respond_to(:ack_message).with(1..2).arguments }
|
22
|
+
it { is_expected.to respond_to(:handle_ack_message).with(1..2).arguments }
|
23
|
+
it { is_expected.to respond_to(:nack_message).with(1..2).arguments }
|
24
|
+
it { is_expected.to respond_to(:handle_nack_message).with(1..2).arguments }
|
25
|
+
|
26
|
+
it { is_expected.to respond_to(:begin_transaction).with(0..1).arguments }
|
27
|
+
it { is_expected.to respond_to(:handle_begin_transaction).with(0..1).arguments }
|
28
|
+
it { is_expected.to respond_to(:commit_transaction).with(0..1).arguments }
|
29
|
+
it { is_expected.to respond_to(:handle_commit_transaction).with(0..1).arguments }
|
30
|
+
it { is_expected.to respond_to(:rollback_transaction).with(0..1).arguments }
|
31
|
+
it { is_expected.to respond_to(:handle_rollback_transaction).with(0..1).arguments }
|
32
|
+
it { is_expected.to respond_to(:in_transaction?).with(0).arguments }
|
33
|
+
|
34
|
+
it { is_expected.to respond_to(:message_count).with(1).arguments }
|
35
|
+
it { is_expected.to respond_to(:handle_message_count).with(1).arguments }
|
36
|
+
it { is_expected.to respond_to(:consumer_count).with(1).arguments }
|
37
|
+
it { is_expected.to respond_to(:handle_consumer_count).with(1).arguments }
|
38
|
+
|
39
|
+
describe 'overrides' do
|
40
|
+
it { expect(subject.class).not_to override_method(:create_destination) }
|
41
|
+
it { expect(subject.class).to override_method(:handle_create_destination) }
|
42
|
+
|
43
|
+
it { expect(subject.class).not_to override_method(:publish) }
|
44
|
+
it { expect(subject.class).to override_method(:handle_publish) }
|
45
|
+
|
46
|
+
it { expect(subject.class).not_to override_method(:pop_message) }
|
47
|
+
it { expect(subject.class).to override_method(:handle_pop_message) }
|
48
|
+
|
49
|
+
it { expect(subject.class).not_to override_method(:message_count) }
|
50
|
+
it { expect(subject.class).not_to override_method(:consumer_count) }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
8
54
|
it 'is initially valid' do
|
9
55
|
is_expected.to be_valid
|
10
56
|
end
|
@@ -17,6 +17,14 @@ RSpec.shared_examples 'a destination' do
|
|
17
17
|
|
18
18
|
it { is_expected.to be_a MessageDriver::Message::Base }
|
19
19
|
|
20
|
+
it 'has a reference to the context that fetched it' do
|
21
|
+
expect(message.ctx).to be_a MessageDriver::Adapters::ContextBase
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'has a reference to the destination that it was fetched from' do
|
25
|
+
expect(message.destination).to be_a MessageDriver::Destination::Base
|
26
|
+
end
|
27
|
+
|
20
28
|
describe '#body' do
|
21
29
|
it { expect(subject.body).to eq(body) }
|
22
30
|
end
|
@@ -30,6 +38,14 @@ RSpec.shared_examples 'a destination' do
|
|
30
38
|
end
|
31
39
|
end
|
32
40
|
end
|
41
|
+
|
42
|
+
context 'interface' do
|
43
|
+
it { is_expected.to respond_to(:publish).with(1..3).arguments }
|
44
|
+
it { is_expected.to respond_to(:pop_message).with(0..1).arguments }
|
45
|
+
it { is_expected.to respond_to(:message_count).with(0).arguments }
|
46
|
+
it { is_expected.to respond_to(:subscribe).with(0..1).arguments }
|
47
|
+
it { is_expected.to respond_to(:consumer_count).with(0).arguments }
|
48
|
+
end
|
33
49
|
end
|
34
50
|
|
35
51
|
RSpec.shared_examples "doesn't support #message_count" do
|
@@ -50,6 +66,12 @@ RSpec.shared_examples 'supports #message_count' do
|
|
50
66
|
pause_if_needed
|
51
67
|
end.to change { destination.message_count }.by(2)
|
52
68
|
end
|
69
|
+
|
70
|
+
it { is_expected.not_to override_method :message_count }
|
71
|
+
|
72
|
+
it 'the adapter context overrides #handle_message_count' do
|
73
|
+
expect(subject.adapter.broker.client.current_adapter_context).to override_method :handle_message_count
|
74
|
+
end
|
53
75
|
end
|
54
76
|
|
55
77
|
RSpec.shared_examples "doesn't support #consumer_count" do
|
@@ -79,4 +101,10 @@ RSpec.shared_examples 'supports #consumer_count' do
|
|
79
101
|
end.to change { destination.consumer_count }.by(-2)
|
80
102
|
end
|
81
103
|
end
|
104
|
+
|
105
|
+
it { is_expected.not_to override_method :consumer_count }
|
106
|
+
|
107
|
+
it 'the adapter context overrides #handle_consumer_count' do
|
108
|
+
expect(subject.adapter.broker.client.current_adapter_context).to override_method :handle_message_count
|
109
|
+
end
|
82
110
|
end
|
@@ -5,6 +5,8 @@ RSpec.shared_examples 'subscriptions are not supported' do
|
|
5
5
|
end
|
6
6
|
end
|
7
7
|
|
8
|
+
it { is_expected.not_to override_method(:handle_subscribe) }
|
9
|
+
|
8
10
|
describe '#subscribe' do
|
9
11
|
it 'raises an error' do
|
10
12
|
destination = double('destination')
|
@@ -23,6 +25,8 @@ RSpec.shared_examples 'subscriptions are supported' do |subscription_type|
|
|
23
25
|
end
|
24
26
|
end
|
25
27
|
|
28
|
+
it { is_expected.to override_method(:handle_subscribe) }
|
29
|
+
|
26
30
|
let(:destination) { adapter_context.create_destination('subscriptions_example_queue') }
|
27
31
|
|
28
32
|
let(:message1) { 'message 1' }
|
@@ -87,6 +91,7 @@ RSpec.shared_examples 'subscriptions are supported' do |subscription_type|
|
|
87
91
|
subscription
|
88
92
|
pause_if_needed
|
89
93
|
end.to change { messages.size }.from(0).to(2)
|
94
|
+
expect(messages.map(&:destination)).to all(be_a(MessageDriver::Destination::Base))
|
90
95
|
bodies = messages.map(&:body)
|
91
96
|
expect(bodies).to include(message1)
|
92
97
|
expect(bodies).to include(message2)
|
@@ -121,7 +126,7 @@ RSpec.shared_examples 'subscriptions are supported' do |subscription_type|
|
|
121
126
|
let(:error) { RuntimeError.new('oh nos!') }
|
122
127
|
let(:consumer) do
|
123
128
|
lambda do |_|
|
124
|
-
|
129
|
+
raise error
|
125
130
|
end
|
126
131
|
end
|
127
132
|
|
@@ -4,6 +4,34 @@ RSpec.shared_examples 'transactions are not supported' do
|
|
4
4
|
expect(subject.supports_transactions?).to eq(false)
|
5
5
|
end
|
6
6
|
end
|
7
|
+
|
8
|
+
describe '#begin_transaction' do
|
9
|
+
it 'raises an error' do
|
10
|
+
expect do
|
11
|
+
subject.begin_transaction
|
12
|
+
end.to raise_error "transactions are not supported by #{subject.adapter.class}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#commit_transaction' do
|
17
|
+
it 'raises an error' do
|
18
|
+
expect do
|
19
|
+
subject.commit_transaction
|
20
|
+
end.to raise_error "transactions are not supported by #{subject.adapter.class}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '#rollback_transaction' do
|
25
|
+
it 'raises an error' do
|
26
|
+
expect do
|
27
|
+
subject.rollback_transaction
|
28
|
+
end.to raise_error "transactions are not supported by #{subject.adapter.class}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
it { is_expected.not_to override_method :handle_begin_transaction }
|
33
|
+
it { is_expected.not_to override_method :handle_commit_transaction }
|
34
|
+
it { is_expected.not_to override_method :handle_rollback_transaction }
|
7
35
|
end
|
8
36
|
|
9
37
|
RSpec.shared_examples 'transactions are supported' do
|
@@ -13,10 +41,13 @@ RSpec.shared_examples 'transactions are supported' do
|
|
13
41
|
end
|
14
42
|
end
|
15
43
|
|
16
|
-
it { is_expected.to
|
17
|
-
it { is_expected.
|
18
|
-
it { is_expected.to
|
19
|
-
it { is_expected.
|
44
|
+
it { is_expected.to override_method :handle_begin_transaction }
|
45
|
+
it { is_expected.not_to override_method :begin_transaction }
|
46
|
+
it { is_expected.to override_method :handle_commit_transaction }
|
47
|
+
it { is_expected.not_to override_method :commit_transaction }
|
48
|
+
it { is_expected.to override_method :handle_rollback_transaction }
|
49
|
+
it { is_expected.not_to override_method :rollback_transaction }
|
50
|
+
it { is_expected.to override_method :in_transaction? }
|
20
51
|
|
21
52
|
describe '#in_transaction?' do
|
22
53
|
it "returns false if you aren't in a transaction" do
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module MessageDriver
|
2
|
+
class TestAdapter < Adapters::Base
|
3
|
+
def initialize(broker, _config)
|
4
|
+
@broker = broker
|
5
|
+
end
|
6
|
+
|
7
|
+
def build_context
|
8
|
+
TestContext.new(self)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class TestContext < Adapters::ContextBase
|
13
|
+
def handle_create_destination(_name, _dest_options = nil, _message_props = nil); end
|
14
|
+
|
15
|
+
def handle_publish(_destination, _body, _dest_options = nil, _message_props = nil); end
|
16
|
+
|
17
|
+
def handle_pop_message(_destination, _options = nil); end
|
18
|
+
end
|
19
|
+
end
|
data/spec/support/utils.rb
CHANGED
@@ -3,11 +3,12 @@ require 'spec_helper'
|
|
3
3
|
module MessageDriver
|
4
4
|
module Adapters
|
5
5
|
RSpec.describe Base do
|
6
|
-
|
7
|
-
|
6
|
+
let(:spec_adapter_class) do
|
7
|
+
Class.new(described_class) do
|
8
|
+
def initialize; end
|
8
9
|
end
|
9
10
|
end
|
10
|
-
subject(:adapter) {
|
11
|
+
subject(:adapter) { spec_adapter_class.new }
|
11
12
|
|
12
13
|
describe '#new_context' do
|
13
14
|
it 'raises an error' do
|
@@ -17,40 +18,45 @@ module MessageDriver
|
|
17
18
|
end
|
18
19
|
end
|
19
20
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
it 'raises an error' do
|
32
|
-
expect do
|
33
|
-
subject.create_destination('foo')
|
34
|
-
end.to raise_error 'Must be implemented in subclass'
|
21
|
+
context 'with a test adapter' do
|
22
|
+
subject(:adapter) { TestAdapter.new(nil, {}) }
|
23
|
+
|
24
|
+
describe ContextBase do
|
25
|
+
context 'with a test context subclass' do
|
26
|
+
subject(:adapter_context) { TestContext.new(adapter) }
|
27
|
+
|
28
|
+
it_behaves_like 'an adapter context'
|
29
|
+
it_behaves_like 'transactions are not supported'
|
30
|
+
it_behaves_like 'client acks are not supported'
|
31
|
+
it_behaves_like 'subscriptions are not supported'
|
35
32
|
end
|
36
|
-
end
|
37
33
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
34
|
+
subject(:adapter_context) { ContextBase.new(adapter) }
|
35
|
+
|
36
|
+
describe '#create_destination' do
|
37
|
+
it 'raises an error' do
|
38
|
+
expect do
|
39
|
+
subject.create_destination('foo')
|
40
|
+
end.to raise_error 'Must be implemented in subclass'
|
41
|
+
end
|
43
42
|
end
|
44
|
-
end
|
45
43
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
44
|
+
describe '#publish' do
|
45
|
+
it 'raises an error' do
|
46
|
+
expect do
|
47
|
+
subject.publish(:destination, foo: 'bar')
|
48
|
+
end.to raise_error 'Must be implemented in subclass'
|
49
|
+
end
|
51
50
|
end
|
52
|
-
end
|
53
51
|
|
52
|
+
describe '#pop_message' do
|
53
|
+
it 'raises an error' do
|
54
|
+
expect do
|
55
|
+
subject.pop_message(:destination)
|
56
|
+
end.to raise_error 'Must be implemented in subclass'
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
54
60
|
end
|
55
61
|
end
|
56
62
|
end
|