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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +20 -2
  3. data/.rubocop_todo.yml +15 -23
  4. data/.travis.yml +10 -22
  5. data/CHANGELOG.md +9 -0
  6. data/Gemfile +34 -24
  7. data/Guardfile +46 -29
  8. data/LICENSE +1 -1
  9. data/Rakefile +14 -6
  10. data/features/CHANGELOG.md +1 -0
  11. data/features/step_definitions/logging_steps.rb +3 -2
  12. data/features/support/firewall_helper.rb +2 -2
  13. data/features/support/no_error_matcher.rb +1 -1
  14. data/lib/message_driver/adapters/base.rb +115 -11
  15. data/lib/message_driver/adapters/bunny_adapter.rb +58 -46
  16. data/lib/message_driver/adapters/in_memory_adapter.rb +57 -35
  17. data/lib/message_driver/adapters/stomp_adapter.rb +10 -10
  18. data/lib/message_driver/broker.rb +16 -19
  19. data/lib/message_driver/client.rb +3 -7
  20. data/lib/message_driver/destination.rb +4 -4
  21. data/lib/message_driver/message.rb +3 -2
  22. data/lib/message_driver/middleware/block_middleware.rb +1 -1
  23. data/lib/message_driver/subscription.rb +1 -1
  24. data/lib/message_driver/version.rb +1 -1
  25. data/message-driver.gemspec +6 -6
  26. data/spec/integration/bunny/amqp_integration_spec.rb +6 -4
  27. data/spec/integration/bunny/bunny_adapter_spec.rb +1 -3
  28. data/spec/integration/in_memory/in_memory_adapter_spec.rb +46 -6
  29. data/spec/integration/stomp/stomp_adapter_spec.rb +0 -2
  30. data/spec/spec_helper.rb +6 -0
  31. data/spec/support/matchers/override_method_matcher.rb +7 -0
  32. data/spec/support/shared/adapter_examples.rb +3 -0
  33. data/spec/support/shared/client_ack_examples.rb +26 -4
  34. data/spec/support/shared/context_examples.rb +46 -0
  35. data/spec/support/shared/destination_examples.rb +28 -0
  36. data/spec/support/shared/subscription_examples.rb +6 -1
  37. data/spec/support/shared/transaction_examples.rb +35 -4
  38. data/spec/support/test_adapter.rb +19 -0
  39. data/spec/support/utils.rb +1 -5
  40. data/spec/units/message_driver/adapters/base_spec.rb +37 -31
  41. data/spec/units/message_driver/broker_spec.rb +1 -2
  42. data/spec/units/message_driver/client_spec.rb +3 -3
  43. data/spec/units/message_driver/destination_spec.rb +4 -2
  44. data/spec/units/message_driver/message_spec.rb +9 -3
  45. data/test_lib/broker_config.rb +0 -2
  46. data/test_lib/provider/base.rb +2 -6
  47. data/test_lib/provider/rabbitmq.rb +3 -3
  48. metadata +18 -16
  49. data/ci/travis_setup +0 -7
  50. data/features/CHANGELOG.md +0 -102
@@ -20,7 +20,7 @@ module FirewallHelper
20
20
  'sudo service rabbitmq-server start'
21
21
  ]
22
22
  }
23
- }
23
+ }.freeze
24
24
 
25
25
  def block_broker_port
26
26
  run_commands(:setup)
@@ -35,7 +35,7 @@ module FirewallHelper
35
35
  def run_commands(step)
36
36
  COMMANDS[os][step].each do |cmd|
37
37
  result = system(cmd)
38
- fail "command `#{cmd}` failed!" unless result
38
+ raise "command `#{cmd}` failed!" unless result
39
39
  end
40
40
  end
41
41
 
@@ -6,7 +6,7 @@ RSpec::Matchers.define :have_no_errors do
6
6
  failure_message do |test_runner|
7
7
  err = test_runner.raised_error
8
8
  filtered = (err.backtrace || []).reject do |line|
9
- Cucumber::Ast::StepInvocation::BACKTRACE_FILTER_PATTERNS.find { |p| line =~ p }
9
+ Cucumber::Formatter::BACKTRACE_FILTER_PATTERNS.find { |p| line =~ p }
10
10
  end
11
11
  (["#{err.class}: #{err}"] + filtered).join("\n ")
12
12
  end
@@ -10,7 +10,7 @@ module MessageDriver
10
10
  end
11
11
 
12
12
  def initialize(_broker, _configuration)
13
- fail 'Must be implemented in subclass'
13
+ raise 'Must be implemented in subclass'
14
14
  end
15
15
 
16
16
  def new_context
@@ -20,7 +20,7 @@ module MessageDriver
20
20
  end
21
21
 
22
22
  def build_context
23
- fail 'Must be implemented in subclass'
23
+ raise 'Must be implemented in subclass'
24
24
  end
25
25
 
26
26
  def reset_after_tests
@@ -31,7 +31,7 @@ module MessageDriver
31
31
  if @contexts
32
32
  ctxs = @contexts
33
33
  @contexts = []
34
- ctxs.each { |ctx| ctx.invalidate }
34
+ ctxs.each(&:invalidate)
35
35
  end
36
36
  end
37
37
  end
@@ -47,20 +47,56 @@ module MessageDriver
47
47
  @valid = true
48
48
  end
49
49
 
50
- def publish(_destination, _body, _headers = {}, _properties = {})
51
- fail 'Must be implemented in subclass'
50
+ def publish(destination, body, headers = {}, properties = {})
51
+ handle_publish(destination, body, headers, properties)
52
52
  end
53
53
 
54
- def pop_message(_destination, _options = {})
55
- fail 'Must be implemented in subclass'
54
+ def pop_message(destination, options = {})
55
+ handle_pop_message(destination, options)
56
56
  end
57
57
 
58
- def subscribe(_destination, _options = {}, &_consumer)
59
- fail "#subscribe is not supported by #{adapter.class}"
58
+ def subscribe(destination, options = {}, &consumer)
59
+ handle_subscribe(destination, options, &consumer)
60
60
  end
61
61
 
62
- def create_destination(_name, _dest_options = {}, _message_props = {})
63
- fail 'Must be implemented in subclass'
62
+ def create_destination(name, dest_options = {}, message_props = {})
63
+ handle_create_destination(name, dest_options, message_props)
64
+ end
65
+
66
+ def ack_message(message, options = {})
67
+ handle_ack_message(message, options)
68
+ end
69
+
70
+ def nack_message(message, options = {})
71
+ handle_nack_message(message, options)
72
+ end
73
+
74
+ def begin_transaction(options = {})
75
+ handle_begin_transaction(options)
76
+ end
77
+
78
+ def commit_transaction(options = {})
79
+ handle_commit_transaction(options)
80
+ end
81
+
82
+ def rollback_transaction(options = {})
83
+ handle_rollback_transaction(options)
84
+ end
85
+
86
+ def message_count(destination)
87
+ handle_message_count(destination)
88
+ end
89
+
90
+ def consumer_count(destination)
91
+ handle_consumer_count(destination)
92
+ end
93
+
94
+ def in_transaction?
95
+ if supports_transactions?
96
+ raise 'must be implemented in subclass'
97
+ else
98
+ raise "#in_transaction? not supported by #{adapter.class}"
99
+ end
64
100
  end
65
101
 
66
102
  def valid?
@@ -82,6 +118,74 @@ module MessageDriver
82
118
  def supports_subscriptions?
83
119
  false
84
120
  end
121
+
122
+ def handle_create_destination(_name, _dest_options = {}, _message_props = {})
123
+ raise 'Must be implemented in subclass'
124
+ end
125
+
126
+ def handle_publish(_destination, _body, _headers = {}, _properties = {})
127
+ raise 'Must be implemented in subclass'
128
+ end
129
+
130
+ def handle_pop_message(_destination, _options = {})
131
+ raise 'Must be implemented in subclass'
132
+ end
133
+
134
+ def handle_subscribe(_destination, _options = {}, &_consumer)
135
+ if supports_subscriptions?
136
+ raise 'Must be implemented in subclass'
137
+ else
138
+ raise "#subscribe is not supported by #{adapter.class}"
139
+ end
140
+ end
141
+
142
+ def handle_ack_message(_message, _options = {})
143
+ if supports_client_acks?
144
+ raise 'Must be implemented in subclass'
145
+ else
146
+ raise "#ack_message is not supported by #{adapter.class}"
147
+ end
148
+ end
149
+
150
+ def handle_nack_message(_message, _options = {})
151
+ if supports_client_acks?
152
+ raise 'Must be implemented in subclass'
153
+ else
154
+ raise "#nack_message is not supported by #{adapter.class}"
155
+ end
156
+ end
157
+
158
+ def handle_begin_transaction(_options = {})
159
+ if supports_transactions?
160
+ raise 'Must be implemented in subclass'
161
+ else
162
+ raise "transactions are not supported by #{adapter.class}"
163
+ end
164
+ end
165
+
166
+ def handle_commit_transaction(_options = {})
167
+ if supports_transactions?
168
+ raise 'Must be implemented in subclass'
169
+ else
170
+ raise "transactions are not supported by #{adapter.class}"
171
+ end
172
+ end
173
+
174
+ def handle_rollback_transaction(_options = {})
175
+ if supports_transactions?
176
+ raise 'Must be implemented in subclass'
177
+ else
178
+ raise "transactions are not supported by #{adapter.class}"
179
+ end
180
+ end
181
+
182
+ def handle_message_count(destination)
183
+ raise "#message_count is not supported by #{destination.class}"
184
+ end
185
+
186
+ def handle_consumer_count(destination)
187
+ raise "#consumer_count is not supported by #{destination.class}"
188
+ end
85
189
  end
86
190
  end
87
191
  end
@@ -25,7 +25,7 @@ module MessageDriver
25
25
  raw_headers = properties[:headers]
26
26
  raw_headers = {} if raw_headers.nil?
27
27
  b, h, p = destination.middleware.on_consume(payload, raw_headers, properties)
28
- super(ctx, b, h, p, raw_body)
28
+ super(ctx, destination, b, h, p, raw_body)
29
29
  @delivery_info = delivery_info
30
30
  end
31
31
 
@@ -59,10 +59,10 @@ module MessageDriver
59
59
  def after_initialize(adapter_context)
60
60
  if @dest_options[:no_declare]
61
61
  if @name.empty?
62
- fail MessageDriver::Error, 'server-named queues must be declared, but you provided :no_declare => true'
62
+ raise MessageDriver::Error, 'server-named queues must be declared, but you provided :no_declare => true'
63
63
  end
64
64
  if @dest_options[:bindings]
65
- fail MessageDriver::Error, 'queues with bindings must be declared, but you provided :no_declare => true'
65
+ raise MessageDriver::Error, 'queues with bindings must be declared, but you provided :no_declare => true'
66
66
  end
67
67
  else
68
68
  adapter_context.with_channel(false) do |ch|
@@ -73,7 +73,7 @@ module MessageDriver
73
73
 
74
74
  def bunny_queue(channel, options = {})
75
75
  opts = @dest_options.dup
76
- opts.merge!(passive: options[:passive]) if options.key? :passive
76
+ opts[:passive] = options[:passive] if options.key? :passive
77
77
  queue = channel.queue(@name, opts)
78
78
  handle_queue_init(queue) if options.fetch(:init, false)
79
79
  queue
@@ -83,7 +83,7 @@ module MessageDriver
83
83
  @name = queue.name
84
84
  if (bindings = @dest_options[:bindings])
85
85
  bindings.each do |bnd|
86
- fail MessageDriver::Error, "binding #{bnd.inspect} must provide a source!" unless bnd[:source]
86
+ raise MessageDriver::Error, "binding #{bnd.inspect} must provide a source!" unless bnd[:source]
87
87
  queue.bind(bnd[:source], bnd[:args] || {})
88
88
  end
89
89
  end
@@ -97,24 +97,24 @@ module MessageDriver
97
97
  @name
98
98
  end
99
99
 
100
- def message_count
101
- adapter.broker.client.current_adapter_context.with_channel(false) do |ch|
100
+ def handle_message_count
101
+ current_adapter_context.with_channel(false) do |ch|
102
102
  bunny_queue(ch, passive: true).message_count
103
103
  end
104
104
  end
105
105
 
106
106
  def subscribe(options = {}, &consumer)
107
- adapter.broker.client.current_adapter_context.subscribe(self, options, &consumer)
107
+ current_adapter_context.subscribe(self, options, &consumer)
108
108
  end
109
109
 
110
- def consumer_count
111
- adapter.broker.client.current_adapter_context.with_channel(false) do |ch|
110
+ def handle_consumer_count
111
+ current_adapter_context.with_channel(false) do |ch|
112
112
  bunny_queue(ch, passive: true).consumer_count
113
113
  end
114
114
  end
115
115
 
116
116
  def purge
117
- adapter.broker.client.current_adapter_context.with_channel(false) do |ch|
117
+ current_adapter_context.with_channel(false) do |ch|
118
118
  bunny_queue(ch).purge
119
119
  end
120
120
  end
@@ -125,14 +125,14 @@ module MessageDriver
125
125
  if (declare = @dest_options[:declare])
126
126
  adapter_context.with_channel(false) do |ch|
127
127
  type = declare.delete(:type)
128
- fail MessageDriver::Error, 'you must provide a valid exchange type' unless type
128
+ raise MessageDriver::Error, 'you must provide a valid exchange type' unless type
129
129
  ch.exchange_declare(@name, type, declare)
130
130
  end
131
131
  end
132
132
  if (bindings = @dest_options[:bindings])
133
133
  adapter_context.with_channel(false) do |ch|
134
134
  bindings.each do |bnd|
135
- fail MessageDriver::Error, "binding #{bnd.inspect} must provide a source!" unless bnd[:source]
135
+ raise MessageDriver::Error, "binding #{bnd.inspect} must provide a source!" unless bnd[:source]
136
136
  ch.exchange_bind(bnd[:source], @name, bnd[:args] || {})
137
137
  end
138
138
  end
@@ -145,8 +145,8 @@ module MessageDriver
145
145
 
146
146
  def start
147
147
  unless destination.is_a? QueueDestination
148
- fail MessageDriver::Error,
149
- 'subscriptions are only supported with QueueDestinations'
148
+ raise MessageDriver::Error,
149
+ 'subscriptions are only supported with QueueDestinations'
150
150
  end
151
151
  @sub_ctx = adapter.new_subscription_context(self)
152
152
  @error_handler = options[:error_handler]
@@ -158,7 +158,7 @@ module MessageDriver
158
158
  when :transactional
159
159
  TransactionalAckHandler.new(self)
160
160
  else
161
- fail MessageDriver::Error, "unrecognized :ack option #{options[:ack]}"
161
+ raise MessageDriver::Error, "unrecognized :ack option #{options[:ack]}"
162
162
  end
163
163
  start_subscription
164
164
  end
@@ -305,14 +305,14 @@ module MessageDriver
305
305
  @require_commit = false
306
306
  end
307
307
 
308
- def create_destination(name, dest_options = {}, message_props = {})
308
+ def handle_create_destination(name, dest_options = {}, message_props = {})
309
309
  dest = case type = dest_options.delete(:type)
310
310
  when :exchange
311
311
  ExchangeDestination.new(adapter, name, dest_options, message_props)
312
312
  when :queue, nil
313
313
  QueueDestination.new(adapter, name, dest_options, message_props)
314
314
  else
315
- fail MessageDriver::Error, "invalid destination type #{type}"
315
+ raise MessageDriver::Error, "invalid destination type #{type}"
316
316
  end
317
317
  dest.after_initialize(self)
318
318
  dest
@@ -322,33 +322,29 @@ module MessageDriver
322
322
  true
323
323
  end
324
324
 
325
- def begin_transaction(options = {})
325
+ def handle_begin_transaction(options = {})
326
326
  if in_transaction?
327
- fail MessageDriver::TransactionError,
328
- "you can't begin another transaction, you are already in one!"
327
+ raise MessageDriver::TransactionError,
328
+ "you can't begin another transaction, you are already in one!"
329
329
  end
330
330
  @in_transaction = true
331
331
  @in_confirms_transaction = true if options[:type] == :confirm_and_wait
332
332
  end
333
333
 
334
- def commit_transaction
334
+ def handle_commit_transaction(_ = nil)
335
335
  if !in_transaction? && !@require_commit
336
- fail MessageDriver::TransactionError,
337
- "you can't finish the transaction unless you already in one!"
336
+ raise MessageDriver::TransactionError,
337
+ "you can't finish the transaction unless you already in one!"
338
338
  end
339
339
  begin
340
340
  if @in_confirms_transaction
341
- unless @rollback_only || @channel.nil?
342
- @channel.wait_for_confirms
343
- end
344
- else
345
- if is_transactional? && valid? && !@need_channel_reset && @require_commit
346
- handle_errors do
347
- if @rollback_only
348
- @channel.tx_rollback
349
- else
350
- @channel.tx_commit
351
- end
341
+ @channel.wait_for_confirms unless @rollback_only || @channel.nil?
342
+ elsif is_transactional? && valid? && !@need_channel_reset && @require_commit
343
+ handle_errors do
344
+ if @rollback_only
345
+ @channel.tx_rollback
346
+ else
347
+ @channel.tx_commit
352
348
  end
353
349
  end
354
350
  end
@@ -360,7 +356,7 @@ module MessageDriver
360
356
  end
361
357
  end
362
358
 
363
- def rollback_transaction
359
+ def handle_rollback_transaction(_ = nil)
364
360
  @rollback_only = true
365
361
  commit_transaction
366
362
  end
@@ -368,13 +364,13 @@ module MessageDriver
368
364
  def transactional?
369
365
  @is_transactional
370
366
  end
371
- alias_method :is_transactional?, :transactional?
367
+ alias is_transactional? transactional?
372
368
 
373
369
  def in_transaction?
374
370
  @in_transaction
375
371
  end
376
372
 
377
- def publish(destination, body, headers = {}, properties = {})
373
+ def handle_publish(destination, body, headers = {}, properties = {})
378
374
  body, exchange, routing_key, props = *destination.publish_params(body, headers, properties)
379
375
  confirm = props.delete(:confirm)
380
376
  confirm = false if confirm.nil?
@@ -387,8 +383,8 @@ module MessageDriver
387
383
  end
388
384
  end
389
385
 
390
- def pop_message(destination, options = {})
391
- fail MessageDriver::Error, "You can't pop a message off an exchange" if destination.is_a? ExchangeDestination
386
+ def handle_pop_message(destination, options = {})
387
+ raise MessageDriver::Error, "You can't pop a message off an exchange" if destination.is_a? ExchangeDestination
392
388
 
393
389
  with_channel(false) do |ch|
394
390
  queue = ch.queue(destination.name, passive: true)
@@ -406,13 +402,13 @@ module MessageDriver
406
402
  true
407
403
  end
408
404
 
409
- def ack_message(message, _options = {})
405
+ def handle_ack_message(message, _options = {})
410
406
  with_channel(true) do |ch|
411
407
  ch.ack(message.delivery_tag)
412
408
  end
413
409
  end
414
410
 
415
- def nack_message(message, options = {})
411
+ def handle_nack_message(message, options = {})
416
412
  requeue = options.fetch(:requeue, true)
417
413
  with_channel(true) do |ch|
418
414
  ch.reject(message.delivery_tag, requeue)
@@ -423,12 +419,28 @@ module MessageDriver
423
419
  true
424
420
  end
425
421
 
426
- def subscribe(destination, options = {}, &consumer)
422
+ def handle_subscribe(destination, options = {}, &consumer)
427
423
  sub = Subscription.new(adapter, destination, consumer, options)
428
424
  sub.start
429
425
  sub
430
426
  end
431
427
 
428
+ def handle_message_count(destination)
429
+ if destination.respond_to?(:handle_message_count)
430
+ destination.handle_message_count
431
+ else
432
+ super
433
+ end
434
+ end
435
+
436
+ def handle_consumer_count(destination)
437
+ if destination.respond_to?(:handle_consumer_count)
438
+ destination.handle_consumer_count
439
+ else
440
+ super
441
+ end
442
+ end
443
+
432
444
  def invalidate(in_unsubscribe = false)
433
445
  super()
434
446
  unless @subscription.nil? || in_unsubscribe
@@ -488,8 +500,8 @@ module MessageDriver
488
500
  end
489
501
 
490
502
  def with_channel(require_commit = true)
491
- fail MessageDriver::TransactionRollbackOnly if @rollback_only
492
- fail MessageDriver::Error, 'this adapter context is not valid!' unless valid?
503
+ raise MessageDriver::TransactionRollbackOnly if @rollback_only
504
+ raise MessageDriver::Error, 'this adapter context is not valid!' unless valid?
493
505
  ensure_channel
494
506
  @require_commit ||= require_commit
495
507
  if in_transaction?
@@ -535,7 +547,7 @@ module MessageDriver
535
547
  required = Gem::Requirement.create('>= 1.7.0')
536
548
  current = Gem::Version.create(Bunny::VERSION)
537
549
  unless required.satisfied_by? current
538
- fail MessageDriver::Error, 'bunny 1.7.0 or later is required for the bunny adapter'
550
+ raise MessageDriver::Error, 'bunny 1.7.0 or later is required for the bunny adapter'
539
551
  end
540
552
  end
541
553
  end