message-driver 0.1.0 → 0.2.0.rc1

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 (85) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/.travis.yml +18 -7
  4. data/CHANGELOG.md +12 -2
  5. data/Gemfile +17 -0
  6. data/Guardfile +8 -4
  7. data/README.md +14 -5
  8. data/Rakefile +44 -11
  9. data/examples/basic_producer_and_consumer/Gemfile +5 -0
  10. data/examples/basic_producer_and_consumer/common.rb +17 -0
  11. data/examples/basic_producer_and_consumer/consumer.rb +24 -0
  12. data/examples/basic_producer_and_consumer/producer.rb +33 -0
  13. data/features/.nav +8 -0
  14. data/features/CHANGELOG.md +12 -2
  15. data/features/amqp_specific_features/binding_amqp_destinations.feature +7 -7
  16. data/features/amqp_specific_features/declaring_amqp_exchanges.feature +3 -3
  17. data/features/amqp_specific_features/nack_redelivered_messages.feature +92 -0
  18. data/features/amqp_specific_features/requeueing_on_nack.feature +44 -0
  19. data/features/amqp_specific_features/server_named_destinations.feature +5 -5
  20. data/features/client_acks.feature +92 -0
  21. data/features/destination_metadata.feature +9 -11
  22. data/features/dynamic_destinations.feature +7 -7
  23. data/features/error_handling.feature +11 -9
  24. data/features/logging.feature +14 -0
  25. data/features/message_consumers/auto_ack_consumers.feature +79 -0
  26. data/features/message_consumers/manual_ack_consumers.feature +95 -0
  27. data/features/message_consumers/transactional_ack_consumers.feature +77 -0
  28. data/features/message_consumers.feature +54 -0
  29. data/features/publishing_a_message.feature +6 -10
  30. data/features/publishing_with_transactions.feature +10 -14
  31. data/features/rabbitmq_specific_features/dead_letter_queueing.feature +116 -0
  32. data/features/step_definitions/dynamic_destinations_steps.rb +3 -3
  33. data/features/step_definitions/error_handling_steps.rb +4 -2
  34. data/features/step_definitions/logging_steps.rb +28 -0
  35. data/features/step_definitions/message_consumers_steps.rb +29 -0
  36. data/features/step_definitions/steps.rb +60 -9
  37. data/features/support/broker_config_helper.rb +19 -0
  38. data/features/support/env.rb +1 -0
  39. data/features/support/firewall_helper.rb +8 -11
  40. data/features/support/message_table_matcher.rb +21 -5
  41. data/features/support/test_runner.rb +39 -16
  42. data/lib/message_driver/adapters/base.rb +51 -4
  43. data/lib/message_driver/adapters/bunny_adapter.rb +251 -127
  44. data/lib/message_driver/adapters/in_memory_adapter.rb +97 -18
  45. data/lib/message_driver/adapters/stomp_adapter.rb +127 -0
  46. data/lib/message_driver/broker.rb +23 -24
  47. data/lib/message_driver/client.rb +157 -0
  48. data/lib/message_driver/destination.rb +7 -4
  49. data/lib/message_driver/errors.rb +27 -0
  50. data/lib/message_driver/logging.rb +11 -0
  51. data/lib/message_driver/message.rb +8 -0
  52. data/lib/message_driver/subscription.rb +18 -0
  53. data/lib/message_driver/vendor/.document +0 -0
  54. data/lib/message_driver/vendor/nesty/nested_error.rb +26 -0
  55. data/lib/message_driver/vendor/nesty.rb +1 -0
  56. data/lib/message_driver/version.rb +1 -1
  57. data/lib/message_driver.rb +4 -2
  58. data/message-driver.gemspec +4 -4
  59. data/spec/integration/{amqp_integration_spec.rb → bunny/amqp_integration_spec.rb} +29 -28
  60. data/spec/integration/bunny/bunny_adapter_spec.rb +339 -0
  61. data/spec/integration/in_memory/in_memory_adapter_spec.rb +126 -0
  62. data/spec/integration/stomp/stomp_adapter_spec.rb +142 -0
  63. data/spec/spec_helper.rb +5 -2
  64. data/spec/support/shared/adapter_examples.rb +17 -0
  65. data/spec/support/shared/client_ack_examples.rb +18 -0
  66. data/spec/support/shared/context_examples.rb +14 -0
  67. data/spec/support/shared/destination_examples.rb +4 -5
  68. data/spec/support/shared/subscription_examples.rb +146 -0
  69. data/spec/support/shared/transaction_examples.rb +43 -0
  70. data/spec/support/utils.rb +14 -0
  71. data/spec/units/message_driver/adapters/base_spec.rb +38 -19
  72. data/spec/units/message_driver/broker_spec.rb +71 -18
  73. data/spec/units/message_driver/client_spec.rb +375 -0
  74. data/spec/units/message_driver/destination_spec.rb +9 -0
  75. data/spec/units/message_driver/logging_spec.rb +18 -0
  76. data/spec/units/message_driver/message_spec.rb +36 -0
  77. data/spec/units/message_driver/subscription_spec.rb +24 -0
  78. data/test_lib/broker_config.rb +50 -20
  79. metadata +83 -45
  80. data/.rbenv-version +0 -1
  81. data/lib/message_driver/exceptions.rb +0 -18
  82. data/lib/message_driver/message_publisher.rb +0 -15
  83. data/spec/integration/message_driver/adapters/bunny_adapter_spec.rb +0 -301
  84. data/spec/units/message_driver/adapters/in_memory_adapter_spec.rb +0 -43
  85. data/spec/units/message_driver/message_publisher_spec.rb +0 -65
@@ -0,0 +1,116 @@
1
+ @bunny
2
+ Feature: DLQ-ing messages with nacks and consumers
3
+
4
+ RabbitMQ supports sending messages to a DLQ if configured correctly.
5
+ See http://www.rabbitmq.com/dlx.html for details.
6
+
7
+ Background:
8
+ Given the following broker configuration
9
+ """ruby
10
+ MessageDriver::Broker.define do |b|
11
+ # declare a dead letter exchange
12
+ b.destination :rabbit_dlx, "rabbit.dead.letter.exchange", type: :exchange, declare: { type: :fanout }
13
+
14
+ # declare a dead letter queue and bind it to the exchange
15
+ b.destination :rabbit_dlq, "rabbit.dead.letter.queue", bindings: [
16
+ { source: "rabbit.dead.letter.exchange" }
17
+ ]
18
+
19
+ # declare a work queue that sends dead letters to our dead letter queue
20
+ b.destination :rabbit_work, "rabbit.work", arguments: { :"x-dead-letter-exchange" => "rabbit.dead.letter.exchange" }
21
+ end
22
+ """
23
+ And I have no messages on :rabbit_work
24
+ And I have no messages on :rabbit_dlq
25
+
26
+ Scenario: Nacking a message with requeue false
27
+ Given I send the following message to :rabbit_work
28
+ | body |
29
+ | Nack Test 1 |
30
+
31
+ When I execute the following code
32
+ """ruby
33
+ message = MessageDriver::Client.pop_message(:rabbit_work, client_ack: true)
34
+ message.nack(requeue: false)
35
+ """
36
+
37
+ Then I expect to find no messages on :rabbit_work
38
+ And I expect to find the following 1 message on :rabbit_dlq
39
+ | body |
40
+ | Nack Test 1 |
41
+
42
+
43
+ Scenario: Nacking a message on a manual_ack consumer
44
+ Given I have a message consumer
45
+ """ruby
46
+ MessageDriver::Broker.consumer(:manual_dql) do |message|
47
+ message.nack(requeue: false)
48
+ end
49
+ """
50
+ And I create a subscription
51
+ """ruby
52
+ MessageDriver::Client.subscribe(:rabbit_work, :manual_dql, ack: :manual)
53
+ """
54
+
55
+ When I send the following messages to :rabbit_work
56
+ | body |
57
+ | Manual Nack 1 |
58
+ | Manual Nack 2 |
59
+ And I let the subscription process
60
+
61
+ Then I expect to find no messages on :rabbit_work
62
+ And I expect to find the following 2 messages on :rabbit_dlq
63
+ | body |
64
+ | Manual Nack 1 |
65
+ | Manual Nack 2 |
66
+
67
+
68
+ Scenario: Raising a DontRequeueError in an auto_ack consumer
69
+ Given I have a message consumer
70
+ """ruby
71
+ MessageDriver::Broker.consumer(:manual_dql) do |message|
72
+ raise MessageDriver::DontRequeueError
73
+ end
74
+ """
75
+ And I create a subscription
76
+ """ruby
77
+ MessageDriver::Client.subscribe(:rabbit_work, :manual_dql, ack: :auto)
78
+ """
79
+
80
+ When I send the following messages to :rabbit_work
81
+ | body |
82
+ | Auto Nack 1 |
83
+ | Auto Nack 2 |
84
+ And I let the subscription process
85
+
86
+ Then I expect to find no messages on :rabbit_work
87
+ And I expect to find the following 2 messages on :rabbit_dlq
88
+ | body |
89
+ | Auto Nack 1 |
90
+ | Auto Nack 2 |
91
+
92
+
93
+ Scenario: Raising a DontRequeueError in a transactional consumer
94
+ Given I have a message consumer
95
+ """ruby
96
+ MessageDriver::Broker.consumer(:transactional_dql) do |message|
97
+ publish(:rabbit_work, "I get rolled back")
98
+ raise MessageDriver::DontRequeueError
99
+ end
100
+ """
101
+ And I create a subscription
102
+ """ruby
103
+ MessageDriver::Client.subscribe(:rabbit_work, :transactional_dql, ack: :transactional)
104
+ """
105
+
106
+ When I send the following messages to :rabbit_work
107
+ | body |
108
+ | Transactional Nack 1 |
109
+ | Transactional Nack 2 |
110
+ And I let the subscription process
111
+
112
+ Then I expect to find no messages on :rabbit_work
113
+ And I expect to find the following 2 messages on :rabbit_dlq
114
+ | body |
115
+ | Transactional Nack 1 |
116
+ | Transactional Nack 2 |
@@ -1,9 +1,9 @@
1
- Given(/^I have a dynamic destination "(#{STRING_OR_SYM})" with the following messages on it:$/) do |destination, table|
2
- dest = MessageDriver::Broker.dynamic_destination(destination, exclusive: true)
1
+ Given(/^I have a dynamic destination "(#{STRING_OR_SYM})" with the following messages on it$/) do |destination, table|
2
+ dest = MessageDriver::Broker.dynamic_destination(destination)
3
3
  test_runner.publish_table_to_destination(dest, table)
4
4
  end
5
5
 
6
- Then(/^I expect to find (#{NUMBER}) messages? on the dynamic destination "(#{STRING_OR_SYM})" with:$/) do |count, destination, table|
6
+ Then(/^I expect to find (#{NUMBER}) messages? on the dynamic destination "(#{STRING_OR_SYM})" with$/) do |count, destination, table|
7
7
  expect(test_runner).to have_no_errors
8
8
  dest = MessageDriver::Broker.dynamic_destination(destination, passive: true)
9
9
  messages = test_runner.fetch_messages(dest)
@@ -1,9 +1,11 @@
1
1
  When "the broker goes down" do
2
- result = block_broker_port
2
+ block_broker_port
3
+ sleep 2
3
4
  end
4
5
 
5
6
  When "the broker comes up" do
6
- result = unblock_broker_port
7
+ unblock_broker_port
8
+ sleep 20
7
9
  end
8
10
 
9
11
  After do
@@ -0,0 +1,28 @@
1
+ require 'logger'
2
+
3
+ LOG_FILE_NAME = "cucumber_log_file.log"
4
+
5
+ Given(/^I am logging to a log file(?: at the (#{STRING_OR_SYM}) level)?$/) do |level|
6
+ step "an empty file named \"#{LOG_FILE_NAME}\""
7
+ in_current_dir do
8
+ @logger = Logger.new(LOG_FILE_NAME)
9
+ end
10
+ step "I set the log level to #{level || "info"}"
11
+ scenario_config[:logger] = @logger
12
+ end
13
+
14
+ Given(/^I set the log level to (#{STRING_OR_SYM})$/) do |level|
15
+ level = level ? level.to_s.upcase : "INFO"
16
+ @logger.level = Logger::SEV_LABEL.find_index(level)
17
+ end
18
+
19
+ Then "the log file should contain:" do |string|
20
+ step "the file \"#{LOG_FILE_NAME}\" should contain:", string
21
+ end
22
+
23
+ After do
24
+ if @logger
25
+ @logger.close
26
+ @logger = nil
27
+ end
28
+ end
@@ -0,0 +1,29 @@
1
+ Given "I have a message consumer" do |src|
2
+ test_runner.run_config_code(src)
3
+ expect(test_runner).to have_no_errors
4
+ end
5
+
6
+ Given(/^I subscribe to (#{STRING_OR_SYM}) with (#{STRING_OR_SYM})$/) do |destination, consumer|
7
+ MessageDriver::Client.subscribe(destination, consumer)
8
+ end
9
+
10
+ Given "I create a subscription" do |src|
11
+ test_runner.run_test_code("@subscription = #{src}")
12
+ expect(test_runner).to have_no_errors
13
+ end
14
+
15
+ When "I cancel the subscription" do
16
+ test_runner.run_test_code("@subscription.unsubscribe")
17
+ step "I allow for processing"
18
+ end
19
+
20
+ When "I let the subscription process" do
21
+ step "I allow for processing"
22
+ step "I cancel the subscription"
23
+ expect(test_runner).to have_no_errors
24
+ end
25
+
26
+ When "I restart the subscription" do
27
+ test_runner.run_test_code("@subscription.start")
28
+ step "I allow for processing"
29
+ end
@@ -1,27 +1,68 @@
1
1
  Given "I am connected to the broker" do
2
- MessageDriver.configure(BrokerConfig.config)
2
+ MessageDriver.configure(broker_config)
3
3
  end
4
4
 
5
- Given "the following broker configuration:" do |src|
5
+ Given "the following broker configuration" do |src|
6
6
  step "I am connected to the broker"
7
- test_runner.config_broker(src)
7
+ test_runner.run_config_code(src)
8
8
  end
9
9
 
10
- When "I execute the following code:" do |src|
10
+ Given(/^I have a destination (#{STRING_OR_SYM})$/) do |destination|
11
+ MessageDriver::Broker.define do |b|
12
+ b.destination(destination, destination.to_s)
13
+ end
14
+ end
15
+
16
+ Given(/^I have a destination (#{STRING_OR_SYM}) with no messages on it$/) do |destination|
17
+ dest = destination.kind_of?(Symbol) ? destination.inspect : destination.to_s
18
+ step "I have a destination #{dest}"
19
+ test_runner.purge_destination(destination)
20
+ end
21
+
22
+ Given(/^I have the following messages? on (#{STRING_OR_SYM})$/) do |destination, table|
23
+ test_runner.purge_destination(destination)
24
+ dest = destination.kind_of?(Symbol) ? destination.inspect : destination.to_s
25
+ step "I send the following messages to #{dest}", table
26
+ end
27
+
28
+ Given(/^I have no messages on (#{STRING_OR_SYM})$/) do |destination|
29
+ test_runner.purge_destination(destination)
30
+ end
31
+
32
+ When(/^I send the following messages? to (#{STRING_OR_SYM})$/) do |destination, table|
33
+ table.hashes.each do |msg|
34
+ MessageDriver::Client.publish(destination, msg[:body])
35
+ end
36
+ end
37
+
38
+ When "I execute the following code" do |src|
11
39
  test_runner.run_test_code(src)
12
40
  end
13
41
 
42
+ When "I reset the context" do
43
+ MessageDriver::Client.current_adapter_context.invalidate
44
+ end
45
+
46
+ When "I allow for processing" do
47
+ test_runner.pause_if_needed
48
+ end
49
+
14
50
  Then(/^I expect to find (#{NUMBER}) messages? on (#{STRING_OR_SYM})$/) do |count, destination|
15
51
  expect(test_runner).to have_no_errors
16
52
  messages = test_runner.fetch_messages(destination)
17
- expect(messages).to have(count).items
53
+ expect(messages).to have(count).items, "expected #{count} messages, but got these instead: #{messages.map(&:body)}"
18
54
  end
19
55
 
20
- Then(/^I expect to find (#{NUMBER}) messages? on (#{STRING_OR_SYM}) with:$/) do |count, destination, table|
56
+ Then(/^I expect to find the following (#{NUMBER}) messages? on (#{STRING_OR_SYM})$/) do |count, destination, table|
21
57
  expect(test_runner).to have_no_errors
22
58
  messages = test_runner.fetch_messages(destination)
23
- expect(messages).to have(count).items
24
59
  expect(messages).to match_message_table(table)
60
+ expect(messages).to have(count).items
61
+ end
62
+
63
+ Then(/^I expect to find the following message on (#{STRING_OR_SYM})$/) do |destination, table|
64
+ dest = destination.kind_of?(Symbol) ? destination.inspect : destination.to_s
65
+ step "I expect to find the following 1 message on #{dest}", table
25
66
  end
26
67
 
27
68
  Then(/^I expect it to raise "(.*?)"$/) do |error_msg|
@@ -31,11 +72,21 @@ Then(/^I expect it to raise "(.*?)"$/) do |error_msg|
31
72
  end
32
73
 
33
74
  Then(/^I expect it to raise a (.*?) error$/) do |error_type|
34
- expect(test_runner.raised_error).to_not be_nil
35
- expect(test_runner.raised_error.class.to_s).to match error_type
75
+ err = test_runner.raised_error
76
+ expect(err).to_not be_nil
77
+ expect(err.class.to_s).to match error_type
36
78
  test_runner.raised_error = nil
37
79
  end
38
80
 
39
81
  Then "I expect to have no errors" do
40
82
  expect(test_runner).to have_no_errors
41
83
  end
84
+
85
+ Then "I expect the following check to pass" do |src|
86
+ step "I execute the following code", src
87
+ step "I expect to have no errors"
88
+ end
89
+
90
+ Before do |current_scenario|
91
+ test_runner.current_feature_file = current_scenario.feature.file
92
+ end
@@ -0,0 +1,19 @@
1
+ module BrokerConfigHelper
2
+ def broker_config
3
+ BrokerConfig.config.merge(@config)
4
+ end
5
+
6
+ def reset_broker_config
7
+ @config = {}
8
+ end
9
+
10
+ def scenario_config
11
+ @config
12
+ end
13
+ end
14
+
15
+ Before do
16
+ reset_broker_config
17
+ end
18
+
19
+ World(BrokerConfigHelper)
@@ -1,5 +1,6 @@
1
1
  require File.join(File.dirname(__FILE__), '..', '..', 'test_lib', 'broker_config')
2
2
 
3
+ require 'aruba/cucumber'
3
4
  require 'message_driver'
4
5
 
5
6
  After do
@@ -1,27 +1,24 @@
1
1
  module FirewallHelper
2
2
 
3
+ def self.port
4
+ BrokerConfig.current_adapter_port
5
+ end
6
+
3
7
  COMMANDS = {
4
8
  darwin: {
5
9
  setup: [
6
- "sudo ipfw add 02070 deny tcp from any to any 5672"
10
+ "lunchy stop rabbit"
7
11
  ],
8
12
  teardown: [
9
- "sudo ipfw delete 02070"
13
+ "lunchy start rabbit"
10
14
  ]
11
15
  },
12
16
  linux: {
13
17
  setup: [
14
- "sudo iptables -N block-rabbit",
15
- "sudo iptables -A block-rabbit -p tcp --dport 5672 -j DROP",
16
- "sudo iptables -A block-rabbit -p tcp --sport 5672 -j DROP",
17
- "sudo iptables -I INPUT -j block-rabbit",
18
- "sudo iptables -I OUTPUT -j block-rabbit"
18
+ "sudo service rabbitmq-server stop"
19
19
  ],
20
20
  teardown: [
21
- "sudo iptables -D INPUT -j block-rabbit",
22
- "sudo iptables -D OUTPUT -j block-rabbit",
23
- "sudo iptables -F block-rabbit",
24
- "sudo iptables -X block-rabbit"
21
+ "sudo service rabbitmq-server start"
25
22
  ]
26
23
  }
27
24
  }
@@ -1,11 +1,27 @@
1
- RSpec::Matchers.define :match_message_table do |expected|
2
- match do |messages|
3
- actual = messages.collect do |msg|
4
- expected.headers.inject({}) do |memo, obj|
1
+ RSpec::Matchers.define :match_message_table do |expected_tbl|
2
+ define_method :expected_hash do
3
+ @expected_hash ||= expected_tbl.hashes
4
+ end
5
+
6
+ define_method :messages_to_hash do |messages|
7
+ messages.collect do |msg|
8
+ expected_tbl.headers.inject({ }) do |memo, obj|
5
9
  memo[obj] = msg.send(obj)
6
10
  memo
7
11
  end
8
12
  end
9
- actual == expected.hashes
13
+ end
14
+
15
+ match do |messages|
16
+ @actual = messages_to_hash(messages)
17
+ @actual == expected_hash
18
+ end
19
+
20
+ failure_message_for_should do |_|
21
+ "expected #{expected_hash} and got #{@actual}"
22
+ end
23
+
24
+ description do
25
+ "contain messages #{expected_hash}"
10
26
  end
11
27
  end
@@ -1,36 +1,50 @@
1
- require 'message_driver'
2
-
3
1
  class TestRunner
4
- include MessageDriver::MessagePublisher
2
+ include MessageDriver::Client
5
3
  include RSpec::Matchers
6
4
 
7
5
  attr_accessor :raised_error
6
+ attr_accessor :current_feature_file
8
7
 
9
- def config_broker(src)
10
- instance_eval(src)
8
+ def run_config_code(src)
9
+ instance_eval(src, current_feature_file)
11
10
  end
12
11
 
13
12
  def run_test_code(src)
14
13
  begin
15
- instance_eval(src)
16
- rescue Exception => e
14
+ instance_eval(src, current_feature_file)
15
+ rescue => e
17
16
  @raised_error = e
18
17
  end
19
18
  end
20
19
 
21
- def fetch_messages(destination)
20
+ def fetch_messages(destination_name)
21
+ destination = fetch_destination(destination_name)
22
+ pause_if_needed
23
+ result = []
24
+ begin
25
+ msg = destination.pop_message
26
+ result << msg unless msg.nil?
27
+ end until msg.nil?
28
+ result
29
+ end
30
+
31
+ def purge_destination(destination_name)
32
+ destination = fetch_destination(destination_name)
33
+ if destination.respond_to? :purge
34
+ destination.purge
35
+ else
36
+ fetch_messages(destination)
37
+ end
38
+ end
39
+
40
+ def fetch_destination(destination)
22
41
  case destination
23
42
  when String, Symbol
24
- fetch_messages(MessageDriver::Broker.find_destination(destination))
43
+ MessageDriver::Broker.find_destination(destination)
25
44
  when MessageDriver::Destination::Base
26
- result = []
27
- begin
28
- msg = destination.pop_message
29
- result << msg unless msg.nil?
30
- end until msg.nil?
31
- result
45
+ destination
32
46
  else
33
- raise "didn't understand destination #{destination}"
47
+ raise "didn't understand destination #{destination.inspect}"
34
48
  end
35
49
  end
36
50
 
@@ -39,6 +53,15 @@ class TestRunner
39
53
  destination.publish(msg[:body], msg[:headers]||{}, msg[:properties]||{})
40
54
  end
41
55
  end
56
+
57
+ def pause_if_needed(seconds=0.1)
58
+ seconds *= 10 if ENV['CI'] == 'true'
59
+ case BrokerConfig.current_adapter
60
+ when :in_memory
61
+ else
62
+ sleep seconds
63
+ end
64
+ end
42
65
  end
43
66
 
44
67
  module KnowsMyTestRunner
@@ -1,10 +1,41 @@
1
1
  module MessageDriver
2
2
  module Adapters
3
3
  class Base
4
+ include Logging
5
+
6
+ attr_accessor :contexts
7
+
4
8
  def initialize(configuration)
5
9
  raise "Must be implemented in subclass"
6
10
  end
7
11
 
12
+ def new_context
13
+ @contexts ||= []
14
+ ctx = build_context
15
+ contexts << ctx
16
+ ctx
17
+ end
18
+
19
+ def build_context
20
+ raise "Must be implemented in subclass"
21
+ end
22
+
23
+ def stop
24
+ contexts.each { |ctx| ctx.invalidate } if contexts
25
+ end
26
+ end
27
+
28
+ class ContextBase
29
+ include Logging
30
+
31
+ attr_reader :adapter
32
+ attr_accessor :valid
33
+
34
+ def initialize(adapter)
35
+ @adapter = adapter
36
+ @valid = true
37
+ end
38
+
8
39
  def publish(destination, body, headers={}, properties={})
9
40
  raise "Must be implemented in subclass"
10
41
  end
@@ -13,16 +44,32 @@ module MessageDriver
13
44
  raise "Must be implemented in subclass"
14
45
  end
15
46
 
16
- def stop
17
- raise "Must be implemented in subclass"
47
+ def subscribe(destination, options={}, &consumer)
48
+ raise "#subscribe is not supported by #{adapter.class}"
18
49
  end
19
50
 
20
51
  def create_destination(name, dest_options={}, message_props={})
21
52
  raise "Must be implemented in subclass"
22
53
  end
23
54
 
24
- def with_transaction(options={}, &block)
25
- yield
55
+ def valid?
56
+ @valid
57
+ end
58
+
59
+ def invalidate
60
+ @valid = false
61
+ end
62
+
63
+ def supports_transactions?
64
+ false
65
+ end
66
+
67
+ def supports_client_acks?
68
+ false
69
+ end
70
+
71
+ def supports_subscriptions?
72
+ false
26
73
  end
27
74
  end
28
75
  end