message-driver 0.3.0 → 0.4.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 (66) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +18 -0
  3. data/.rubocop_todo.yml +160 -0
  4. data/.travis.yml +5 -4
  5. data/CHANGELOG.md +5 -0
  6. data/Gemfile +9 -8
  7. data/Guardfile +14 -7
  8. data/README.md +2 -0
  9. data/Rakefile +16 -10
  10. data/examples/basic_producer_and_consumer/Gemfile +2 -2
  11. data/examples/basic_producer_and_consumer/common.rb +3 -3
  12. data/examples/basic_producer_and_consumer/consumer.rb +5 -5
  13. data/examples/basic_producer_and_consumer/producer.rb +7 -7
  14. data/features/CHANGELOG.md +5 -0
  15. data/features/message_consumers/transactional_ack_consumers.feature +1 -0
  16. data/features/rabbitmq_specific_features/publisher_acknowledgements.feature +51 -0
  17. data/features/step_definitions/error_handling_steps.rb +2 -2
  18. data/features/step_definitions/logging_steps.rb +4 -4
  19. data/features/step_definitions/message_consumers_steps.rb +8 -8
  20. data/features/step_definitions/rabbitmq_specific_steps.rb +10 -0
  21. data/features/step_definitions/steps.rb +15 -15
  22. data/features/support/env.rb +3 -0
  23. data/features/support/firewall_helper.rb +5 -6
  24. data/features/support/message_table_matcher.rb +3 -4
  25. data/features/support/no_error_matcher.rb +3 -3
  26. data/features/support/test_runner.rb +11 -3
  27. data/features/support/transforms.rb +1 -1
  28. data/lib/message-driver.rb +1 -1
  29. data/lib/message_driver.rb +0 -1
  30. data/lib/message_driver/adapters/base.rb +10 -10
  31. data/lib/message_driver/adapters/bunny_adapter.rb +57 -30
  32. data/lib/message_driver/adapters/in_memory_adapter.rb +4 -5
  33. data/lib/message_driver/adapters/stomp_adapter.rb +4 -6
  34. data/lib/message_driver/broker.rb +5 -4
  35. data/lib/message_driver/client.rb +6 -6
  36. data/lib/message_driver/destination.rb +2 -2
  37. data/lib/message_driver/errors.rb +1 -4
  38. data/lib/message_driver/logging.rb +1 -1
  39. data/lib/message_driver/message.rb +2 -2
  40. data/lib/message_driver/subscription.rb +1 -1
  41. data/lib/message_driver/version.rb +1 -1
  42. data/lib/{message_driver/vendor → vendor}/.document +0 -0
  43. data/lib/vendor/nesty.rb +1 -0
  44. data/lib/vendor/nesty/nested_error.rb +28 -0
  45. data/message-driver.gemspec +15 -14
  46. data/spec/integration/bunny/amqp_integration_spec.rb +43 -43
  47. data/spec/integration/bunny/bunny_adapter_spec.rb +117 -101
  48. data/spec/integration/in_memory/in_memory_adapter_spec.rb +35 -35
  49. data/spec/integration/stomp/stomp_adapter_spec.rb +42 -42
  50. data/spec/spec_helper.rb +4 -1
  51. data/spec/support/shared/adapter_examples.rb +7 -7
  52. data/spec/support/shared/client_ack_examples.rb +6 -6
  53. data/spec/support/shared/context_examples.rb +4 -4
  54. data/spec/support/shared/destination_examples.rb +10 -10
  55. data/spec/support/shared/subscription_examples.rb +29 -29
  56. data/spec/support/shared/transaction_examples.rb +10 -10
  57. data/spec/units/message_driver/adapters/base_spec.rb +19 -19
  58. data/spec/units/message_driver/broker_spec.rb +57 -58
  59. data/spec/units/message_driver/client_spec.rb +84 -84
  60. data/spec/units/message_driver/destination_spec.rb +4 -4
  61. data/spec/units/message_driver/message_spec.rb +19 -19
  62. data/spec/units/message_driver/subscription_spec.rb +4 -4
  63. data/test_lib/broker_config.rb +2 -2
  64. metadata +27 -6
  65. data/lib/message_driver/vendor/nesty.rb +0 -1
  66. data/lib/message_driver/vendor/nesty/nested_error.rb +0 -26
@@ -9,7 +9,6 @@ module MessageDriver
9
9
 
10
10
  module Adapters
11
11
  class InMemoryAdapter < Base
12
-
13
12
  class Message < MessageDriver::Message::Base
14
13
  end
15
14
 
@@ -30,7 +29,6 @@ module MessageDriver
30
29
  end
31
30
 
32
31
  class Destination < MessageDriver::Destination::Base
33
-
34
32
  def subscription
35
33
  adapter.subscription_for(name)
36
34
  end
@@ -39,7 +37,7 @@ module MessageDriver
39
37
  message_queue.size
40
38
  end
41
39
 
42
- def pop_message(options={})
40
+ def pop_message(_options={})
43
41
  message_queue.shift
44
42
  end
45
43
 
@@ -63,16 +61,17 @@ module MessageDriver
63
61
  end
64
62
 
65
63
  private
64
+
66
65
  def message_queue
67
66
  adapter.message_queue_for(name)
68
67
  end
69
68
  end
70
69
 
71
- def initialize(broker, config={})
70
+ def initialize(broker, _config={})
72
71
  @broker = broker
73
72
  @destinations = {}
74
73
  @message_store = Hash.new { |h,k| h[k] = [] }
75
- @subscriptions = Hash.new
74
+ @subscriptions = {}
76
75
  end
77
76
 
78
77
  def build_context
@@ -10,7 +10,6 @@ module MessageDriver
10
10
 
11
11
  module Adapters
12
12
  class StompAdapter < Base
13
-
14
13
  class Message < MessageDriver::Message::Base
15
14
  attr_reader :stomp_message
16
15
  def initialize(ctx, stomp_message)
@@ -20,7 +19,6 @@ module MessageDriver
20
19
  end
21
20
 
22
21
  class Destination < MessageDriver::Destination::Base
23
-
24
22
  end
25
23
 
26
24
  attr_reader :config, :poll_timeout
@@ -32,7 +30,7 @@ module MessageDriver
32
30
  @config = config.symbolize_keys
33
31
  connect_headers = @config[:connect_headers] ||= {}
34
32
  connect_headers.symbolize_keys
35
- connect_headers[:"accept-version"] = "1.1,1.2"
33
+ connect_headers[:"accept-version"] = '1.1,1.2'
36
34
 
37
35
  vhost = @config.delete(:vhost)
38
36
  connect_headers[:host] = vhost if vhost
@@ -50,13 +48,13 @@ module MessageDriver
50
48
  #end
51
49
 
52
50
  def create_destination(name, dest_options={}, message_props={})
53
- unless name.start_with?("/")
51
+ unless name.start_with?('/')
54
52
  name = "/queue/#{name}"
55
53
  end
56
54
  Destination.new(adapter, name, dest_options, message_props)
57
55
  end
58
56
 
59
- def publish(destination, body, headers={}, properties={})
57
+ def publish(destination, body, headers={}, _properties={})
60
58
  with_connection do |connection|
61
59
  connection.publish(destination.name, body, headers)
62
60
  end
@@ -119,7 +117,7 @@ module MessageDriver
119
117
  required = Gem::Requirement.create('~> 1.3.1')
120
118
  current = Gem::Version.create(Stomp::Version::STRING)
121
119
  unless required.satisfied_by? current
122
- raise MessageDriver::Error, "stomp 1.3.1 or a later version of the 1.3.x series is required for the stomp adapter"
120
+ raise MessageDriver::Error, 'stomp 1.3.1 or a later version of the 1.3.x series is required for the stomp adapter'
123
121
  end
124
122
  end
125
123
  end
@@ -27,7 +27,7 @@ module MessageDriver
27
27
  end
28
28
 
29
29
  def client(name)
30
- unless result = clients[name]
30
+ unless (result = clients[name])
31
31
  result = clients[name] = Client.for_broker(name)
32
32
  end
33
33
  result
@@ -63,6 +63,7 @@ module MessageDriver
63
63
  end
64
64
 
65
65
  private
66
+
66
67
  def brokers
67
68
  @brokers ||= { }
68
69
  end
@@ -85,7 +86,7 @@ module MessageDriver
85
86
  @configuration = options
86
87
  @destinations = {}
87
88
  @consumers = {}
88
- logger.debug "MessageDriver configured successfully!"
89
+ logger.debug 'MessageDriver configured successfully!'
89
90
  end
90
91
 
91
92
  def logger
@@ -123,7 +124,7 @@ module MessageDriver
123
124
  end
124
125
 
125
126
  def consumer(key, &block)
126
- raise MessageDriver::Error, "you must provide a block" unless block_given?
127
+ raise MessageDriver::Error, 'you must provide a block' unless block_given?
127
128
  @consumers[key] = block
128
129
  end
129
130
 
@@ -144,7 +145,7 @@ module MessageDriver
144
145
  def resolve_adapter(adapter, options)
145
146
  case adapter
146
147
  when nil
147
- raise "you must specify an adapter"
148
+ raise 'you must specify an adapter'
148
149
  when Symbol, String
149
150
  resolve_adapter(find_adapter_class(adapter), options)
150
151
  when Class
@@ -54,7 +54,7 @@ module MessageDriver
54
54
  broker.find_consumer(consumer)
55
55
  end
56
56
 
57
- def with_message_transaction(options={}, &block)
57
+ def with_message_transaction(options={})
58
58
  wrapper = fetch_context_wrapper
59
59
  wrapper.increment_transaction_depth
60
60
  begin
@@ -76,7 +76,7 @@ module MessageDriver
76
76
  yield
77
77
  end
78
78
  else
79
- logger.debug("this adapter does not support transactions")
79
+ logger.debug('this adapter does not support transactions')
80
80
  yield
81
81
  end
82
82
  ensure
@@ -89,7 +89,7 @@ module MessageDriver
89
89
  ctx.nil? ? nil : ctx.ctx
90
90
  end
91
91
 
92
- def with_adapter_context(adapter_context, &block)
92
+ def with_adapter_context(adapter_context)
93
93
  old_ctx, Thread.current[adapter_context_key] = fetch_context_wrapper(false), build_context_wrapper(adapter_context)
94
94
  begin
95
95
  yield
@@ -114,13 +114,13 @@ module MessageDriver
114
114
  Broker::DEFAULT_BROKER_NAME
115
115
  end
116
116
 
117
- def for_broker(_broker_name)
118
- Module.new do |mod|
117
+ def for_broker(name)
118
+ Module.new do
119
119
  include Client
120
120
  extend self
121
121
 
122
122
  define_method :broker_name do
123
- _broker_name
123
+ name
124
124
  end
125
125
  end
126
126
  end
@@ -18,7 +18,7 @@ module MessageDriver
18
18
  adapter.broker.client.pop_message(self, options)
19
19
  end
20
20
 
21
- def after_initialize(adapter_context)
21
+ def after_initialize(_adapter_context)
22
22
  #does nothing, feel free to override as needed
23
23
  end
24
24
 
@@ -26,7 +26,7 @@ module MessageDriver
26
26
  raise "#message_count is not supported by #{self.class}"
27
27
  end
28
28
 
29
- def subscribe(&consumer)
29
+ def subscribe(&_consumer)
30
30
  raise "#subscribe is not supported by #{self.class}"
31
31
  end
32
32
  end
@@ -1,7 +1,4 @@
1
- vendor = File.expand_path('../vendor', __FILE__)
2
- $:.unshift(vendor) unless $:.include?(vendor)
3
-
4
- require 'nesty'
1
+ require 'vendor/nesty'
5
2
 
6
3
  module MessageDriver
7
4
  class Error < StandardError; end
@@ -7,7 +7,7 @@ module MessageDriver
7
7
  end
8
8
 
9
9
  def exception_to_str(e)
10
- (["#{e.class}: #{e.to_s}"] + e.backtrace).join("\n ")
10
+ (["#{e.class}: #{e}"] + e.backtrace).join("\n ")
11
11
  end
12
12
 
13
13
  def message_with_exception(message, e)
@@ -16,7 +16,7 @@ module MessageDriver
16
16
  if ctx.supports_client_acks?
17
17
  ctx.ack_message(self, options)
18
18
  else
19
- logger.debug("this adapter does not support client acks")
19
+ logger.debug('this adapter does not support client acks')
20
20
  end
21
21
  end
22
22
 
@@ -24,7 +24,7 @@ module MessageDriver
24
24
  if ctx.supports_client_acks?
25
25
  ctx.nack_message(self, options)
26
26
  else
27
- logger.debug("this adapter does not support client acks")
27
+ logger.debug('this adapter does not support client acks')
28
28
  end
29
29
  end
30
30
  end
@@ -12,7 +12,7 @@ module MessageDriver
12
12
  end
13
13
 
14
14
  def unsubscribe
15
- raise "must be implemented in subclass"
15
+ raise 'must be implemented in subclass'
16
16
  end
17
17
  end
18
18
  end
@@ -1,5 +1,5 @@
1
1
  module Message
2
2
  module Driver
3
- VERSION = "0.3.0"
3
+ VERSION = '0.4.0'
4
4
  end
5
5
  end
File without changes
@@ -0,0 +1 @@
1
+ require 'vendor/nesty/nested_error'
@@ -0,0 +1,28 @@
1
+ module MessageDriver
2
+ module Nesty
3
+ module NestedError
4
+ attr_reader :nested, :raw_backtrace
5
+
6
+ def initialize(msg = nil, nested)
7
+ super(msg)
8
+ @nested = nested
9
+ end
10
+
11
+ def set_backtrace(backtrace)
12
+ @raw_backtrace = backtrace
13
+ if nested
14
+ backtrace = backtrace - nested_raw_backtrace
15
+ backtrace += ["#{nested.backtrace.first}: #{nested.message} (#{nested.class.name})"]
16
+ backtrace += nested.backtrace[1..-1] || []
17
+ end
18
+ super(backtrace)
19
+ end
20
+
21
+ private
22
+
23
+ def nested_raw_backtrace
24
+ nested.respond_to?(:raw_backtrace) ? nested.raw_backtrace : nested.backtrace
25
+ end
26
+ end
27
+ end
28
+ end
@@ -4,24 +4,25 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'message_driver/version'
5
5
 
6
6
  Gem::Specification.new do |gem|
7
- gem.name = "message-driver"
7
+ gem.name = 'message-driver'
8
8
  gem.version = Message::Driver::VERSION
9
- gem.authors = ["Matt Campbell"]
10
- gem.email = ["message-driver@soupmatt.com"]
11
- gem.description = %q{Easy message queues for ruby using AMQ, STOMP and others}
12
- gem.summary = %q{Easy message queues for ruby}
13
- gem.homepage = "https://github.com/message-driver/message-driver"
14
- gem.license = "MIT"
9
+ gem.authors = ['Matt Campbell']
10
+ gem.email = ['message-driver@soupmatt.com']
11
+ gem.description = 'Easy message queues for ruby using AMQ, STOMP and others'
12
+ gem.summary = 'Easy message queues for ruby'
13
+ gem.homepage = 'https://github.com/message-driver/message-driver'
14
+ gem.license = 'MIT'
15
15
 
16
- gem.files = `git ls-files`.split($/)
17
- gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
16
+ gem.files = `git ls-files`.split($RS)
17
+ gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
18
18
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
19
- gem.require_paths = ["lib"]
19
+ gem.require_paths = %w(lib)
20
20
 
21
21
  gem.required_ruby_version = '>= 1.9.2'
22
22
 
23
- gem.add_development_dependency "rake"
24
- gem.add_development_dependency "rspec", "~> 2.14.0"
25
- gem.add_development_dependency "cucumber"
26
- gem.add_development_dependency "aruba"
23
+ gem.add_development_dependency 'rake'
24
+ gem.add_development_dependency 'rspec', '~> 2.14.0'
25
+ gem.add_development_dependency 'cucumber'
26
+ gem.add_development_dependency 'aruba'
27
+ gem.add_development_dependency 'rubocop'
27
28
  end
@@ -1,11 +1,11 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe "AMQP Integration", :bunny, type: :integration do
3
+ describe 'AMQP Integration', :bunny, type: :integration do
4
4
  let!(:broker) { MessageDriver::Broker.configure BrokerConfig.config }
5
5
 
6
6
  context "when a queue can't be found" do
7
- let(:queue_name) { "my.lost.queue" }
8
- it "raises a MessageDriver::QueueNotFound error" do
7
+ let(:queue_name) { 'my.lost.queue' }
8
+ it 'raises a MessageDriver::QueueNotFound error' do
9
9
  expect {
10
10
  broker.dynamic_destination(queue_name, passive: true)
11
11
  }.to raise_error(MessageDriver::QueueNotFound) do |err|
@@ -15,40 +15,40 @@ describe "AMQP Integration", :bunny, type: :integration do
15
15
  end
16
16
  end
17
17
 
18
- context "when a channel level exception occurs" do
19
- it "raises a MessageDriver::WrappedError error" do
18
+ context 'when a channel level exception occurs' do
19
+ it 'raises a MessageDriver::WrappedError error' do
20
20
  expect {
21
- broker.dynamic_destination("not.a.queue", passive: true)
21
+ broker.dynamic_destination('not.a.queue', passive: true)
22
22
  }.to raise_error(MessageDriver::WrappedError) { |err| err.nested.should be_a Bunny::ChannelLevelException }
23
23
  end
24
24
 
25
- it "reestablishes the channel transparently" do
25
+ it 'reestablishes the channel transparently' do
26
26
  expect {
27
- broker.dynamic_destination("not.a.queue", passive: true)
27
+ broker.dynamic_destination('not.a.queue', passive: true)
28
28
  }.to raise_error(MessageDriver::WrappedError)
29
29
  expect {
30
- broker.dynamic_destination("", exclusive: true)
30
+ broker.dynamic_destination('', exclusive: true)
31
31
  }.to_not raise_error
32
32
  end
33
33
 
34
- context "when in a transaction" do
35
- it "sets the channel_context as rollback-only until the transaction is finished" do
34
+ context 'when in a transaction' do
35
+ it 'sets the channel_context as rollback-only until the transaction is finished' do
36
36
  MessageDriver::Client.with_message_transaction do
37
37
  expect {
38
- broker.dynamic_destination("not.a.queue", passive: true)
38
+ broker.dynamic_destination('not.a.queue', passive: true)
39
39
  }.to raise_error(MessageDriver::WrappedError)
40
40
  expect {
41
- broker.dynamic_destination("", exclusive: true)
41
+ broker.dynamic_destination('', exclusive: true)
42
42
  }.to raise_error(MessageDriver::TransactionRollbackOnly)
43
43
  end
44
44
  expect {
45
- broker.dynamic_destination("", exclusive: true)
45
+ broker.dynamic_destination('', exclusive: true)
46
46
  }.to_not raise_error
47
47
  end
48
48
  end
49
49
  end
50
50
 
51
- context "when the broker connection fails", pending: "these spec are busted" do
51
+ context 'when the broker connection fails', pending: 'these spec are busted' do
52
52
  def disrupt_connection
53
53
  #yes, this is very implementation specific
54
54
  broker.adapter.connection.instance_variable_get(:@transport).close
@@ -58,85 +58,85 @@ describe "AMQP Integration", :bunny, type: :integration do
58
58
  broker.dynamic_destination(queue_name, exclusive: true)
59
59
  end
60
60
 
61
- it "raises a MessageDriver::ConnectionError" do
62
- dest = create_destination("test_queue")
61
+ it 'raises a MessageDriver::ConnectionError' do
62
+ dest = create_destination('test_queue')
63
63
  disrupt_connection
64
64
  expect {
65
- dest.publish("Reconnection Test")
65
+ dest.publish('Reconnection Test')
66
66
  }.to raise_error(MessageDriver::ConnectionError) do |err|
67
67
  expect(err.nested).to be_a Bunny::NetworkErrorWrapper
68
68
  end
69
69
  end
70
70
 
71
- it "seemlessly reconnects" do
72
- dest = create_destination("seemless.reconnect.queue")
71
+ it 'seemlessly reconnects' do
72
+ dest = create_destination('seemless.reconnect.queue')
73
73
  disrupt_connection
74
74
  expect {
75
- dest.publish("Reconnection Test 1")
75
+ dest.publish('Reconnection Test 1')
76
76
  }.to raise_error(MessageDriver::ConnectionError)
77
- dest = create_destination("seemless.reconnect.queue")
78
- dest.publish("Reconnection Test 2")
77
+ dest = create_destination('seemless.reconnect.queue')
78
+ dest.publish('Reconnection Test 2')
79
79
  msg = dest.pop_message
80
80
  expect(msg).to_not be_nil
81
- expect(msg.body).to eq("Reconnection Test 2")
81
+ expect(msg.body).to eq('Reconnection Test 2')
82
82
  end
83
83
 
84
- context "when in a transaction" do
85
- it "raises a MessageDriver::ConnectionError" do
84
+ context 'when in a transaction' do
85
+ it 'raises a MessageDriver::ConnectionError' do
86
86
  expect {
87
87
  MessageDriver::Client.with_message_transaction do
88
88
  disrupt_connection
89
- broker.dynamic_destination("", exclusive: true)
89
+ broker.dynamic_destination('', exclusive: true)
90
90
  end
91
91
  }.to raise_error(MessageDriver::ConnectionError)
92
92
  end
93
93
 
94
- it "sets the channel_context as rollback-only until the transaction is finished" do
94
+ it 'sets the channel_context as rollback-only until the transaction is finished' do
95
95
  MessageDriver::Client.with_message_transaction do
96
96
  disrupt_connection
97
97
  expect {
98
- broker.dynamic_destination("", exclusive: true)
98
+ broker.dynamic_destination('', exclusive: true)
99
99
  }.to raise_error(MessageDriver::ConnectionError)
100
100
  expect {
101
- broker.dynamic_destination("", exclusive: true)
101
+ broker.dynamic_destination('', exclusive: true)
102
102
  }.to raise_error(MessageDriver::TransactionRollbackOnly)
103
103
  end
104
104
  expect {
105
- broker.dynamic_destination("", exclusive: true)
105
+ broker.dynamic_destination('', exclusive: true)
106
106
  }.to_not raise_error
107
107
  end
108
108
  end
109
109
  end
110
110
 
111
- context "when an unhandled expection occurs in a transaction" do
112
- let(:destination) { broker.dynamic_destination("", exclusive: true) }
111
+ context 'when an unhandled expection occurs in a transaction' do
112
+ let(:destination) { broker.dynamic_destination('', exclusive: true) }
113
113
 
114
- it "rolls back the transaction" do
114
+ it 'rolls back the transaction' do
115
115
  expect {
116
116
  MessageDriver::Client.with_message_transaction do
117
- destination.publish("Test Message")
118
- raise "unhandled error"
117
+ destination.publish('Test Message')
118
+ raise 'unhandled error'
119
119
  end
120
- }.to raise_error "unhandled error"
120
+ }.to raise_error 'unhandled error'
121
121
  expect(destination.pop_message).to be_nil
122
122
  end
123
123
 
124
- it "allows the next transaction to continue" do
124
+ it 'allows the next transaction to continue' do
125
125
  expect {
126
126
  MessageDriver::Client.with_message_transaction do
127
- destination.publish("Test Message 1")
128
- raise "unhandled error"
127
+ destination.publish('Test Message 1')
128
+ raise 'unhandled error'
129
129
  end
130
- }.to raise_error "unhandled error"
130
+ }.to raise_error 'unhandled error'
131
131
  expect(destination.pop_message).to be_nil
132
132
 
133
133
  MessageDriver::Client.with_message_transaction do
134
- destination.publish("Test Message 2")
134
+ destination.publish('Test Message 2')
135
135
  end
136
136
 
137
137
  msg = destination.pop_message
138
138
  expect(msg).to_not be_nil
139
- expect(msg.body).to eq("Test Message 2")
139
+ expect(msg.body).to eq('Test Message 2')
140
140
  end
141
141
  end
142
142
  end