message-driver 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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