message-driver 0.4.0 → 0.5.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.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/.coveralls.yml +2 -0
  3. data/.rubocop.yml +26 -2
  4. data/.rubocop_todo.yml +15 -123
  5. data/.travis.yml +2 -1
  6. data/CHANGELOG.md +10 -1
  7. data/Gemfile +15 -6
  8. data/Rakefile +23 -12
  9. data/ci/reset_vhost +8 -3
  10. data/ci/travis_setup +0 -3
  11. data/features/.nav +6 -1
  12. data/features/CHANGELOG.md +10 -1
  13. data/features/amqp_specific_features/binding_amqp_destinations.feature +1 -0
  14. data/features/amqp_specific_features/declaring_amqp_exchanges.feature +1 -0
  15. data/features/amqp_specific_features/server_named_destinations.feature +1 -0
  16. data/features/destination_metadata.feature +26 -0
  17. data/features/logging.feature +1 -1
  18. data/features/middleware/middleware_basics.feature +91 -0
  19. data/features/middleware/middleware_ordering.feature +60 -0
  20. data/features/middleware/middleware_parameters.feature +43 -0
  21. data/features/middleware/middleware_with_blocks.feature +85 -0
  22. data/features/step_definitions/dynamic_destinations_steps.rb +1 -1
  23. data/features/step_definitions/message_consumers_steps.rb +5 -0
  24. data/features/step_definitions/middleware_steps.rb +10 -0
  25. data/features/step_definitions/steps.rb +10 -2
  26. data/features/support/env.rb +4 -3
  27. data/features/support/firewall_helper.rb +1 -1
  28. data/features/support/message_table_matcher.rb +3 -2
  29. data/features/support/no_error_matcher.rb +2 -2
  30. data/features/support/test_runner.rb +11 -57
  31. data/features/support/transforms.rb +12 -10
  32. data/lib/message_driver.rb +3 -1
  33. data/lib/message_driver/adapters/base.rb +11 -11
  34. data/lib/message_driver/adapters/bunny_adapter.rb +189 -132
  35. data/lib/message_driver/adapters/in_memory_adapter.rb +51 -34
  36. data/lib/message_driver/adapters/stomp_adapter.rb +22 -23
  37. data/lib/message_driver/broker.rb +21 -16
  38. data/lib/message_driver/client.rb +15 -16
  39. data/lib/message_driver/destination.rb +26 -8
  40. data/lib/message_driver/message.rb +5 -4
  41. data/lib/message_driver/middleware.rb +8 -0
  42. data/lib/message_driver/middleware/base.rb +19 -0
  43. data/lib/message_driver/middleware/block_middleware.rb +33 -0
  44. data/lib/message_driver/middleware/middleware_stack.rb +61 -0
  45. data/lib/message_driver/subscription.rb +2 -2
  46. data/lib/message_driver/version.rb +1 -1
  47. data/message-driver.gemspec +3 -4
  48. data/spec/integration/bunny/amqp_integration_spec.rb +21 -82
  49. data/spec/integration/bunny/bunny_adapter_spec.rb +288 -268
  50. data/spec/integration/in_memory/in_memory_adapter_spec.rb +93 -90
  51. data/spec/integration/stomp/stomp_adapter_spec.rb +126 -93
  52. data/spec/spec_helper.rb +11 -9
  53. data/spec/support/shared/adapter_examples.rb +1 -1
  54. data/spec/support/shared/client_ack_examples.rb +4 -4
  55. data/spec/support/shared/context_examples.rb +6 -4
  56. data/spec/support/shared/destination_examples.rb +54 -14
  57. data/spec/support/shared/subscription_examples.rb +33 -26
  58. data/spec/support/shared/transaction_examples.rb +12 -12
  59. data/spec/support/utils.rb +1 -1
  60. data/spec/units/message_driver/adapters/base_spec.rb +42 -40
  61. data/spec/units/message_driver/broker_spec.rb +38 -38
  62. data/spec/units/message_driver/client_spec.rb +87 -87
  63. data/spec/units/message_driver/destination_spec.rb +16 -11
  64. data/spec/units/message_driver/message_spec.rb +96 -70
  65. data/spec/units/message_driver/middleware/base_spec.rb +30 -0
  66. data/spec/units/message_driver/middleware/block_middleware_spec.rb +82 -0
  67. data/spec/units/message_driver/middleware/middleware_stack_spec.rb +165 -0
  68. data/spec/units/message_driver/subscription_spec.rb +18 -16
  69. data/test_lib/broker_config.rb +21 -5
  70. data/test_lib/coverage.rb +11 -0
  71. data/test_lib/provider/base.rb +59 -0
  72. data/test_lib/provider/in_memory.rb +6 -0
  73. data/test_lib/provider/rabbitmq.rb +67 -0
  74. metadata +46 -35
data/spec/spec_helper.rb CHANGED
@@ -1,29 +1,29 @@
1
- require 'coveralls'
2
- Coveralls.wear!
1
+ ENV['COMMAND_NAME'] = 'specs'
2
+ require File.join(File.dirname(__FILE__), '..', 'test_lib', 'coverage')
3
+ require File.join(File.dirname(__FILE__), '..', 'test_lib', 'broker_config')
3
4
 
4
5
  require 'message_driver'
5
6
 
6
- require File.join(File.dirname(__FILE__), '..', 'test_lib', 'broker_config')
7
+ BrokerConfig.setup_provider
7
8
 
8
- Dir['./spec/support/**/*.rb'].sort.each {|f| require f}
9
+ Dir['./spec/support/**/*.rb'].sort.each { |f| require f }
9
10
 
10
11
  RSpec.configure do |c|
11
- c.treat_symbols_as_metadata_keys_with_true_values = true
12
- c.order = 'random'
12
+ c.order = :random
13
13
  c.filter_run :focus
14
14
 
15
15
  c.reporter.message("Acceptance Tests running with broker config: #{BrokerConfig.config}")
16
16
 
17
17
  spec_logger = Logger.new(STDOUT).tap { |l| l.level = Logger::FATAL }
18
- c.before(:each) do
18
+ c.before(:example) do
19
19
  MessageDriver.logger = spec_logger
20
20
  end
21
21
 
22
- c.after(:each) do
22
+ c.after(:example) do
23
23
  MessageDriver::Broker.reset
24
24
  end
25
25
 
26
- c.filter_run_excluding :no_ci if ENV['CI']=='true' && ENV['ADAPTER'] && ENV['ADAPTER'].start_with?('bunny')
26
+ c.filter_run_excluding :no_ci if ENV['CI'] == 'true' && ENV['ADAPTER'] && ENV['ADAPTER'].start_with?('bunny')
27
27
  if c.inclusion_filter[:all_adapters] == true
28
28
  BrokerConfig.unconfigured_adapters.each do |a|
29
29
  c.filter_run_excluding a
@@ -32,4 +32,6 @@ RSpec.configure do |c|
32
32
  else
33
33
  c.run_all_when_everything_filtered = true
34
34
  end
35
+
36
+ c.expose_dsl_globally = false
35
37
  end
@@ -1,4 +1,4 @@
1
- shared_examples 'an adapter' do
1
+ RSpec.shared_examples 'an adapter' do
2
2
  describe '#new_context' do
3
3
  it 'returns a MessageDriver::Adapters::ContextBase' do
4
4
  expect(subject.new_context).to be_a MessageDriver::Adapters::ContextBase
@@ -1,15 +1,15 @@
1
- shared_examples 'client acks are supported' do
1
+ RSpec.shared_examples 'client acks are supported' do
2
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 { should respond_to :ack_message }
9
- it { should respond_to :nack_message }
8
+ it { is_expected.to respond_to :ack_message }
9
+ it { is_expected.to respond_to :nack_message }
10
10
  end
11
11
 
12
- shared_examples 'client acks are not supported' do
12
+ RSpec.shared_examples 'client acks are not supported' do
13
13
  describe '#supports_client_acks' do
14
14
  it 'returns false' do
15
15
  expect(subject.supports_client_acks?).to eq(false)
@@ -1,10 +1,12 @@
1
- shared_examples 'an adapter context' do
2
- it { should be_a MessageDriver::Adapters::ContextBase }
1
+ RSpec.shared_examples 'an adapter context' do
2
+ it { is_expected.to be_a MessageDriver::Adapters::ContextBase }
3
3
 
4
- its(:adapter) { should be adapter }
4
+ describe '#adapter' do
5
+ it { expect(subject.adapter).to be adapter }
6
+ end
5
7
 
6
8
  it 'is initially valid' do
7
- should be_valid
9
+ is_expected.to be_valid
8
10
  end
9
11
 
10
12
  describe '#invalidate' do
@@ -1,10 +1,12 @@
1
- shared_examples 'a destination' do
2
- its(:adapter) { should be adapter }
1
+ RSpec.shared_examples 'a destination' do
2
+ describe '#adapter' do
3
+ it { expect(subject.adapter).to be adapter }
4
+ end
3
5
 
4
6
  describe '#pop_message' do
5
7
  let(:body) { 'The message body' }
6
- let(:headers) { { 'foo' => 'bar', 'bar' => 'baz'} }
7
- let(:properties) { {persistent: true, client_ack: true} }
8
+ let(:headers) { { 'foo' => 'bar', 'bar' => 'baz' } }
9
+ let(:properties) { { persistent: true, client_ack: true } }
8
10
 
9
11
  before do
10
12
  destination.publish(body, headers, properties)
@@ -13,30 +15,68 @@ shared_examples 'a destination' do
13
15
  context 'the result' do
14
16
  subject(:message) { destination.pop_message }
15
17
 
16
- it { should be_a MessageDriver::Message::Base }
17
- its(:body) { should eq(body) }
18
- its(:headers) { should include(headers) }
19
- its(:properties) { should_not be_nil }
18
+ it { is_expected.to be_a MessageDriver::Message::Base }
19
+
20
+ describe '#body' do
21
+ it { expect(subject.body).to eq(body) }
22
+ end
23
+
24
+ describe '#headers' do
25
+ it { expect(subject.headers).to include(headers) }
26
+ end
27
+
28
+ describe '#properties' do
29
+ it { expect(subject.properties).not_to be_nil }
30
+ end
20
31
  end
21
32
  end
22
33
  end
23
34
 
24
- shared_examples "doesn't support #message_count" do
35
+ RSpec.shared_examples "doesn't support #message_count" do
25
36
  describe '#message_count' do
26
37
  it 'raises an error' do
27
- expect {
38
+ expect do
28
39
  destination.message_count
29
- }.to raise_error "#message_count is not supported by #{destination.class}"
40
+ end.to raise_error "#message_count is not supported by #{destination.class}"
30
41
  end
31
42
  end
32
43
  end
33
44
 
34
- shared_examples 'supports #message_count' do
45
+ RSpec.shared_examples 'supports #message_count' do
35
46
  it "reports it's message_count" do
36
- expect {
47
+ expect do
37
48
  destination.publish('msg1')
38
49
  destination.publish('msg2')
39
50
  pause_if_needed
40
- }.to change{destination.message_count}.by(2)
51
+ end.to change { destination.message_count }.by(2)
52
+ end
53
+ end
54
+
55
+ RSpec.shared_examples "doesn't support #consumer_count" do
56
+ describe '#consumer_count' do
57
+ it 'raises an error' do
58
+ expect do
59
+ destination.consumer_count
60
+ end.to raise_error "#consumer_count is not supported by #{destination.class}"
61
+ end
62
+ end
63
+ end
64
+
65
+ RSpec.shared_examples 'supports #consumer_count' do
66
+ describe '#consumer_count' do
67
+ it "reports it's consumer count" do
68
+ consumer1 = ->(_) {}
69
+ consumer2 = ->(_) {}
70
+ sub1 = nil
71
+ sub2 = nil
72
+ expect do
73
+ sub1 = destination.subscribe(&consumer1)
74
+ sub2 = destination.subscribe(&consumer2)
75
+ end.to change { destination.consumer_count }.by(2)
76
+ expect do
77
+ sub1.unsubscribe
78
+ sub2.unsubscribe
79
+ end.to change { destination.consumer_count }.by(-2)
80
+ end
41
81
  end
42
82
  end
@@ -1,4 +1,4 @@
1
- shared_examples 'subscriptions are not supported' do
1
+ RSpec.shared_examples 'subscriptions are not supported' do
2
2
  describe '#supports_subscriptions?' do
3
3
  it 'returns false' do
4
4
  expect(subject.supports_subscriptions?).to eq(false)
@@ -8,15 +8,15 @@ shared_examples 'subscriptions are not supported' do
8
8
  describe '#subscribe' do
9
9
  it 'raises an error' do
10
10
  destination = double('destination')
11
- consumer = lambda do |_| end
12
- expect {
11
+ consumer = ->(_) {}
12
+ expect do
13
13
  subject.subscribe(destination, &consumer)
14
- }.to raise_error "#subscribe is not supported by #{subject.adapter.class}"
14
+ end.to raise_error "#subscribe is not supported by #{subject.adapter.class}"
15
15
  end
16
16
  end
17
17
  end
18
18
 
19
- shared_examples 'subscriptions are supported' do |subscription_type|
19
+ RSpec.shared_examples 'subscriptions are supported' do |subscription_type|
20
20
  describe '#supports_subscriptions?' do
21
21
  it 'returns true' do
22
22
  expect(subject.supports_subscriptions?).to eq(true)
@@ -36,9 +36,7 @@ shared_examples 'subscriptions are supported' do |subscription_type|
36
36
 
37
37
  describe '#subscribe' do
38
38
  before do
39
- if destination.respond_to? :purge
40
- destination.purge
41
- end
39
+ destination.purge if destination.respond_to? :purge
42
40
  end
43
41
 
44
42
  let(:subscription) { adapter_context.subscribe(destination, &consumer) }
@@ -53,18 +51,27 @@ shared_examples 'subscriptions are supported' do |subscription_type|
53
51
  context 'the subscription' do
54
52
  subject { subscription }
55
53
 
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 }
54
+ it { is_expected.to be_a MessageDriver::Subscription::Base }
55
+ it { is_expected.to be_a subscription_type }
56
+
57
+ describe '#adapter' do
58
+ it { expect(subject.adapter).to be adapter }
59
+ end
60
+
61
+ describe '#destination' do
62
+ it { expect(subject.destination).to be destination }
63
+ end
64
+
65
+ describe '#consumer' do
66
+ it { expect(subject.consumer).to be consumer }
67
+ end
61
68
 
62
69
  describe '#unsubscribe' do
63
70
  it "makes it so messages don't go to the consumer any more" do
64
71
  subscription.unsubscribe
65
- expect {
72
+ expect do
66
73
  destination.publish('should not be consumed')
67
- }.to_not change{messages.size}
74
+ end.to_not change { messages.size }
68
75
  end
69
76
  end
70
77
  end
@@ -76,10 +83,10 @@ shared_examples 'subscriptions are supported' do |subscription_type|
76
83
  end
77
84
 
78
85
  it 'plays the messages into the consumer' do
79
- expect {
86
+ expect do
80
87
  subscription
81
88
  pause_if_needed
82
- }.to change{messages.size}.from(0).to(2)
89
+ end.to change { messages.size }.from(0).to(2)
83
90
  bodies = messages.map(&:body)
84
91
  expect(bodies).to include(message1)
85
92
  expect(bodies).to include(message2)
@@ -87,10 +94,10 @@ shared_examples 'subscriptions are supported' do |subscription_type|
87
94
 
88
95
  it 'removes the messages from the queue' do
89
96
  pause_if_needed
90
- expect {
97
+ expect do
91
98
  subscription
92
99
  pause_if_needed
93
- }.to change{destination.message_count}.from(2).to(0)
100
+ end.to change { destination.message_count }.from(2).to(0)
94
101
  end
95
102
  end
96
103
 
@@ -100,12 +107,12 @@ shared_examples 'subscriptions are supported' do |subscription_type|
100
107
  end
101
108
 
102
109
  it 'consumers the message into the consumer instead of putting them on the queue' do
103
- expect {
104
- expect {
110
+ expect do
111
+ expect do
105
112
  subject.publish(destination, message1)
106
113
  pause_if_needed
107
- }.to change{messages.length}.from(0).to(1)
108
- }.to_not change{destination.message_count}
114
+ end.to change { messages.length }.from(0).to(1)
115
+ end.to_not change { destination.message_count }
109
116
  expect(messages[0].body).to eq(message1)
110
117
  end
111
118
  end
@@ -114,7 +121,7 @@ shared_examples 'subscriptions are supported' do |subscription_type|
114
121
  let(:error) { RuntimeError.new('oh nos!') }
115
122
  let(:consumer) do
116
123
  lambda do |_|
117
- raise error
124
+ fail error
118
125
  end
119
126
  end
120
127
 
@@ -125,10 +132,10 @@ shared_examples 'subscriptions are supported' do |subscription_type|
125
132
 
126
133
  it 'keeps processing the messages' do
127
134
  pause_if_needed
128
- expect {
135
+ expect do
129
136
  subscription
130
137
  pause_if_needed
131
- }.to change{destination.message_count}.from(2).to(0)
138
+ end.to change { destination.message_count }.from(2).to(0)
132
139
  end
133
140
 
134
141
  context 'an error_handler is provided' do
@@ -1,4 +1,4 @@
1
- shared_examples 'transactions are not supported' do
1
+ RSpec.shared_examples 'transactions are not supported' do
2
2
  describe '#supports_transactions?' do
3
3
  it 'returns false' do
4
4
  expect(subject.supports_transactions?).to eq(false)
@@ -6,17 +6,17 @@ shared_examples 'transactions are not supported' do
6
6
  end
7
7
  end
8
8
 
9
- shared_examples 'transactions are supported' do
9
+ RSpec.shared_examples 'transactions are supported' do
10
10
  describe '#supports_transactions?' do
11
11
  it 'returns true' do
12
12
  expect(subject.supports_transactions?).to eq(true)
13
13
  end
14
14
  end
15
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? }
16
+ it { is_expected.to respond_to :begin_transaction }
17
+ it { is_expected.to respond_to :commit_transaction }
18
+ it { is_expected.to respond_to :rollback_transaction }
19
+ it { is_expected.to respond_to :in_transaction? }
20
20
 
21
21
  describe '#in_transaction?' do
22
22
  it "returns false if you aren't in a transaction" do
@@ -26,18 +26,18 @@ shared_examples 'transactions are supported' do
26
26
 
27
27
  it 'raises a MessageDriver::TransactionError error if you begin two transactions' do
28
28
  subject.begin_transaction
29
- expect {
29
+ expect do
30
30
  subject.begin_transaction
31
- }.to raise_error MessageDriver::TransactionError
31
+ end.to raise_error MessageDriver::TransactionError
32
32
  end
33
33
  it 'raises a MessageDriver::TransactionError error if you commit outside of a transaction' do
34
- expect {
34
+ expect do
35
35
  subject.commit_transaction
36
- }.to raise_error MessageDriver::TransactionError
36
+ end.to raise_error MessageDriver::TransactionError
37
37
  end
38
38
  it 'raises a MessageDriver::TransactionError error if you rollback outside of a transaction' do
39
- expect {
39
+ expect do
40
40
  subject.rollback_transaction
41
- }.to raise_error MessageDriver::TransactionError
41
+ end.to raise_error MessageDriver::TransactionError
42
42
  end
43
43
  end
@@ -1,5 +1,5 @@
1
1
  module Utils
2
- def pause_if_needed(seconds=0.1)
2
+ def pause_if_needed(seconds = 0.1)
3
3
  seconds *= 10 if ENV['CI'] == 'true'
4
4
  case BrokerConfig.current_adapter
5
5
  when :in_memory
@@ -1,55 +1,57 @@
1
1
  require 'spec_helper'
2
2
 
3
- module MessageDriver::Adapters
4
- describe Base do
5
- class TestAdapter < Base
6
- def initialize(_configuration)
7
- end
8
- end
9
- subject(:adapter) { TestAdapter.new({}) }
10
-
11
- describe '#new_context' do
12
- it 'raises an error' do
13
- expect {
14
- subject.new_context
15
- }.to raise_error 'Must be implemented in subclass'
16
- end
17
- end
18
-
19
- describe ContextBase do
20
- class TestContext < ContextBase
3
+ module MessageDriver
4
+ module Adapters
5
+ RSpec.describe Base do
6
+ class TestAdapter < Base
7
+ def initialize(_configuration)
8
+ end
21
9
  end
22
- subject(:adapter_context) { TestContext.new(adapter) }
23
-
24
- it_behaves_like 'an adapter context'
25
- it_behaves_like 'transactions are not supported'
26
- it_behaves_like 'client acks are not supported'
27
- it_behaves_like 'subscriptions are not supported'
10
+ subject(:adapter) { TestAdapter.new({}) }
28
11
 
29
- describe '#create_destination' do
12
+ describe '#new_context' do
30
13
  it 'raises an error' do
31
- expect {
32
- subject.create_destination('foo')
33
- }.to raise_error 'Must be implemented in subclass'
14
+ expect do
15
+ subject.new_context
16
+ end.to raise_error 'Must be implemented in subclass'
34
17
  end
35
18
  end
36
19
 
37
- describe '#publish' do
38
- it 'raises an error' do
39
- expect {
40
- subject.publish(:destination, foo: 'bar')
41
- }.to raise_error 'Must be implemented in subclass'
20
+ describe ContextBase do
21
+ class TestContext < ContextBase
22
+ end
23
+ subject(:adapter_context) { TestContext.new(adapter) }
24
+
25
+ it_behaves_like 'an adapter context'
26
+ it_behaves_like 'transactions are not supported'
27
+ it_behaves_like 'client acks are not supported'
28
+ it_behaves_like 'subscriptions are not supported'
29
+
30
+ describe '#create_destination' do
31
+ it 'raises an error' do
32
+ expect do
33
+ subject.create_destination('foo')
34
+ end.to raise_error 'Must be implemented in subclass'
35
+ end
42
36
  end
43
- end
44
37
 
45
- describe '#pop_message' do
46
- it 'raises an error' do
47
- expect {
48
- subject.pop_message(:destination)
49
- }.to raise_error 'Must be implemented in subclass'
38
+ describe '#publish' do
39
+ it 'raises an error' do
40
+ expect do
41
+ subject.publish(:destination, foo: 'bar')
42
+ end.to raise_error 'Must be implemented in subclass'
43
+ end
44
+ end
45
+
46
+ describe '#pop_message' do
47
+ it 'raises an error' do
48
+ expect do
49
+ subject.pop_message(:destination)
50
+ end.to raise_error 'Must be implemented in subclass'
51
+ end
50
52
  end
51
- end
52
53
 
54
+ end
53
55
  end
54
56
  end
55
57
  end