beetle 3.4.2 → 3.5.3
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.
- checksums.yaml +4 -4
- data/Rakefile +8 -12
- data/beetle.gemspec +3 -1
- data/examples/redundant.rb +1 -1
- data/examples/rpc.rb +1 -1
- data/features/redis_auto_failover.feature +20 -0
- data/features/step_definitions/redis_auto_failover_steps.rb +28 -8
- data/features/support/test_daemons/redis_configuration_server.rb +2 -1
- data/lib/beetle/base.rb +8 -6
- data/lib/beetle/client.rb +13 -2
- data/lib/beetle/publisher.rb +19 -11
- data/lib/beetle/subscriber.rb +7 -5
- data/lib/beetle/version.rb +1 -1
- data/test/beetle/amqp_gem_behavior_test.rb +1 -1
- data/test/beetle/base_test.rb +1 -1
- data/test/beetle/client_test.rb +45 -4
- data/test/beetle/deduplication_store_test.rb +1 -1
- data/test/beetle/publisher_test.rb +54 -12
- data/test/beetle/subscriber_test.rb +18 -3
- data/test/test_helper.rb +8 -7
- metadata +51 -31
- data/README.rdoc +0 -233
- data/REDIS_AUTO_FAILOVER.rdoc +0 -116
- data/RELEASE_NOTES.rdoc +0 -373
- data/examples/README.rdoc +0 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bce54bf1dc2290bb4c1598f6210b1c292d09691e91df2f67e913747535c90f2d
|
4
|
+
data.tar.gz: e6f510fb5b78a7ed0483f713920222ff1959e7a3e3073aac61abed25af56b0bd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8682a1720108f7e95ad9802bcfe5b30283c735cfaa67323e5aca6bca1e1c06d0b6bb58d8fd2b8f4fc1fb7032579832667b78bab0c0f7013a937556650ad14ad7
|
7
|
+
data.tar.gz: 255b3fd3827a1f33c1c244967649ab8eaa1adc8f6daa3a111b21e299f1bcc0341f324a1bee3f2c578f5c93b39eeb913caf2c3a6d8ea88d1e89c028c48576e1b0
|
data/Rakefile
CHANGED
@@ -115,18 +115,14 @@ Rake::TestTask.new do |t|
|
|
115
115
|
t.warning = false
|
116
116
|
end
|
117
117
|
|
118
|
-
|
119
|
-
|
120
|
-
RDoc::Task.new do |rdoc|
|
121
|
-
rdoc.rdoc_dir = 'site/rdoc'
|
122
|
-
rdoc.title = 'Beetle'
|
123
|
-
rdoc.main = 'README.rdoc'
|
124
|
-
rdoc.options << '--line-numbers' << '--inline-source' << '--quiet'
|
125
|
-
rdoc.rdoc_files.include('**/*.rdoc')
|
126
|
-
rdoc.rdoc_files.include('MIT-LICENSE')
|
127
|
-
rdoc.rdoc_files.include('lib/**/*.rb')
|
118
|
+
task :clean do
|
119
|
+
sh "rm -f tmp/*.output tmp/*.log tmp/master-dir/* tmp/slave-dir/* tmp/*lock tmp/*pid test.log" unless ENV['GITHUB_ACTIONS']
|
128
120
|
end
|
129
121
|
|
130
|
-
|
131
|
-
|
122
|
+
require 'yard'
|
123
|
+
|
124
|
+
YARD::Rake::YardocTask.new do |t|
|
125
|
+
OTHER_PATHS = %w()
|
126
|
+
t.files = ['lib/**/*.rb'] + OTHER_PATHS
|
127
|
+
t.options = %w(--markup-provider=redcarpet --markup=markdown --main=README.md --output-dir=site/yard)
|
132
128
|
end
|
data/beetle.gemspec
CHANGED
@@ -39,8 +39,10 @@ Gem::Specification.new do |s|
|
|
39
39
|
s.add_development_dependency "mocha", "~> 1.3.0"
|
40
40
|
s.add_development_dependency "mysql2", "~> 0.4.4"
|
41
41
|
s.add_development_dependency "rake", "~> 13.0"
|
42
|
-
s.add_development_dependency "rdoc", "~> 4.0"
|
43
42
|
s.add_development_dependency "simplecov", "~> 0.15"
|
44
43
|
s.add_development_dependency "webmock", "~> 3.0"
|
45
44
|
s.add_development_dependency "websocket-eventmachine-client"
|
45
|
+
s.add_development_dependency 'yard'
|
46
|
+
s.add_development_dependency 'redcarpet'
|
47
|
+
s.add_development_dependency 'github-markup'
|
46
48
|
end
|
data/examples/redundant.rb
CHANGED
@@ -17,7 +17,7 @@ Beetle.config.logger.level = Logger::INFO
|
|
17
17
|
client = Beetle::Client.new
|
18
18
|
|
19
19
|
# use two servers
|
20
|
-
Beetle.config.servers = "localhost:5672, localhost:5673"
|
20
|
+
Beetle.config.servers = ENV["RABBITMQ_SERVERS"] || "localhost:5672, localhost:5673"
|
21
21
|
# instantiate a client
|
22
22
|
client = Beetle::Client.new
|
23
23
|
|
data/examples/rpc.rb
CHANGED
@@ -4,7 +4,7 @@ require File.expand_path(File.dirname(__FILE__)+"/../lib/beetle")
|
|
4
4
|
|
5
5
|
# suppress debug messages
|
6
6
|
Beetle.config.logger.level = Logger::INFO
|
7
|
-
Beetle.config.servers = "localhost:5672, localhost:5673"
|
7
|
+
Beetle.config.servers = ENV["RABBITMQ_SERVERS"] || "localhost:5672, localhost:5673"
|
8
8
|
# instantiate a client
|
9
9
|
|
10
10
|
client = Beetle::Client.new
|
@@ -24,6 +24,26 @@ Feature: Redis auto failover
|
|
24
24
|
Given a redis server "redis-1" exists as master
|
25
25
|
Then the role of redis server "redis-1" should be "slave"
|
26
26
|
|
27
|
+
Scenario: Successful redis master switch with multiple slaves
|
28
|
+
And a redis server "redis-3" exists as slave of "redis-3"
|
29
|
+
Given a redis configuration server using redis servers "redis-1,redis-2,redis-3" with clients "rc-client-1,rc-client-2" exists
|
30
|
+
And a redis configuration client "rc-client-1" using redis servers "redis-1,redis-2,redis-3" exists
|
31
|
+
And a redis configuration client "rc-client-2" using redis servers "redis-1,redis-2,redis-3" exists
|
32
|
+
And a beetle handler using the redis-master file from "rc-client-1" exists
|
33
|
+
And redis server "redis-1" is down
|
34
|
+
And the retry timeout for the redis master check is reached
|
35
|
+
Then a system notification for "redis-1" not being available should be sent
|
36
|
+
And the role of redis server "redis-2" should be "master"
|
37
|
+
And the redis master file of the redis configuration server should contain "redis-2"
|
38
|
+
And the redis master of "rc-client-1" should be "redis-2"
|
39
|
+
And the redis master of "rc-client-2" should be "redis-2"
|
40
|
+
And the redis master of the beetle handler should be "redis-2"
|
41
|
+
And a system notification for switching from "redis-1" to "redis-2" should be sent
|
42
|
+
Given a redis server "redis-1" exists as master
|
43
|
+
Then the role of redis server "redis-1" should be "slave"
|
44
|
+
And the redis server "redis-1" is a slave of "redis-2"
|
45
|
+
And the redis server "redis-3" is a slave of "redis-2"
|
46
|
+
|
27
47
|
Scenario: Successful single redis master switch with multiple failover sets
|
28
48
|
Given a redis server "redis-3" exists as master
|
29
49
|
And a redis server "redis-4" exists as slave of "redis-3"
|
@@ -1,8 +1,9 @@
|
|
1
1
|
Given /^consul state has been cleared$/ do
|
2
|
+
consul_host = ENV["CONSUL_HOST"] || "localhost:8500"
|
2
3
|
system "killall beetle beetle_handler >/dev/null 2>/dev/null"
|
3
|
-
system "curl --silent --request PUT http
|
4
|
-
system "curl --silent --request PUT http
|
5
|
-
system "curl --silent --request DELETE http
|
4
|
+
system "curl --silent --request PUT http://#{consul_host}/v1/kv/apps/beetle/config/ >/dev/null"
|
5
|
+
system "curl --silent --request PUT http://#{consul_host}/v1/kv/shared/config/ >/dev/null"
|
6
|
+
system "curl --silent --request DELETE http://#{consul_host}/v1/kv/apps/beetle/state/redis_master_file_content >/dev/null"
|
6
7
|
end
|
7
8
|
|
8
9
|
Given /^a redis server "([^\"]*)" exists as master$/ do |redis_name|
|
@@ -93,7 +94,6 @@ Given /^an old redis master file for "([^\"]*)" with master "([^\"]*)" exists$/
|
|
93
94
|
end
|
94
95
|
end
|
95
96
|
|
96
|
-
|
97
97
|
Then /^the role of redis server "([^\"]*)" should be "(master|slave)"$/ do |redis_name, role|
|
98
98
|
expected_role = false
|
99
99
|
10.times do
|
@@ -103,6 +103,16 @@ Then /^the role of redis server "([^\"]*)" should be "(master|slave)"$/ do |redi
|
|
103
103
|
assert expected_role, "#{redis_name} is not a #{role}"
|
104
104
|
end
|
105
105
|
|
106
|
+
Then /^the redis server "([^\"]*)" is a slave of "([^\"]*)"$/ do |redis_name, redis_master_name|
|
107
|
+
master = TestDaemons::Redis[redis_master_name].redis
|
108
|
+
slave = TestDaemons::Redis[redis_name].redis
|
109
|
+
3.times do
|
110
|
+
sleep 1
|
111
|
+
break if slave.slave_of?(master.host, master.port)
|
112
|
+
end
|
113
|
+
assert slave.slave_of?(master.host, master.port)
|
114
|
+
end
|
115
|
+
|
106
116
|
Then /^the redis master of "([^\"]*)" (?:in system "([^"]*)" )?should be "([^\"]*)"$/ do |redis_configuration_client_name, system_name, redis_name|
|
107
117
|
system_name ||= "system"
|
108
118
|
master_file = redis_master_file(redis_configuration_client_name)
|
@@ -143,11 +153,21 @@ end
|
|
143
153
|
Then /^the redis master of the beetle handler should be "([^\"]*)"$/ do |redis_name|
|
144
154
|
Beetle.config.servers = "127.0.0.1:5672" # rabbitmq
|
145
155
|
Beetle.config.logger.level = Logger::INFO
|
146
|
-
|
147
|
-
|
148
|
-
|
156
|
+
redis_master = TestDaemons::Redis[redis_name].ip_with_port
|
157
|
+
response = nil
|
158
|
+
expected_response = ['OK', redis_master]
|
159
|
+
3.times do |i|
|
160
|
+
client = Beetle::Client.new.configure :auto_delete => true do |config|
|
161
|
+
config.queue(:echo, :lazy => true, :dead_lettering => true)
|
162
|
+
config.message(:echo)
|
163
|
+
end
|
164
|
+
t1 = Time.now
|
165
|
+
response = client.rpc(:echo, 'echo')
|
166
|
+
t2 = Time.now
|
167
|
+
# puts "OK,#{redis_master} =?= #{response.join(',')} after #{t2-t1}, attempt #{i+1}"
|
168
|
+
break if expected_response == response
|
149
169
|
end
|
150
|
-
|
170
|
+
assert_equal expected_response, response
|
151
171
|
end
|
152
172
|
|
153
173
|
Then /^a system notification for "([^\"]*)" not being available should be sent$/ do |redis_name|
|
@@ -25,9 +25,10 @@ module TestDaemons
|
|
25
25
|
|
26
26
|
def self.daemon_controller
|
27
27
|
clients_parameter_string = @@redis_configuration_clients.blank? ? "" : "--client-ids #{@@redis_configuration_clients}"
|
28
|
+
consul_host = ENV["CONSUL_HOST"] || "localhost:8500"
|
28
29
|
DaemonController.new(
|
29
30
|
:identifier => "Redis configuration test server",
|
30
|
-
:start_command => "./beetle configuration_server -v -d --redis-master-file #{redis_master_file} --redis-servers '#{@@redis_servers}' #{clients_parameter_string} --redis-master-retry-interval 1 --pid-file #{pid_file} --log-file #{log_file} --redis-failover-confidence-level #{@@confidence_level} --consul http
|
31
|
+
:start_command => "./beetle configuration_server -v -d --redis-master-file #{redis_master_file} --redis-servers '#{@@redis_servers}' #{clients_parameter_string} --redis-master-retry-interval 1 --pid-file #{pid_file} --log-file #{log_file} --redis-failover-confidence-level #{@@confidence_level} --consul http://#{consul_host}",
|
31
32
|
:ping_command => lambda{ answers_text_requests? },
|
32
33
|
:pid_file => pid_file,
|
33
34
|
:log_file => log_file,
|
data/lib/beetle/base.rb
CHANGED
@@ -67,23 +67,25 @@ module Beetle
|
|
67
67
|
logger.debug("Beetle: binding queue #{name} with internal name #{opts[:amqp_name]} on server #{@server}")
|
68
68
|
queue_name = opts[:amqp_name]
|
69
69
|
creation_options = opts.slice(*QUEUE_CREATION_KEYS)
|
70
|
-
|
70
|
+
|
71
|
+
the_queue = declare_queue!(queue_name, creation_options)
|
71
72
|
@client.bindings[name].each do |binding_options|
|
72
73
|
exchange_name = binding_options[:exchange]
|
73
74
|
binding_options = binding_options.slice(*QUEUE_BINDING_KEYS)
|
74
|
-
|
75
|
+
logger.debug("Beetle: binding queue #{queue_name} to #{exchange_name} with opts: #{binding_options.inspect}")
|
76
|
+
bind_queue!(the_queue, exchange_name, binding_options)
|
75
77
|
end
|
76
78
|
the_queue
|
77
79
|
end
|
78
80
|
end
|
79
81
|
|
80
|
-
def bind_dead_letter_queue!(channel, target_queue,
|
82
|
+
def bind_dead_letter_queue!(channel, target_queue, creation_options = {})
|
81
83
|
policy_options = @client.queues[target_queue].slice(:dead_lettering, :lazy, :dead_lettering_msg_ttl)
|
82
84
|
policy_options[:message_ttl] = policy_options.delete(:dead_lettering_msg_ttl)
|
83
85
|
dead_letter_queue_name = "#{target_queue}_dead_letter"
|
84
86
|
if policy_options[:dead_lettering]
|
85
|
-
logger.debug("Beetle: creating dead letter queue #{dead_letter_queue_name} with opts: #{
|
86
|
-
channel.queue(dead_letter_queue_name,
|
87
|
+
logger.debug("Beetle: creating dead letter queue #{dead_letter_queue_name} with opts: #{creation_options.inspect}")
|
88
|
+
channel.queue(dead_letter_queue_name, creation_options)
|
87
89
|
end
|
88
90
|
return {
|
89
91
|
:queue_name => target_queue,
|
@@ -93,7 +95,7 @@ module Beetle
|
|
93
95
|
}.merge(policy_options)
|
94
96
|
end
|
95
97
|
|
96
|
-
# called by <tt>
|
98
|
+
# called by <tt>declare_queue!</tt>
|
97
99
|
def publish_policy_options(options)
|
98
100
|
# avoid endless recursion
|
99
101
|
return if options[:queue_name] == @client.config.beetle_policy_updates_queue_name
|
data/lib/beetle/client.rb
CHANGED
@@ -280,6 +280,13 @@ module Beetle
|
|
280
280
|
publisher.throttled?
|
281
281
|
end
|
282
282
|
|
283
|
+
# set up queues and policies for all configured queues. Otherwise this will
|
284
|
+
# happen on first use of an exchange, which can be undesired for latency
|
285
|
+
# sensitive endpoints. Only needs to be called once.
|
286
|
+
def setup_queues_and_policies
|
287
|
+
publisher.setup_queues_and_policies
|
288
|
+
end
|
289
|
+
|
283
290
|
# traces queues without consuming them. useful for debugging message flow.
|
284
291
|
def trace(queue_names=self.queues.keys, tracer=nil, &block)
|
285
292
|
queues_to_trace = self.queues.slice(*queue_names)
|
@@ -378,8 +385,12 @@ module Beetle
|
|
378
385
|
end
|
379
386
|
|
380
387
|
def load_brokers_from_config
|
381
|
-
@servers = config.servers
|
382
|
-
@additional_subscription_servers = config.additional_subscription_servers
|
388
|
+
@servers = parse_server_list(config.servers)
|
389
|
+
@additional_subscription_servers = parse_server_list(config.additional_subscription_servers) - @servers
|
390
|
+
end
|
391
|
+
|
392
|
+
def parse_server_list(s)
|
393
|
+
s.split(/ *, */).uniq.reject(&:blank?)
|
383
394
|
end
|
384
395
|
end
|
385
396
|
end
|
data/lib/beetle/publisher.rb
CHANGED
@@ -34,7 +34,7 @@ module Beetle
|
|
34
34
|
Bunny::ConnectionError, Bunny::ForcedChannelCloseError, Bunny::ForcedConnectionCloseError,
|
35
35
|
Bunny::MessageError, Bunny::ProtocolError, Bunny::ServerDownError, Bunny::UnsubscribeError,
|
36
36
|
Bunny::AcknowledgementError, Qrack::BufferOverflowError, Qrack::InvalidTypeError,
|
37
|
-
Errno::EHOSTUNREACH, Errno::ECONNRESET, Timeout::Error
|
37
|
+
Errno::EHOSTUNREACH, Errno::ECONNRESET, Errno::ETIMEDOUT, Timeout::Error
|
38
38
|
]
|
39
39
|
end
|
40
40
|
|
@@ -66,6 +66,7 @@ module Beetle
|
|
66
66
|
logger.debug "Beetle: message sent!"
|
67
67
|
published = 1
|
68
68
|
rescue *bunny_exceptions => e
|
69
|
+
logger.warn("Beetle: publishing exception #{e} #{e.backtrace[0..4].join("\n")}")
|
69
70
|
stop!(e)
|
70
71
|
tries -= 1
|
71
72
|
# retry same server on receiving the first exception for it (might have been a normal restart)
|
@@ -98,6 +99,7 @@ module Beetle
|
|
98
99
|
published << @server
|
99
100
|
logger.debug "Beetle: message sent (#{published})!"
|
100
101
|
rescue *bunny_exceptions => e
|
102
|
+
logger.warn("Beetle: publishing exception #{e} #{e.backtrace[0..4].join("\n")}")
|
101
103
|
stop!(e)
|
102
104
|
retry if (tries += 1) == 1
|
103
105
|
mark_server_dead
|
@@ -169,10 +171,14 @@ module Beetle
|
|
169
171
|
end
|
170
172
|
end
|
171
173
|
|
172
|
-
def setup_queues_and_policies
|
174
|
+
def setup_queues_and_policies
|
173
175
|
each_server do
|
174
|
-
|
175
|
-
|
176
|
+
begin
|
177
|
+
@client.queues.keys.each do |name|
|
178
|
+
queue(name)
|
179
|
+
end
|
180
|
+
rescue => e
|
181
|
+
logger.warn "Beetle: failed setting up queues and policies on #{@server}: #{e}"
|
176
182
|
end
|
177
183
|
end
|
178
184
|
end
|
@@ -247,17 +253,19 @@ module Beetle
|
|
247
253
|
@exchanges_with_bound_queues[exchange_name] = true
|
248
254
|
end
|
249
255
|
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
queue.bind(exchange(exchange_name), binding_keys)
|
256
|
-
policy_options = bind_dead_letter_queue!(bunny, queue_name, creation_keys)
|
256
|
+
def declare_queue!(queue_name, creation_options)
|
257
|
+
logger.debug("Beetle: creating queue with opts: #{creation_options.inspect}")
|
258
|
+
queue = bunny.queue(queue_name, creation_options)
|
259
|
+
|
260
|
+
policy_options = bind_dead_letter_queue!(bunny, queue_name, creation_options)
|
257
261
|
publish_policy_options(policy_options)
|
258
262
|
queue
|
259
263
|
end
|
260
264
|
|
265
|
+
def bind_queue!(queue, exchange_name, binding_options)
|
266
|
+
queue.bind(exchange(exchange_name), binding_options)
|
267
|
+
end
|
268
|
+
|
261
269
|
def stop!(exception=nil)
|
262
270
|
return unless bunny?
|
263
271
|
timeout = @client.config.publishing_timeout + @client.config.publisher_connect_timeout + 1
|
data/lib/beetle/subscriber.rb
CHANGED
@@ -214,18 +214,20 @@ module Beetle
|
|
214
214
|
channel.__send__(opts[:type], name, opts.slice(*EXCHANGE_CREATION_KEYS))
|
215
215
|
end
|
216
216
|
|
217
|
-
def
|
218
|
-
queue = channel.queue(queue_name,
|
217
|
+
def declare_queue!(queue_name, creation_options)
|
218
|
+
queue = channel.queue(queue_name, creation_options)
|
219
219
|
unless tracing?
|
220
220
|
# we don't want to create dead-letter queues for tracing
|
221
|
-
policy_options = bind_dead_letter_queue!(channel, queue_name,
|
221
|
+
policy_options = bind_dead_letter_queue!(channel, queue_name, creation_options)
|
222
222
|
publish_policy_options(policy_options)
|
223
223
|
end
|
224
|
-
exchange = exchange(exchange_name)
|
225
|
-
queue.bind(exchange, binding_keys)
|
226
224
|
queue
|
227
225
|
end
|
228
226
|
|
227
|
+
def bind_queue!(queue, exchange_name, binding_options)
|
228
|
+
queue.bind(exchange(exchange_name), binding_options)
|
229
|
+
end
|
230
|
+
|
229
231
|
def connection_settings
|
230
232
|
{
|
231
233
|
:host => current_host, :port => current_port, :logging => false,
|
data/lib/beetle/version.rb
CHANGED
@@ -7,7 +7,7 @@ class AMQPGemBehaviorTest < Minitest::Test
|
|
7
7
|
begin
|
8
8
|
exception = nil
|
9
9
|
EM.run do
|
10
|
-
AMQP.start(:
|
10
|
+
AMQP.start(logging: false, host: ENV['RABBITMQ_SERVERS'] || 'localhost') do |connection|
|
11
11
|
EM::Timer.new(1){ connection.close { EM.stop }}
|
12
12
|
channel = AMQP::Channel.new(connection)
|
13
13
|
channel.on_error { puts "woot"}
|
data/test/beetle/base_test.rb
CHANGED
data/test/beetle/client_test.rb
CHANGED
@@ -8,7 +8,7 @@ module Beetle
|
|
8
8
|
end
|
9
9
|
|
10
10
|
test "should have a default server" do
|
11
|
-
|
11
|
+
assert !@client.servers.empty?
|
12
12
|
end
|
13
13
|
|
14
14
|
test "should have no additional subscription servers" do
|
@@ -282,6 +282,12 @@ module Beetle
|
|
282
282
|
client.stop_publishing
|
283
283
|
end
|
284
284
|
|
285
|
+
test "should delegate setup_queues_and_policies to the publisher instance" do
|
286
|
+
client = Client.new
|
287
|
+
client.send(:publisher).expects(:setup_queues_and_policies)
|
288
|
+
client.setup_queues_and_policies
|
289
|
+
end
|
290
|
+
|
285
291
|
test "should delegate queue purging to the publisher instance" do
|
286
292
|
client = Client.new
|
287
293
|
client.register_queue(:queue)
|
@@ -337,17 +343,17 @@ module Beetle
|
|
337
343
|
|
338
344
|
test "trying to listen to an unknown queue should raise an exception" do
|
339
345
|
client = Client.new
|
340
|
-
assert_raises(UnknownQueue) {
|
346
|
+
assert_raises(UnknownQueue) { client.listen_queues([:foobar])}
|
341
347
|
end
|
342
348
|
|
343
349
|
test "trying to pause listening on an unknown queue should raise an exception" do
|
344
350
|
client = Client.new
|
345
|
-
assert_raises(UnknownQueue) {
|
351
|
+
assert_raises(UnknownQueue) { client.pause_listening(:foobar)}
|
346
352
|
end
|
347
353
|
|
348
354
|
test "trying to resume listening on an unknown queue should raise an exception" do
|
349
355
|
client = Client.new
|
350
|
-
assert_raises(UnknownQueue) {
|
356
|
+
assert_raises(UnknownQueue) { client.pause_listening(:foobar)}
|
351
357
|
end
|
352
358
|
|
353
359
|
test "should delegate stop_listening to the subscriber instance" do
|
@@ -451,4 +457,39 @@ module Beetle
|
|
451
457
|
msg_stub
|
452
458
|
end
|
453
459
|
end
|
460
|
+
|
461
|
+
class ServerDeduplicationTest < Minitest::Test
|
462
|
+
def setup
|
463
|
+
@config = Configuration.new
|
464
|
+
@config.servers = "localhost:5672,localhost:5672"
|
465
|
+
@config.additional_subscription_servers = @config.servers + ",localhost:1234,localhost:1234"
|
466
|
+
@client = Client.new(@config)
|
467
|
+
end
|
468
|
+
|
469
|
+
test "duplicates are removed from the server list" do
|
470
|
+
assert_equal ["localhost:5672"], @client.servers
|
471
|
+
end
|
472
|
+
|
473
|
+
test "duplicates and servers in the server list are removed from the additional subscription server list" do
|
474
|
+
assert_equal ["localhost:1234"], @client.additional_subscription_servers
|
475
|
+
end
|
476
|
+
end
|
477
|
+
|
478
|
+
class EmptyServerStringTest < Minitest::Test
|
479
|
+
def setup
|
480
|
+
@config = Configuration.new
|
481
|
+
@config.servers = "localhost:5672,\t,localhost:5672, "
|
482
|
+
@config.additional_subscription_servers = @config.servers + ",localhost:1234, , ,,"
|
483
|
+
@client = Client.new(@config)
|
484
|
+
end
|
485
|
+
|
486
|
+
test "empty strings are removed from the server list" do
|
487
|
+
assert_equal ["localhost:5672"], @client.servers
|
488
|
+
end
|
489
|
+
|
490
|
+
test "empty strings are removed from the additional subscription server list" do
|
491
|
+
assert_equal ["localhost:1234"], @client.additional_subscription_servers
|
492
|
+
end
|
493
|
+
end
|
494
|
+
|
454
495
|
end
|
@@ -87,7 +87,7 @@ module Beetle
|
|
87
87
|
private
|
88
88
|
def redis_test_master_file(server_string)
|
89
89
|
tmp_dir = File.expand_path("../../../tmp", __FILE__)
|
90
|
-
Dir.mkdir(tmp_dir) unless File.
|
90
|
+
Dir.mkdir(tmp_dir) unless File.exist?(tmp_dir)
|
91
91
|
path = tmp_dir + "/redis-master-for-unit-tests"
|
92
92
|
File.open(path, "w"){|f| f.puts server_string}
|
93
93
|
path
|
@@ -77,7 +77,9 @@ module Beetle
|
|
77
77
|
|
78
78
|
class PublisherPublishingTest < Minitest::Test
|
79
79
|
def setup
|
80
|
-
@
|
80
|
+
@config = Configuration.new
|
81
|
+
@config.servers = ENV['RABBITMQ_SERVERS'].split(',').first if ENV['RABBITMQ_SERVERS']
|
82
|
+
@client = Client.new(@config)
|
81
83
|
@pub = Publisher.new(@client)
|
82
84
|
@pub.stubs(:bind_queues_for_exchange)
|
83
85
|
@client.register_queue("mama", :exchange => "mama-exchange")
|
@@ -277,6 +279,7 @@ module Beetle
|
|
277
279
|
class PublisherQueueManagementTest < Minitest::Test
|
278
280
|
def setup
|
279
281
|
@config = Configuration.new
|
282
|
+
@config.servers = ENV['RABBITMQ_SERVERS'] if ENV['RABBITMQ_SERVERS']
|
280
283
|
@client = Client.new(@config)
|
281
284
|
@pub = Publisher.new(@client)
|
282
285
|
end
|
@@ -304,7 +307,11 @@ module Beetle
|
|
304
307
|
@client.register_queue('test_queue_1', :exchange => 'test_exchange')
|
305
308
|
@client.register_queue('test_queue_2', :exchange => 'test_exchange')
|
306
309
|
@client.register_queue('test_queue_3', :exchange => 'test_exchange_2')
|
307
|
-
|
310
|
+
queue = mock("queue")
|
311
|
+
@pub.expects(:bind_queue!).with(queue, "test_exchange", {:key => "test_queue_1"}).once
|
312
|
+
@pub.expects(:bind_queue!).with(queue, "test_exchange", {:key => "test_queue_2"}).once
|
313
|
+
@pub.expects(:bind_queue!).with(queue, "test_exchange_2", {:key => "test_queue_3"}).once
|
314
|
+
@pub.expects(:declare_queue!).returns(queue).times(3)
|
308
315
|
@pub.send(:bind_queues_for_exchange, 'test_exchange')
|
309
316
|
@pub.send(:bind_queues_for_exchange, 'test_exchange_2')
|
310
317
|
end
|
@@ -312,8 +319,22 @@ module Beetle
|
|
312
319
|
test "should not rebind the defined queues for the used exchanges if they already have been bound" do
|
313
320
|
@client.register_queue('test_queue_1', :exchange => 'test_exchange')
|
314
321
|
@client.register_queue('test_queue_2', :exchange => 'test_exchange')
|
315
|
-
|
322
|
+
queue = mock("queue")
|
323
|
+
@pub.expects(:declare_queue!).returns(queue).twice
|
324
|
+
@pub.expects(:bind_queue!).with(queue, "test_exchange", {:key => "test_queue_1"}).once
|
325
|
+
@pub.expects(:bind_queue!).with(queue, "test_exchange", {:key => "test_queue_2"}).once
|
326
|
+
@pub.send(:bind_queues_for_exchange, 'test_exchange')
|
316
327
|
@pub.send(:bind_queues_for_exchange, 'test_exchange')
|
328
|
+
end
|
329
|
+
|
330
|
+
test "should declare queues only once even with many bindings" do
|
331
|
+
|
332
|
+
@client.register_queue('test_queue', :exchange => 'test_exchange')
|
333
|
+
@client.register_binding('test_queue', :exchange => 'test_exchange', :key => 'sir-message-a-lot')
|
334
|
+
queue = mock("queue")
|
335
|
+
@pub.expects(:declare_queue!).returns(queue).once
|
336
|
+
@pub.expects(:bind_queue!).with(queue, "test_exchange", {:key => "test_queue"}).once
|
337
|
+
@pub.expects(:bind_queue!).with(queue, "test_exchange", {:key => "sir-message-a-lot"}).once
|
317
338
|
@pub.send(:bind_queues_for_exchange, 'test_exchange')
|
318
339
|
end
|
319
340
|
|
@@ -342,14 +363,34 @@ module Beetle
|
|
342
363
|
end
|
343
364
|
|
344
365
|
test "setting up queues and policies should iterate over all servers" do
|
345
|
-
|
346
|
-
|
366
|
+
client = Client.new
|
367
|
+
client.register_queue("queue")
|
368
|
+
pub = Publisher.new(client)
|
369
|
+
pub.servers = %w(a b)
|
370
|
+
|
347
371
|
s = sequence("setup")
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
372
|
+
pub.expects(:set_current_server).with("a").in_sequence(s)
|
373
|
+
pub.expects(:queue).with(client.config.beetle_policy_updates_queue_name).in_sequence(s)
|
374
|
+
pub.expects(:queue).with("queue").in_sequence(s)
|
375
|
+
pub.expects(:set_current_server).with("b").in_sequence(s)
|
376
|
+
pub.expects(:queue).with(client.config.beetle_policy_updates_queue_name).in_sequence(s)
|
377
|
+
pub.expects(:queue).with("queue").in_sequence(s)
|
378
|
+
|
379
|
+
pub.setup_queues_and_policies()
|
380
|
+
end
|
381
|
+
|
382
|
+
test "setting up queues and policies should handle ephemeral errors" do
|
383
|
+
client = Client.new
|
384
|
+
pub = Publisher.new(client)
|
385
|
+
client.register_queue("queue")
|
386
|
+
pub.servers = %w(a b)
|
387
|
+
pub.stubs(:queue).raises(StandardError)
|
388
|
+
|
389
|
+
s = sequence("setup")
|
390
|
+
pub.expects(:set_current_server).with("a").in_sequence(s)
|
391
|
+
pub.expects(:set_current_server).with("b").in_sequence(s)
|
392
|
+
|
393
|
+
pub.setup_queues_and_policies()
|
353
394
|
end
|
354
395
|
|
355
396
|
test "reports whether it has been throttled" do
|
@@ -516,10 +557,11 @@ module Beetle
|
|
516
557
|
end
|
517
558
|
end
|
518
559
|
|
519
|
-
|
520
560
|
class RPCTest < Minitest::Test
|
521
561
|
def setup
|
522
|
-
@
|
562
|
+
@config = Configuration.new
|
563
|
+
@config.servers = ENV['RABBITMQ_SERVERS'].split(',').first if ENV['RABBITMQ_SERVERS']
|
564
|
+
@client = Client.new(@config)
|
523
565
|
@pub = Publisher.new(@client)
|
524
566
|
@client.register_message(:test, :exchange => :some_exchange)
|
525
567
|
end
|
@@ -52,7 +52,9 @@ module Beetle
|
|
52
52
|
|
53
53
|
class SubscriberPauseAndResumeTest < Minitest::Test
|
54
54
|
def setup
|
55
|
-
@
|
55
|
+
@config = Configuration.new
|
56
|
+
@config.servers = "localhost:5672"
|
57
|
+
@client = Client.new(@config)
|
56
58
|
@sub = @client.send(:subscriber)
|
57
59
|
@sub.servers << "localhost:7777"
|
58
60
|
@server1, @server2 = @sub.servers
|
@@ -127,7 +129,7 @@ module Beetle
|
|
127
129
|
@sub = @client.send(:subscriber)
|
128
130
|
end
|
129
131
|
|
130
|
-
test "subscribers server list should contain
|
132
|
+
test "subscribers server list should contain additional subcription hosts" do
|
131
133
|
assert_equal ["localhost:5672", "localhost:1234"], @sub.servers
|
132
134
|
end
|
133
135
|
end
|
@@ -168,6 +170,17 @@ module Beetle
|
|
168
170
|
@sub.send(:bind_queues, %W(x y))
|
169
171
|
end
|
170
172
|
|
173
|
+
test "binding queues with many bindings should create it only once" do
|
174
|
+
@client.register_queue(:x, :exchange => 'test_exchange')
|
175
|
+
@client.register_binding(:x, :exchange => 'test_exchange', :key => 'sir-message-a-lot')
|
176
|
+
@client.register_handler(%w(x)){}
|
177
|
+
@sub.stubs(:exchange)
|
178
|
+
queue = mock("queue")
|
179
|
+
queue.expects(:bind).twice
|
180
|
+
@sub.expects(:declare_queue!).returns(queue).once
|
181
|
+
@sub.send(:bind_queues, %W(x))
|
182
|
+
end
|
183
|
+
|
171
184
|
test "subscribing to queues should subscribe on all queues" do
|
172
185
|
@client.register_queue(:x)
|
173
186
|
@client.register_queue(:y)
|
@@ -331,7 +344,9 @@ module Beetle
|
|
331
344
|
|
332
345
|
class SubscriptionTest < Minitest::Test
|
333
346
|
def setup
|
334
|
-
@
|
347
|
+
@config = Configuration.new
|
348
|
+
@config.servers = "locahost:5672"
|
349
|
+
@client = Client.new(@config)
|
335
350
|
@sub = @client.send(:subscriber)
|
336
351
|
end
|
337
352
|
|