message-driver 0.1.0 → 0.2.0.rc1

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