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