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.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/.travis.yml +18 -7
- data/CHANGELOG.md +12 -2
- data/Gemfile +17 -0
- data/Guardfile +8 -4
- data/README.md +14 -5
- data/Rakefile +44 -11
- data/examples/basic_producer_and_consumer/Gemfile +5 -0
- data/examples/basic_producer_and_consumer/common.rb +17 -0
- data/examples/basic_producer_and_consumer/consumer.rb +24 -0
- data/examples/basic_producer_and_consumer/producer.rb +33 -0
- data/features/.nav +8 -0
- data/features/CHANGELOG.md +12 -2
- data/features/amqp_specific_features/binding_amqp_destinations.feature +7 -7
- data/features/amqp_specific_features/declaring_amqp_exchanges.feature +3 -3
- data/features/amqp_specific_features/nack_redelivered_messages.feature +92 -0
- data/features/amqp_specific_features/requeueing_on_nack.feature +44 -0
- data/features/amqp_specific_features/server_named_destinations.feature +5 -5
- data/features/client_acks.feature +92 -0
- data/features/destination_metadata.feature +9 -11
- data/features/dynamic_destinations.feature +7 -7
- data/features/error_handling.feature +11 -9
- data/features/logging.feature +14 -0
- data/features/message_consumers/auto_ack_consumers.feature +79 -0
- data/features/message_consumers/manual_ack_consumers.feature +95 -0
- data/features/message_consumers/transactional_ack_consumers.feature +77 -0
- data/features/message_consumers.feature +54 -0
- data/features/publishing_a_message.feature +6 -10
- data/features/publishing_with_transactions.feature +10 -14
- data/features/rabbitmq_specific_features/dead_letter_queueing.feature +116 -0
- data/features/step_definitions/dynamic_destinations_steps.rb +3 -3
- data/features/step_definitions/error_handling_steps.rb +4 -2
- data/features/step_definitions/logging_steps.rb +28 -0
- data/features/step_definitions/message_consumers_steps.rb +29 -0
- data/features/step_definitions/steps.rb +60 -9
- data/features/support/broker_config_helper.rb +19 -0
- data/features/support/env.rb +1 -0
- data/features/support/firewall_helper.rb +8 -11
- data/features/support/message_table_matcher.rb +21 -5
- data/features/support/test_runner.rb +39 -16
- data/lib/message_driver/adapters/base.rb +51 -4
- data/lib/message_driver/adapters/bunny_adapter.rb +251 -127
- data/lib/message_driver/adapters/in_memory_adapter.rb +97 -18
- data/lib/message_driver/adapters/stomp_adapter.rb +127 -0
- data/lib/message_driver/broker.rb +23 -24
- data/lib/message_driver/client.rb +157 -0
- data/lib/message_driver/destination.rb +7 -4
- data/lib/message_driver/errors.rb +27 -0
- data/lib/message_driver/logging.rb +11 -0
- data/lib/message_driver/message.rb +8 -0
- data/lib/message_driver/subscription.rb +18 -0
- data/lib/message_driver/vendor/.document +0 -0
- data/lib/message_driver/vendor/nesty/nested_error.rb +26 -0
- data/lib/message_driver/vendor/nesty.rb +1 -0
- data/lib/message_driver/version.rb +1 -1
- data/lib/message_driver.rb +4 -2
- data/message-driver.gemspec +4 -4
- data/spec/integration/{amqp_integration_spec.rb → bunny/amqp_integration_spec.rb} +29 -28
- data/spec/integration/bunny/bunny_adapter_spec.rb +339 -0
- data/spec/integration/in_memory/in_memory_adapter_spec.rb +126 -0
- data/spec/integration/stomp/stomp_adapter_spec.rb +142 -0
- data/spec/spec_helper.rb +5 -2
- data/spec/support/shared/adapter_examples.rb +17 -0
- data/spec/support/shared/client_ack_examples.rb +18 -0
- data/spec/support/shared/context_examples.rb +14 -0
- data/spec/support/shared/destination_examples.rb +4 -5
- data/spec/support/shared/subscription_examples.rb +146 -0
- data/spec/support/shared/transaction_examples.rb +43 -0
- data/spec/support/utils.rb +14 -0
- data/spec/units/message_driver/adapters/base_spec.rb +38 -19
- data/spec/units/message_driver/broker_spec.rb +71 -18
- data/spec/units/message_driver/client_spec.rb +375 -0
- data/spec/units/message_driver/destination_spec.rb +9 -0
- data/spec/units/message_driver/logging_spec.rb +18 -0
- data/spec/units/message_driver/message_spec.rb +36 -0
- data/spec/units/message_driver/subscription_spec.rb +24 -0
- data/test_lib/broker_config.rb +50 -20
- metadata +83 -45
- data/.rbenv-version +0 -1
- data/lib/message_driver/exceptions.rb +0 -18
- data/lib/message_driver/message_publisher.rb +0 -15
- data/spec/integration/message_driver/adapters/bunny_adapter_spec.rb +0 -301
- data/spec/units/message_driver/adapters/in_memory_adapter_spec.rb +0 -43
- 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
|
2
|
-
dest = MessageDriver::Broker.dynamic_destination(destination
|
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
|
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)
|
@@ -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(
|
2
|
+
MessageDriver.configure(broker_config)
|
3
3
|
end
|
4
4
|
|
5
|
-
Given "the following broker configuration
|
5
|
+
Given "the following broker configuration" do |src|
|
6
6
|
step "I am connected to the broker"
|
7
|
-
test_runner.
|
7
|
+
test_runner.run_config_code(src)
|
8
8
|
end
|
9
9
|
|
10
|
-
|
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})
|
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
|
-
|
35
|
-
expect(
|
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)
|
data/features/support/env.rb
CHANGED
@@ -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
|
-
"
|
10
|
+
"lunchy stop rabbit"
|
7
11
|
],
|
8
12
|
teardown: [
|
9
|
-
"
|
13
|
+
"lunchy start rabbit"
|
10
14
|
]
|
11
15
|
},
|
12
16
|
linux: {
|
13
17
|
setup: [
|
14
|
-
"sudo
|
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
|
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 |
|
2
|
-
|
3
|
-
|
4
|
-
|
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
|
-
|
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::
|
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
|
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
|
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(
|
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
|
-
|
43
|
+
MessageDriver::Broker.find_destination(destination)
|
25
44
|
when MessageDriver::Destination::Base
|
26
|
-
|
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
|
17
|
-
raise "
|
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
|
25
|
-
|
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
|