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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '08db25367467939ff6a625b0caf2b940832b398c7988189ac2a0e91d5244a78b'
4
- data.tar.gz: d9ffc4a722b0d86db98e81e0f9080b76e2fbd01537cbb4a6839b00665e778f19
3
+ metadata.gz: bce54bf1dc2290bb4c1598f6210b1c292d09691e91df2f67e913747535c90f2d
4
+ data.tar.gz: e6f510fb5b78a7ed0483f713920222ff1959e7a3e3073aac61abed25af56b0bd
5
5
  SHA512:
6
- metadata.gz: c7f986880a871a59a74ee9e3fc63b9b384097713eedc9f106c7b799cd6b8762714d05d181665ac5aadea0675fd10f30acfbaec8fcdf921a31721c609220b95ad
7
- data.tar.gz: 3beb91290f71cf8191f9abe0a116732e0e880a3e0e57d2c774c2c417bde4fb697b7980e2d2f6af0bdfcd601b124c7c4286a796fada014771be3bb8b049130d12
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
- require 'rdoc/task'
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
- task :clean do
131
- sh "rm -f tmp/*.output tmp/*.log tmp/master-dir/* tmp/slave-dir/* tmp/*lock tmp/*pid test.log"
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
@@ -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://localhost:8500/v1/kv/apps/beetle/config/ >/dev/null"
4
- system "curl --silent --request PUT http://localhost:8500/v1/kv/shared/config/ >/dev/null"
5
- system "curl --silent --request DELETE http://localhost:8500/v1/kv/apps/beetle/state/redis_master_file_content >/dev/null"
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
- client = Beetle::Client.new.configure :auto_delete => true do |config|
147
- config.queue(:echo, :lazy => true, :dead_lettering => true)
148
- config.message(:echo)
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
- assert_match /#{TestDaemons::Redis[redis_name].ip_with_port}/, client.rpc(:echo, 'nil').second
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://localhost:8500",
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
- the_queue = nil
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
- the_queue = bind_queue!(queue_name, creation_options, exchange_name, binding_options)
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, creation_keys = {})
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: #{creation_keys.inspect}")
86
- channel.queue(dead_letter_queue_name, creation_keys)
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>bind_queue!</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.split(/ *, */)
382
- @additional_subscription_servers = config.additional_subscription_servers.split(/ *, */)
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
@@ -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(queue_names) #:nodoc:
174
+ def setup_queues_and_policies
173
175
  each_server do
174
- queue_names.each do |name|
175
- queue(name, create_policies: true)
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
- # TODO: Refactor, fetch the keys and stuff itself
251
- def bind_queue!(queue_name, creation_keys, exchange_name, binding_keys)
252
- logger.debug("Beetle: creating queue with opts: #{creation_keys.inspect}")
253
- queue = bunny.queue(queue_name, creation_keys)
254
- logger.debug("Beetle: binding queue #{queue_name} to #{exchange_name} with opts: #{binding_keys.inspect}")
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
@@ -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 bind_queue!(queue_name, creation_keys, exchange_name, binding_keys)
218
- queue = channel.queue(queue_name, creation_keys)
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, creation_keys)
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,
@@ -1,3 +1,3 @@
1
1
  module Beetle
2
- VERSION = "3.4.2"
2
+ VERSION = "3.5.3"
3
3
  end
@@ -7,7 +7,7 @@ class AMQPGemBehaviorTest < Minitest::Test
7
7
  begin
8
8
  exception = nil
9
9
  EM.run do
10
- AMQP.start(:logging => false) do |connection|
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"}
@@ -26,7 +26,7 @@ module Beetle
26
26
  end
27
27
 
28
28
  test "server should be initialized" do
29
- assert_equal @bs.servers.first, @bs.server
29
+ assert @bs.server
30
30
  end
31
31
 
32
32
  test "current_host should return the hostname of the current server" do
@@ -8,7 +8,7 @@ module Beetle
8
8
  end
9
9
 
10
10
  test "should have a default server" do
11
- assert_equal ["localhost:5672"], @client.servers
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) { Client.new.listen_queues([:foobar])}
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) { Client.new.pause_listening(:foobar)}
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) { Client.new.pause_listening(:foobar)}
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.exists?(tmp_dir)
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
- @client = Client.new
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
- @pub.expects(:bind_queue!).returns(1).times(3)
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
- @pub.expects(:bind_queue!).twice
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
- @pub.servers = %w(a b)
346
- queue = mock("queue")
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
- @pub.expects(:set_current_server).with("a").in_sequence(s)
349
- @pub.expects(:queue).with("queue", :create_policies => true).returns(queue).in_sequence(s)
350
- @pub.expects(:set_current_server).with("b").in_sequence(s)
351
- @pub.expects(:queue).with("queue", :create_policies => true).returns(queue).in_sequence(s)
352
- @pub.setup_queues_and_policies(["queue"])
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
- @client = Client.new
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
- @client = Client.new
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 addtional subcription hosts" do
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
- @client = Client.new
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