beetle 0.3.0.rc.3 → 0.3.0.rc.4
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.
- data/Rakefile +2 -6
- data/beetle.gemspec +5 -3
- data/examples/nonexistent_server.rb +28 -0
- data/examples/redundant.rb +1 -1
- data/examples/rpc.rb +3 -3
- data/lib/beetle/base.rb +4 -0
- data/lib/beetle/message.rb +3 -2
- data/lib/beetle/subscriber.rb +67 -44
- data/script/console~ +2 -0
- data/test/beetle/amqp_gem_behavior_test.rb +30 -0
- data/test/beetle/base_test.rb +4 -0
- data/test/beetle/subscriber_test.rb +114 -78
- data/test/colorized_test_output.rb +25 -0
- data/test/test_helper.rb +4 -6
- metadata +73 -33
data/Rakefile
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'rake'
|
2
2
|
require 'rake/testtask'
|
3
3
|
require 'rcov/rcovtask'
|
4
|
+
require 'bundler/gem_tasks'
|
5
|
+
|
4
6
|
# rake 0.9.2 hack to supress deprecation warnings caused by cucumber
|
5
7
|
include Rake::DSL if RAKEVERSION >= "0.9"
|
6
8
|
require 'cucumber/rake/task'
|
@@ -30,7 +32,6 @@ namespace :test do
|
|
30
32
|
end if RUBY_PLATFORM =~ /darwin/
|
31
33
|
end
|
32
34
|
|
33
|
-
|
34
35
|
namespace :beetle do
|
35
36
|
task :test do
|
36
37
|
Beetle::Client.new.test
|
@@ -108,8 +109,3 @@ Rake::RDocTask.new do |rdoc|
|
|
108
109
|
rdoc.rdoc_files.include('MIT-LICENSE')
|
109
110
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
110
111
|
end
|
111
|
-
|
112
|
-
desc "build the beetle gem"
|
113
|
-
task :build do
|
114
|
-
system("gem build beetle.gemspec")
|
115
|
-
end
|
data/beetle.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "beetle"
|
3
|
-
s.version = "0.3.0.rc.
|
3
|
+
s.version = "0.3.0.rc.4"
|
4
4
|
s.required_rubygems_version = ">= 1.3.7"
|
5
5
|
s.authors = ["Stefan Kaes", "Pascal Friederich", "Ali Jelveh", "Sebastian Roebke"]
|
6
6
|
s.date = Time.now.strftime('%Y-%m-%d')
|
@@ -29,10 +29,12 @@ Gem::Specification.new do |s|
|
|
29
29
|
|
30
30
|
s.specification_version = 3
|
31
31
|
s.add_runtime_dependency("uuid4r", [">= 0.1.2"])
|
32
|
-
s.add_runtime_dependency("bunny", ["
|
32
|
+
s.add_runtime_dependency("bunny", ["= 0.7.8"])
|
33
33
|
s.add_runtime_dependency("redis", ["= 2.2.0"])
|
34
34
|
s.add_runtime_dependency("hiredis", ["= 0.3.2"])
|
35
|
-
s.add_runtime_dependency("
|
35
|
+
s.add_runtime_dependency("amq-client", ["= 0.8.3"])
|
36
|
+
s.add_runtime_dependency("amq-protocol", ["= 0.8.1"])
|
37
|
+
s.add_runtime_dependency("amqp", ["= 0.8.0"])
|
36
38
|
s.add_runtime_dependency("activesupport", [">= 2.3.4"])
|
37
39
|
s.add_runtime_dependency("daemons", [">= 1.0.10"])
|
38
40
|
s.add_development_dependency("rake", [">= 0.8.7"])
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# nonexistent_server.rb
|
2
|
+
# this example shows what happens when you try connect to a nonexistent server
|
3
|
+
#
|
4
|
+
# start it with ruby nonexistent_server.rb
|
5
|
+
|
6
|
+
require "rubygems"
|
7
|
+
require File.expand_path("../lib/beetle", File.dirname(__FILE__))
|
8
|
+
|
9
|
+
# set Beetle log level to info, less noisy than debug
|
10
|
+
Beetle.config.logger.level = Logger::INFO
|
11
|
+
|
12
|
+
Beetle.config.servers = "unknown.railsexpress.de:5672"
|
13
|
+
|
14
|
+
# setup client
|
15
|
+
client = Beetle::Client.new
|
16
|
+
client.register_queue(:test)
|
17
|
+
client.register_message(:test)
|
18
|
+
|
19
|
+
# register our handler to the message, check out the message.rb for more stuff you can get from the message object
|
20
|
+
client.register_handler(:test) {|message| puts "got message: #{message.data}"}
|
21
|
+
|
22
|
+
# start listening
|
23
|
+
# this starts the event machine event loop using EM.run
|
24
|
+
# the block passed to listen will be yielded as the last step of the setup process
|
25
|
+
client.listen do
|
26
|
+
EM.add_timer(10) { client.stop_listening }
|
27
|
+
end
|
28
|
+
|
data/examples/redundant.rb
CHANGED
@@ -58,7 +58,7 @@ end
|
|
58
58
|
# this starts the event machine event loop using EM.run
|
59
59
|
# the block passed to listen will be yielded as the last step of the setup process
|
60
60
|
client.listen do
|
61
|
-
EM.add_timer(0.
|
61
|
+
EM.add_timer(0.2) { client.stop_listening }
|
62
62
|
end
|
63
63
|
|
64
64
|
puts "Received #{k} test messages"
|
data/examples/rpc.rb
CHANGED
@@ -3,7 +3,7 @@ require "rubygems"
|
|
3
3
|
require File.expand_path(File.dirname(__FILE__)+"/../lib/beetle")
|
4
4
|
|
5
5
|
# suppress debug messages
|
6
|
-
Beetle.config.logger.level = Logger::
|
6
|
+
Beetle.config.logger.level = Logger::INFO
|
7
7
|
Beetle.config.servers = "localhost:5672, localhost:5673"
|
8
8
|
# instantiate a client
|
9
9
|
|
@@ -28,12 +28,12 @@ if ARGV.include?("--server")
|
|
28
28
|
trap("INT") { puts "stopped echo server"; client.stop_listening }
|
29
29
|
end
|
30
30
|
else
|
31
|
-
n =
|
31
|
+
n = 10000
|
32
32
|
ms = Benchmark.ms do
|
33
33
|
n.times do |i|
|
34
34
|
content = "Hello #{i}"
|
35
35
|
# puts "performing RPC with message content '#{content}'"
|
36
|
-
status, result = client.rpc(:echo, content)
|
36
|
+
status, result = client.rpc(:echo, content, :persistent => false)
|
37
37
|
# puts "status #{status}"
|
38
38
|
# puts "result #{result}"
|
39
39
|
# puts
|
data/lib/beetle/base.rb
CHANGED
data/lib/beetle/message.rb
CHANGED
@@ -73,9 +73,10 @@ module Beetle
|
|
73
73
|
|
74
74
|
# extracts various values form the AMQP header properties
|
75
75
|
def decode #:nodoc:
|
76
|
-
|
76
|
+
# p header.attributes
|
77
|
+
amqp_headers = header.attributes
|
77
78
|
@uuid = amqp_headers[:message_id]
|
78
|
-
headers = amqp_headers[:headers]
|
79
|
+
headers = amqp_headers[:headers].symbolize_keys
|
79
80
|
@format_version = headers[:format_version].to_i
|
80
81
|
@flags = headers[:flags].to_i
|
81
82
|
@expires_at = headers[:expires_at].to_i
|
data/lib/beetle/subscriber.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'amqp'
|
2
|
-
require 'mq'
|
3
2
|
|
4
3
|
module Beetle
|
5
4
|
# Manages subscriptions and message processing on the receiver side of things.
|
@@ -10,9 +9,10 @@ module Beetle
|
|
10
9
|
super
|
11
10
|
@servers.concat @client.additional_subscription_servers
|
12
11
|
@handlers = {}
|
13
|
-
@
|
14
|
-
@
|
12
|
+
@connections = {}
|
13
|
+
@channels = {}
|
15
14
|
@subscriptions = {}
|
15
|
+
@listened_queues = []
|
16
16
|
end
|
17
17
|
|
18
18
|
# the client calls this method to subscribe to a list of queues.
|
@@ -24,11 +24,12 @@ module Beetle
|
|
24
24
|
#
|
25
25
|
# yields before entering the eventmachine loop (if a block was given)
|
26
26
|
def listen_queues(queues) #:nodoc:
|
27
|
+
@listened_queues = queues
|
28
|
+
@exchanges_for_queues = exchanges_for_queues(queues)
|
27
29
|
EM.run do
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
subscribe_queues(queues)
|
30
|
+
each_server do
|
31
|
+
connect_server connection_settings
|
32
|
+
end
|
32
33
|
yield if block_given?
|
33
34
|
end
|
34
35
|
end
|
@@ -47,10 +48,10 @@ module Beetle
|
|
47
48
|
|
48
49
|
# closes all AMQP connections and stops the eventmachine loop
|
49
50
|
def stop! #:nodoc:
|
50
|
-
if @
|
51
|
+
if @connections.empty?
|
51
52
|
EM.stop_event_loop
|
52
53
|
else
|
53
|
-
server, connection = @
|
54
|
+
server, connection = @connections.shift
|
54
55
|
logger.debug "Beetle: closing connection to #{server}"
|
55
56
|
connection.close { stop! }
|
56
57
|
end
|
@@ -74,30 +75,19 @@ module Beetle
|
|
74
75
|
end
|
75
76
|
|
76
77
|
def create_exchanges(exchanges)
|
77
|
-
|
78
|
-
exchanges.each { |name| exchange(name) }
|
79
|
-
end
|
78
|
+
exchanges.each { |name| exchange(name) }
|
80
79
|
end
|
81
80
|
|
82
81
|
def bind_queues(queues)
|
83
|
-
|
84
|
-
queues.each { |name| queue(name) }
|
85
|
-
end
|
82
|
+
queues.each { |name| queue(name) }
|
86
83
|
end
|
87
84
|
|
88
85
|
def subscribe_queues(queues)
|
89
|
-
|
90
|
-
queues.each { |name| subscribe(name) if @handlers.include?(name) }
|
91
|
-
end
|
86
|
+
queues.each { |name| subscribe(name) if @handlers.include?(name) }
|
92
87
|
end
|
93
88
|
|
94
|
-
|
95
|
-
|
96
|
-
# (instead of filling it). this is necesssary to ensure that one subscriber always just
|
97
|
-
# handles one single message. we cannot ensure reliability if the buffer is filled with
|
98
|
-
# messages and crashes.
|
99
|
-
def mq(server=@server)
|
100
|
-
@mqs[server] ||= MQ.new(amqp_connection).prefetch(1)
|
89
|
+
def channel(server=@server)
|
90
|
+
@channels[server]
|
101
91
|
end
|
102
92
|
|
103
93
|
def subscriptions(server=@server)
|
@@ -116,12 +106,8 @@ module Beetle
|
|
116
106
|
callback = create_subscription_callback(queue_name, amqp_queue_name, handler, opts)
|
117
107
|
keys = opts.slice(*SUBSCRIPTION_KEYS).merge(:key => "#", :ack => true)
|
118
108
|
logger.debug "Beetle: subscribing to queue #{amqp_queue_name} with key # on server #{@server}"
|
119
|
-
|
120
|
-
|
121
|
-
subscriptions[queue_name] = [keys, callback]
|
122
|
-
rescue MQ::Error
|
123
|
-
error("Beetle: binding multiple handlers for the same queue isn't possible.")
|
124
|
-
end
|
109
|
+
queues[queue_name].subscribe(keys, &callback)
|
110
|
+
subscriptions[queue_name] = [keys, callback]
|
125
111
|
end
|
126
112
|
|
127
113
|
def pause(queue_name)
|
@@ -147,13 +133,14 @@ module Beetle
|
|
147
133
|
if result.reject?
|
148
134
|
sleep 1
|
149
135
|
header.reject(:requeue => true)
|
150
|
-
elsif reply_to = header.
|
136
|
+
elsif reply_to = header.attributes[:reply_to]
|
137
|
+
# logger.info "Beetle: sending reply to queue #{reply_to}"
|
151
138
|
# require 'ruby-debug'
|
152
139
|
# Debugger.start
|
153
140
|
# debugger
|
154
141
|
status = result == Beetle::RC::OK ? "OK" : "FAILED"
|
155
|
-
exchange =
|
156
|
-
exchange.publish(m.handler_result.to_s, :headers => {:status => status})
|
142
|
+
exchange = AMQP::Exchange.new(channel(server), :direct, "")
|
143
|
+
exchange.publish(m.handler_result.to_s, :routing_key => reply_to, :persistent => false, :headers => {:status => status})
|
157
144
|
end
|
158
145
|
# logger.debug "Beetle: processed message"
|
159
146
|
rescue Exception
|
@@ -168,27 +155,63 @@ module Beetle
|
|
168
155
|
end
|
169
156
|
|
170
157
|
def create_exchange!(name, opts)
|
171
|
-
|
158
|
+
channel.__send__(opts[:type], name, opts.slice(*EXCHANGE_CREATION_KEYS))
|
172
159
|
end
|
173
160
|
|
174
161
|
def bind_queue!(queue_name, creation_keys, exchange_name, binding_keys)
|
175
|
-
queue =
|
162
|
+
queue = channel.queue(queue_name, creation_keys)
|
176
163
|
exchange = exchange(exchange_name)
|
177
164
|
queue.bind(exchange, binding_keys)
|
178
165
|
queue
|
179
166
|
end
|
180
167
|
|
181
|
-
def
|
182
|
-
|
168
|
+
def connection_settings
|
169
|
+
{
|
170
|
+
:host => current_host, :port => current_port, :logging => false,
|
171
|
+
:user => Beetle.config.user, :pass => Beetle.config.password, :vhost => Beetle.config.vhost,
|
172
|
+
:on_tcp_connection_failure => on_tcp_connection_failure
|
173
|
+
}
|
174
|
+
end
|
175
|
+
|
176
|
+
def on_tcp_connection_failure
|
177
|
+
Proc.new do |settings|
|
178
|
+
logger.warn "Beetle: connection failed: #{server_from_settings(settings)}"
|
179
|
+
EM::Timer.new(10) { connect_server(settings) }
|
180
|
+
end
|
183
181
|
end
|
184
182
|
|
185
|
-
def
|
186
|
-
#
|
187
|
-
|
188
|
-
|
189
|
-
con.instance_variable_set("@on_disconnect", proc{ con.__send__(:reconnect) })
|
190
|
-
con
|
183
|
+
def on_tcp_connection_loss(connection, settings)
|
184
|
+
# reconnect in 10 seconds, without enforcement
|
185
|
+
logger.warn "Beetle: lost connection: #{server_from_settings(settings)}. reconnecting."
|
186
|
+
connection.reconnect(false, 10)
|
191
187
|
end
|
192
188
|
|
189
|
+
def connect_server(settings)
|
190
|
+
server = server_from_settings settings
|
191
|
+
logger.info "Beetle: connecting to rabbit #{server}"
|
192
|
+
AMQP.connect(settings) do |connection|
|
193
|
+
connection.on_tcp_connection_loss(&method(:on_tcp_connection_loss))
|
194
|
+
@connections[server] = connection
|
195
|
+
open_channel_and_subscribe(connection, settings)
|
196
|
+
end
|
197
|
+
rescue EventMachine::ConnectionError => e
|
198
|
+
# something serious went wrong, for example DNS lookup failure
|
199
|
+
# in this case, the on_tcp_connection_failure callback is never called automatically
|
200
|
+
logger.error "Beetle: connection failed: #{e.class}(#{e})"
|
201
|
+
settings[:on_tcp_connection_failure].call(settings)
|
202
|
+
end
|
203
|
+
|
204
|
+
def open_channel_and_subscribe(connection, settings)
|
205
|
+
server = server_from_settings settings
|
206
|
+
AMQP::Channel.new(connection) do |channel|
|
207
|
+
channel.auto_recovery = true
|
208
|
+
channel.prefetch(1)
|
209
|
+
set_current_server server
|
210
|
+
@channels[server] = channel
|
211
|
+
create_exchanges(@exchanges_for_queues)
|
212
|
+
bind_queues(@listened_queues)
|
213
|
+
subscribe_queues(@listened_queues)
|
214
|
+
end
|
215
|
+
end
|
193
216
|
end
|
194
217
|
end
|
data/script/console~
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
2
|
+
require 'eventmachine'
|
3
|
+
require 'amqp'
|
4
|
+
|
5
|
+
class AMQPGemBehaviorTest < Test::Unit::TestCase
|
6
|
+
test "subscribing twice to the same queue raises a RuntimeError which throws us out of the event loop" do
|
7
|
+
begin
|
8
|
+
@exception = nil
|
9
|
+
EM.run do
|
10
|
+
AMQP.start do |connection|
|
11
|
+
begin
|
12
|
+
EM::Timer.new(1){ connection.close { EM.stop }}
|
13
|
+
channel = AMQP::Channel.new(connection)
|
14
|
+
channel.on_error { puts "woot"}
|
15
|
+
exchange = channel.topic("beetle_tests")
|
16
|
+
queue = AMQP::Queue.new(channel)
|
17
|
+
queue.bind(exchange, :key => "#")
|
18
|
+
queue.subscribe { }
|
19
|
+
queue.subscribe { }
|
20
|
+
rescue
|
21
|
+
# we never get here, because the subscription is deferred
|
22
|
+
# the only known way to avoid this is to use the block version of AMQP::Queue.new
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
rescue Exception => @exception
|
27
|
+
end
|
28
|
+
assert @exception
|
29
|
+
end
|
30
|
+
end
|
data/test/beetle/base_test.rb
CHANGED
@@ -48,5 +48,9 @@ module Beetle
|
|
48
48
|
@bs.send(:set_current_server, "xxx:123")
|
49
49
|
assert_equal "xxx:123", @bs.server
|
50
50
|
end
|
51
|
+
|
52
|
+
test "server_from_settings should create a valid server string from an AMQP settings hash" do
|
53
|
+
assert_equal "goofy:123", @bs.send(:server_from_settings, {:host => "goofy", :port => 123})
|
54
|
+
end
|
51
55
|
end
|
52
56
|
end
|
@@ -8,40 +8,18 @@ module Beetle
|
|
8
8
|
end
|
9
9
|
|
10
10
|
test "initially there should be no amqp connections" do
|
11
|
-
assert_equal({}, @sub.instance_variable_get("@
|
11
|
+
assert_equal({}, @sub.instance_variable_get("@connections"))
|
12
12
|
end
|
13
13
|
|
14
|
-
test "initially there should be no
|
15
|
-
assert_equal({}, @sub.instance_variable_get("@
|
14
|
+
test "initially there should be no channels" do
|
15
|
+
assert_equal({}, @sub.instance_variable_get("@channels"))
|
16
16
|
end
|
17
17
|
|
18
|
-
test "
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
assert_equal 42, connections[@sub.server]
|
24
|
-
end
|
25
|
-
|
26
|
-
test "new amqp connections should be created using current host and port" do
|
27
|
-
m = mock("dummy")
|
28
|
-
expected_amqp_options = {
|
29
|
-
:host => @sub.send(:current_host), :port => @sub.send(:current_port),
|
30
|
-
:user => "guest", :pass => "guest", :vhost => "/", :logging => false
|
31
|
-
}
|
32
|
-
AMQP.expects(:connect).with(expected_amqp_options).returns(m)
|
33
|
-
# TODO: smarter way to test? what triggers the amqp_connection private method call?
|
34
|
-
assert_equal m, @sub.send(:new_amqp_connection)
|
35
|
-
end
|
36
|
-
|
37
|
-
test "mq instances should be created for the current server if accessed" do
|
38
|
-
@sub.expects(:amqp_connection).returns(11)
|
39
|
-
mq_mock = mock('mq')
|
40
|
-
mq_mock.expects(:prefetch).with(1).returns(42)
|
41
|
-
MQ.expects(:new).with(11).returns(mq_mock)
|
42
|
-
assert_equal 42, @sub.send(:mq)
|
43
|
-
mqs = @sub.instance_variable_get("@mqs")
|
44
|
-
assert_equal 42, mqs[@sub.server]
|
18
|
+
test "channel should return the channel associated with the current server, if there is one" do
|
19
|
+
channel = mock("donald")
|
20
|
+
@sub.instance_variable_set("@channels", {"donald:1" => channel})
|
21
|
+
assert_nil @sub.send(:channel, "goofy:123")
|
22
|
+
assert_equal channel, @sub.send(:channel, "donald:1")
|
45
23
|
end
|
46
24
|
|
47
25
|
test "stop! should close all amqp connections and then stop the event loop" do
|
@@ -49,7 +27,7 @@ module Beetle
|
|
49
27
|
connection1.expects(:close).yields
|
50
28
|
connection2 = mock('con2')
|
51
29
|
connection2.expects(:close).yields
|
52
|
-
@sub.instance_variable_set "@
|
30
|
+
@sub.instance_variable_set "@connections", [["server1", connection1], ["server2",connection2]]
|
53
31
|
EM.expects(:stop_event_loop)
|
54
32
|
@sub.send(:stop!)
|
55
33
|
end
|
@@ -156,31 +134,43 @@ module Beetle
|
|
156
134
|
q.expects(:bind).with(:the_exchange, {:key => "haha.#"})
|
157
135
|
m = mock("MQ")
|
158
136
|
m.expects(:queue).with("some_queue", :durable => true, :passive => false, :auto_delete => false, :exclusive => false).returns(q)
|
159
|
-
@sub.expects(:
|
137
|
+
@sub.expects(:channel).returns(m)
|
160
138
|
|
161
139
|
@sub.send(:queue, "some_queue")
|
162
140
|
assert_equal q, @sub.send(:queues)["some_queue"]
|
163
141
|
end
|
164
142
|
|
165
|
-
test "binding queues should
|
166
|
-
s = sequence("binding")
|
143
|
+
test "binding queues should bind all queues" do
|
167
144
|
@client.register_queue(:x)
|
168
145
|
@client.register_queue(:y)
|
169
146
|
@client.register_handler(%w(x y)){}
|
170
|
-
@sub.
|
171
|
-
@sub.expects(:
|
172
|
-
@sub.expects(:queue).with("x").in_sequence(s)
|
173
|
-
@sub.expects(:queue).with("y").in_sequence(s)
|
174
|
-
@sub.expects(:set_current_server).with("b").in_sequence(s)
|
175
|
-
@sub.expects(:queue).with("x").in_sequence(s)
|
176
|
-
@sub.expects(:queue).with("y").in_sequence(s)
|
147
|
+
@sub.expects(:queue).with("x")
|
148
|
+
@sub.expects(:queue).with("y")
|
177
149
|
@sub.send(:bind_queues, %W(x y))
|
178
150
|
end
|
179
151
|
|
152
|
+
test "subscribing to queues should subscribe on all queues" do
|
153
|
+
@client.register_queue(:x)
|
154
|
+
@client.register_queue(:y)
|
155
|
+
@client.register_handler(%w(x y)){}
|
156
|
+
@sub.expects(:subscribe).with("x")
|
157
|
+
@sub.expects(:subscribe).with("y")
|
158
|
+
@sub.send(:subscribe_queues, %W(x y))
|
159
|
+
end
|
160
|
+
|
180
161
|
test "should not try to bind a queue for an exchange which has no queue" do
|
181
162
|
@client.register_message(:without_queue)
|
182
163
|
assert_equal [], @sub.send(:queues_for_exchanges, ["without_queue"])
|
183
164
|
end
|
165
|
+
|
166
|
+
test "should not subscribe on a queue for which there is no handler" do
|
167
|
+
@client.register_queue(:x)
|
168
|
+
@client.register_queue(:y)
|
169
|
+
@client.register_handler(%w(y)){}
|
170
|
+
@sub.expects(:subscribe).with("y")
|
171
|
+
@sub.send(:subscribe_queues, %W(x y))
|
172
|
+
end
|
173
|
+
|
184
174
|
end
|
185
175
|
|
186
176
|
class SubscriberExchangeManagementTest < Test::Unit::TestCase
|
@@ -197,26 +187,20 @@ module Beetle
|
|
197
187
|
@client.register_exchange("some_exchange", "type" => "topic", "durable" => true)
|
198
188
|
m = mock("AMQP")
|
199
189
|
m.expects(:topic).with("some_exchange", :durable => true).returns(42)
|
200
|
-
@sub.expects(:
|
190
|
+
@sub.expects(:channel).returns(m)
|
201
191
|
ex = @sub.send(:exchange, "some_exchange")
|
202
192
|
assert @sub.send(:exchanges).include?("some_exchange")
|
203
193
|
ex2 = @sub.send(:exchange, "some_exchange")
|
204
194
|
assert_equal ex2, ex
|
205
195
|
end
|
206
196
|
|
207
|
-
test "should create exchanges for all exchanges passed to create_exchanges
|
208
|
-
@sub.servers = %w(x y)
|
197
|
+
test "should create exchanges for all exchanges passed to create_exchanges for the current server" do
|
209
198
|
@client.register_queue(:donald, :exchange => 'duck')
|
210
199
|
@client.register_queue(:mickey)
|
211
200
|
@client.register_queue(:mouse, :exchange => 'mickey')
|
212
201
|
|
213
|
-
|
214
|
-
@sub.expects(:
|
215
|
-
@sub.expects(:create_exchange!).with("duck", anything).in_sequence(exchange_creation)
|
216
|
-
@sub.expects(:create_exchange!).with("mickey", anything).in_sequence(exchange_creation)
|
217
|
-
@sub.expects(:set_current_server).with('y', anything).in_sequence(exchange_creation)
|
218
|
-
@sub.expects(:create_exchange!).with("duck", anything).in_sequence(exchange_creation)
|
219
|
-
@sub.expects(:create_exchange!).with("mickey", anything).in_sequence(exchange_creation)
|
202
|
+
@sub.expects(:create_exchange!).with("duck", anything)
|
203
|
+
@sub.expects(:create_exchange!).with("mickey", anything)
|
220
204
|
@sub.send(:create_exchanges, %w(duck mickey))
|
221
205
|
end
|
222
206
|
end
|
@@ -240,7 +224,7 @@ module Beetle
|
|
240
224
|
assert_nothing_raised { @callback.call(header, 'foo') }
|
241
225
|
end
|
242
226
|
|
243
|
-
test "should call reject on the message header when processing the handler returns true on
|
227
|
+
test "should call reject on the message header when processing the handler returns true on reject?" do
|
244
228
|
header = header_with_params({})
|
245
229
|
result = mock("result")
|
246
230
|
result.expects(:reject?).returns(true)
|
@@ -256,10 +240,10 @@ module Beetle
|
|
256
240
|
Message.any_instance.expects(:process).returns(result)
|
257
241
|
Message.any_instance.expects(:handler_result).returns("response-data")
|
258
242
|
mq = mock("MQ")
|
259
|
-
@sub.expects(:
|
243
|
+
@sub.expects(:channel).with(@sub.server).returns(mq)
|
260
244
|
exchange = mock("exchange")
|
261
|
-
exchange.expects(:publish).with("response-data", :headers => {:status => "OK"})
|
262
|
-
|
245
|
+
exchange.expects(:publish).with("response-data", :routing_key => "tmp-queue", :headers => {:status => "OK"}, :persistent => false)
|
246
|
+
AMQP::Exchange.expects(:new).with(mq, :direct, "").returns(exchange)
|
263
247
|
@callback.call(header, 'foo')
|
264
248
|
end
|
265
249
|
|
@@ -269,10 +253,10 @@ module Beetle
|
|
269
253
|
Message.any_instance.expects(:process).returns(result)
|
270
254
|
Message.any_instance.expects(:handler_result).returns(nil)
|
271
255
|
mq = mock("MQ")
|
272
|
-
@sub.expects(:
|
256
|
+
@sub.expects(:channel).with(@sub.server).returns(mq)
|
273
257
|
exchange = mock("exchange")
|
274
|
-
exchange.expects(:publish).with("", :headers => {:status => "FAILED"})
|
275
|
-
|
258
|
+
exchange.expects(:publish).with("", :routing_key => "tmp-queue", :headers => {:status => "FAILED"}, :persistent => false)
|
259
|
+
AMQP::Exchange.expects(:new).with(mq, :direct, "").returns(exchange)
|
276
260
|
@callback.call(header, 'foo')
|
277
261
|
end
|
278
262
|
|
@@ -284,18 +268,6 @@ module Beetle
|
|
284
268
|
@sub = @client.send(:subscriber)
|
285
269
|
end
|
286
270
|
|
287
|
-
test "subscribe should create subscriptions on all queues for all servers" do
|
288
|
-
@sub.servers << "localhost:7777"
|
289
|
-
@client.register_message(:a)
|
290
|
-
@client.register_message(:b)
|
291
|
-
@client.register_queue(:a)
|
292
|
-
@client.register_queue(:b)
|
293
|
-
@client.register_handler(%W(a b)){}
|
294
|
-
@sub.expects(:subscribe).with("a").times(2)
|
295
|
-
@sub.expects(:subscribe).with("b").times(2)
|
296
|
-
@sub.send(:subscribe_queues, %W(a b))
|
297
|
-
end
|
298
|
-
|
299
271
|
test "subscribe should subscribe with a subscription callback created from the registered block and remember the subscription" do
|
300
272
|
@client.register_queue(:some_queue, :exchange => "some_exchange", :key => "some_key")
|
301
273
|
server = @sub.server
|
@@ -312,28 +284,32 @@ module Beetle
|
|
312
284
|
q = mock("QUEUE")
|
313
285
|
subscription_options = {:ack => true, :key => "#"}
|
314
286
|
q.expects(:subscribe).with(subscription_options).yields(header, "foo")
|
315
|
-
@sub.expects(:queues).returns({"some_queue" => q}).
|
287
|
+
@sub.expects(:queues).returns({"some_queue" => q}).once
|
316
288
|
@sub.send(:subscribe, "some_queue")
|
317
289
|
assert block_called
|
318
290
|
assert @sub.__send__(:has_subscription?, "some_queue")
|
319
|
-
q.expects(:subscribe).with(subscription_options).raises(MQ::Error)
|
320
|
-
assert_raises(Error) { @sub.send(:subscribe, "some_queue") }
|
291
|
+
# q.expects(:subscribe).with(subscription_options).raises(MQ::Error)
|
292
|
+
# assert_raises(Error) { @sub.send(:subscribe, "some_queue") }
|
321
293
|
end
|
322
294
|
|
323
295
|
test "subscribe should fail if no handler exists for given message" do
|
324
296
|
assert_raises(Error){ @sub.send(:subscribe, "some_queue") }
|
325
297
|
end
|
326
298
|
|
327
|
-
test "listening on queues should use eventmachine
|
299
|
+
test "listening on queues should use eventmachine, connect to each server, and yield" do
|
328
300
|
@client.register_exchange(:an_exchange)
|
329
301
|
@client.register_queue(:a_queue, :exchange => :an_exchange)
|
330
302
|
@client.register_message(:a_message, :key => "foo", :exchange => :an_exchange)
|
303
|
+
@sub.servers << "localhost:7777"
|
331
304
|
|
305
|
+
@sub.expects(:connect_server).twice
|
332
306
|
EM.expects(:run).yields
|
333
|
-
@sub.expects(:create_exchanges).with(["an_exchange"])
|
334
|
-
@sub.expects(:bind_queues).with(["a_queue"])
|
335
|
-
@sub.expects(:subscribe_queues).with(["a_queue"])
|
336
|
-
|
307
|
+
# @sub.expects(:create_exchanges).with(["an_exchange"])
|
308
|
+
# @sub.expects(:bind_queues).with(["a_queue"])
|
309
|
+
# @sub.expects(:subscribe_queues).with(["a_queue"])
|
310
|
+
yielded = false
|
311
|
+
@sub.listen_queues(["a_queue"]) { yielded = true}
|
312
|
+
assert yielded
|
337
313
|
end
|
338
314
|
end
|
339
315
|
|
@@ -357,4 +333,64 @@ module Beetle
|
|
357
333
|
|
358
334
|
end
|
359
335
|
|
336
|
+
class ConnectionTest < Test::Unit::TestCase
|
337
|
+
def setup
|
338
|
+
@client = Client.new
|
339
|
+
@sub = @client.send(:subscriber)
|
340
|
+
@sub.send(:set_current_server, "mickey:42")
|
341
|
+
@settings = @sub.send(:connection_settings)
|
342
|
+
end
|
343
|
+
|
344
|
+
test "connection settings should use current host and port and specify connection failure callback" do
|
345
|
+
assert_equal "mickey", @settings[:host]
|
346
|
+
assert_equal 42, @settings[:port]
|
347
|
+
assert @settings.has_key?(:on_tcp_connection_failure)
|
348
|
+
end
|
349
|
+
|
350
|
+
test "tcp connection failure should try to connect again after 10 seconds" do
|
351
|
+
cb = @sub.send(:on_tcp_connection_failure)
|
352
|
+
EM::Timer.expects(:new).with(10).yields
|
353
|
+
@sub.expects(:connect_server).with(@settings)
|
354
|
+
@sub.logger.expects(:warn).with("Beetle: connection failed: mickey:42")
|
355
|
+
cb.call(@settings)
|
356
|
+
end
|
357
|
+
|
358
|
+
test "tcp connection loss handler tries to reconnect" do
|
359
|
+
connection = mock("connection")
|
360
|
+
connection.expects(:reconnect).with(false, 10)
|
361
|
+
@sub.logger.expects(:warn).with("Beetle: lost connection: mickey:42. reconnecting.")
|
362
|
+
@sub.send(:on_tcp_connection_loss, connection, {:host => "mickey", :port => 42})
|
363
|
+
end
|
364
|
+
|
365
|
+
test "event machine connection error" do
|
366
|
+
connection = mock("connection")
|
367
|
+
AMQP.expects(:connect).raises(EventMachine::ConnectionError)
|
368
|
+
@settings[:on_tcp_connection_failure].expects(:call).with(@settings)
|
369
|
+
@sub.send(:connect_server, @settings)
|
370
|
+
end
|
371
|
+
|
372
|
+
test "successfull connection to broker" do
|
373
|
+
connection = mock("connection")
|
374
|
+
connection.expects(:on_tcp_connection_loss)
|
375
|
+
@sub.expects(:open_channel_and_subscribe).with(connection, @settings)
|
376
|
+
AMQP.expects(:connect).with(@settings).yields(connection)
|
377
|
+
@sub.send(:connect_server, @settings)
|
378
|
+
assert_equal connection, @sub.instance_variable_get("@connections")["mickey:42"]
|
379
|
+
end
|
380
|
+
|
381
|
+
test "channel opening, exchange creation, queue bindings and subscription" do
|
382
|
+
connection = mock("connection")
|
383
|
+
channel = mock("channel")
|
384
|
+
channel.expects(:prefetch).with(1)
|
385
|
+
channel.expects(:auto_recovery=).with(true)
|
386
|
+
AMQP::Channel.expects(:new).with(connection).yields(channel)
|
387
|
+
@sub.expects(:create_exchanges)
|
388
|
+
@sub.expects(:bind_queues)
|
389
|
+
@sub.expects(:subscribe_queues)
|
390
|
+
@sub.send(:open_channel_and_subscribe, connection, @settings)
|
391
|
+
assert_equal channel, @sub.instance_variable_get("@channels")["mickey:42"]
|
392
|
+
end
|
393
|
+
|
394
|
+
end
|
395
|
+
|
360
396
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# colorized output for Test::Unit / MiniTest
|
2
|
+
begin
|
3
|
+
if RUBY_VERSION < "1.9"
|
4
|
+
require 'redgreen'
|
5
|
+
else
|
6
|
+
module ColorizedDots
|
7
|
+
require 'ansi/code'
|
8
|
+
def run(runner)
|
9
|
+
r = super
|
10
|
+
ANSI.ansi(r, ANSI_COLOR_MAPPING[r])
|
11
|
+
end
|
12
|
+
ANSI_COLOR_MAPPING = Hash.new(:white).merge!('.' => :green, 'S' => :magenta, 'F' => :yellow, 'E' => :red )
|
13
|
+
end
|
14
|
+
class MiniTest::Unit
|
15
|
+
TestCase.send(:include, ColorizedDots)
|
16
|
+
def status(io = @@out)
|
17
|
+
format = "%d tests, %d assertions, %d failures, %d errors, %d skips"
|
18
|
+
color = (errors + failures) > 0 ? :red : :green
|
19
|
+
io.puts ANSI.ansi(format % [test_count, assertion_count, failures, errors, skips], color)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
rescue LoadError => e
|
24
|
+
# do nothing
|
25
|
+
end unless ENV['TM_FILENAME']
|
data/test/test_helper.rb
CHANGED
@@ -4,11 +4,7 @@ require 'mocha'
|
|
4
4
|
require 'active_support/testing/declarative'
|
5
5
|
|
6
6
|
require File.expand_path(File.dirname(__FILE__) + '/../lib/beetle')
|
7
|
-
|
8
|
-
begin
|
9
|
-
require 'redgreen' unless ENV['TM_FILENAME']
|
10
|
-
rescue LoadError => e
|
11
|
-
end
|
7
|
+
require File.expand_path(File.dirname(__FILE__) + '/colorized_test_output')
|
12
8
|
|
13
9
|
# we can remove this hack which is needed only for testing
|
14
10
|
begin
|
@@ -29,13 +25,15 @@ end
|
|
29
25
|
Beetle.config.logger = Logger.new(File.dirname(__FILE__) + '/../test.log')
|
30
26
|
Beetle.config.redis_server = "localhost:6379"
|
31
27
|
|
28
|
+
|
32
29
|
def header_with_params(opts = {})
|
33
30
|
beetle_headers = Beetle::Message.publishing_options(opts)
|
34
31
|
header = mock("header")
|
35
|
-
header.stubs(:
|
32
|
+
header.stubs(:attributes).returns(beetle_headers)
|
36
33
|
header
|
37
34
|
end
|
38
35
|
|
36
|
+
|
39
37
|
def redis_stub(name, opts = {})
|
40
38
|
default_port = opts['port'] || "1234"
|
41
39
|
default_host = opts['host'] || "foo"
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: beetle
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 15424045
|
5
5
|
prerelease: 6
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 3
|
9
9
|
- 0
|
10
10
|
- rc
|
11
|
-
-
|
12
|
-
version: 0.3.0.rc.
|
11
|
+
- 4
|
12
|
+
version: 0.3.0.rc.4
|
13
13
|
platform: ruby
|
14
14
|
authors:
|
15
15
|
- Stefan Kaes
|
@@ -20,7 +20,8 @@ autorequire:
|
|
20
20
|
bindir: bin
|
21
21
|
cert_chain: []
|
22
22
|
|
23
|
-
date: 2011-10-
|
23
|
+
date: 2011-10-11 00:00:00 +02:00
|
24
|
+
default_executable: beetle
|
24
25
|
dependencies:
|
25
26
|
- !ruby/object:Gem::Dependency
|
26
27
|
name: uuid4r
|
@@ -44,14 +45,14 @@ dependencies:
|
|
44
45
|
requirement: &id002 !ruby/object:Gem::Requirement
|
45
46
|
none: false
|
46
47
|
requirements:
|
47
|
-
- -
|
48
|
+
- - "="
|
48
49
|
- !ruby/object:Gem::Version
|
49
|
-
hash:
|
50
|
+
hash: 19
|
50
51
|
segments:
|
51
52
|
- 0
|
52
53
|
- 7
|
53
|
-
-
|
54
|
-
version: 0.7.
|
54
|
+
- 8
|
55
|
+
version: 0.7.8
|
55
56
|
type: :runtime
|
56
57
|
version_requirements: *id002
|
57
58
|
- !ruby/object:Gem::Dependency
|
@@ -87,25 +88,57 @@ dependencies:
|
|
87
88
|
type: :runtime
|
88
89
|
version_requirements: *id004
|
89
90
|
- !ruby/object:Gem::Dependency
|
90
|
-
name:
|
91
|
+
name: amq-client
|
91
92
|
prerelease: false
|
92
93
|
requirement: &id005 !ruby/object:Gem::Requirement
|
93
94
|
none: false
|
94
95
|
requirements:
|
95
|
-
- -
|
96
|
+
- - "="
|
96
97
|
- !ruby/object:Gem::Version
|
97
|
-
hash:
|
98
|
+
hash: 57
|
98
99
|
segments:
|
99
100
|
- 0
|
100
|
-
-
|
101
|
-
-
|
102
|
-
version: 0.
|
101
|
+
- 8
|
102
|
+
- 3
|
103
|
+
version: 0.8.3
|
103
104
|
type: :runtime
|
104
105
|
version_requirements: *id005
|
105
106
|
- !ruby/object:Gem::Dependency
|
106
|
-
name:
|
107
|
+
name: amq-protocol
|
107
108
|
prerelease: false
|
108
109
|
requirement: &id006 !ruby/object:Gem::Requirement
|
110
|
+
none: false
|
111
|
+
requirements:
|
112
|
+
- - "="
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
hash: 61
|
115
|
+
segments:
|
116
|
+
- 0
|
117
|
+
- 8
|
118
|
+
- 1
|
119
|
+
version: 0.8.1
|
120
|
+
type: :runtime
|
121
|
+
version_requirements: *id006
|
122
|
+
- !ruby/object:Gem::Dependency
|
123
|
+
name: amqp
|
124
|
+
prerelease: false
|
125
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
126
|
+
none: false
|
127
|
+
requirements:
|
128
|
+
- - "="
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
hash: 63
|
131
|
+
segments:
|
132
|
+
- 0
|
133
|
+
- 8
|
134
|
+
- 0
|
135
|
+
version: 0.8.0
|
136
|
+
type: :runtime
|
137
|
+
version_requirements: *id007
|
138
|
+
- !ruby/object:Gem::Dependency
|
139
|
+
name: activesupport
|
140
|
+
prerelease: false
|
141
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
109
142
|
none: false
|
110
143
|
requirements:
|
111
144
|
- - ">="
|
@@ -117,11 +150,11 @@ dependencies:
|
|
117
150
|
- 4
|
118
151
|
version: 2.3.4
|
119
152
|
type: :runtime
|
120
|
-
version_requirements: *
|
153
|
+
version_requirements: *id008
|
121
154
|
- !ruby/object:Gem::Dependency
|
122
155
|
name: daemons
|
123
156
|
prerelease: false
|
124
|
-
requirement: &
|
157
|
+
requirement: &id009 !ruby/object:Gem::Requirement
|
125
158
|
none: false
|
126
159
|
requirements:
|
127
160
|
- - ">="
|
@@ -133,11 +166,11 @@ dependencies:
|
|
133
166
|
- 10
|
134
167
|
version: 1.0.10
|
135
168
|
type: :runtime
|
136
|
-
version_requirements: *
|
169
|
+
version_requirements: *id009
|
137
170
|
- !ruby/object:Gem::Dependency
|
138
171
|
name: rake
|
139
172
|
prerelease: false
|
140
|
-
requirement: &
|
173
|
+
requirement: &id010 !ruby/object:Gem::Requirement
|
141
174
|
none: false
|
142
175
|
requirements:
|
143
176
|
- - ">="
|
@@ -149,11 +182,11 @@ dependencies:
|
|
149
182
|
- 7
|
150
183
|
version: 0.8.7
|
151
184
|
type: :development
|
152
|
-
version_requirements: *
|
185
|
+
version_requirements: *id010
|
153
186
|
- !ruby/object:Gem::Dependency
|
154
187
|
name: mocha
|
155
188
|
prerelease: false
|
156
|
-
requirement: &
|
189
|
+
requirement: &id011 !ruby/object:Gem::Requirement
|
157
190
|
none: false
|
158
191
|
requirements:
|
159
192
|
- - ">="
|
@@ -163,11 +196,11 @@ dependencies:
|
|
163
196
|
- 0
|
164
197
|
version: "0"
|
165
198
|
type: :development
|
166
|
-
version_requirements: *
|
199
|
+
version_requirements: *id011
|
167
200
|
- !ruby/object:Gem::Dependency
|
168
201
|
name: rcov
|
169
202
|
prerelease: false
|
170
|
-
requirement: &
|
203
|
+
requirement: &id012 !ruby/object:Gem::Requirement
|
171
204
|
none: false
|
172
205
|
requirements:
|
173
206
|
- - ">="
|
@@ -177,11 +210,11 @@ dependencies:
|
|
177
210
|
- 0
|
178
211
|
version: "0"
|
179
212
|
type: :development
|
180
|
-
version_requirements: *
|
213
|
+
version_requirements: *id012
|
181
214
|
- !ruby/object:Gem::Dependency
|
182
215
|
name: redgreen
|
183
216
|
prerelease: false
|
184
|
-
requirement: &
|
217
|
+
requirement: &id013 !ruby/object:Gem::Requirement
|
185
218
|
none: false
|
186
219
|
requirements:
|
187
220
|
- - ">="
|
@@ -191,11 +224,11 @@ dependencies:
|
|
191
224
|
- 0
|
192
225
|
version: "0"
|
193
226
|
type: :development
|
194
|
-
version_requirements: *
|
227
|
+
version_requirements: *id013
|
195
228
|
- !ruby/object:Gem::Dependency
|
196
229
|
name: wirble
|
197
230
|
prerelease: false
|
198
|
-
requirement: &
|
231
|
+
requirement: &id014 !ruby/object:Gem::Requirement
|
199
232
|
none: false
|
200
233
|
requirements:
|
201
234
|
- - ">="
|
@@ -205,11 +238,11 @@ dependencies:
|
|
205
238
|
- 0
|
206
239
|
version: "0"
|
207
240
|
type: :development
|
208
|
-
version_requirements: *
|
241
|
+
version_requirements: *id014
|
209
242
|
- !ruby/object:Gem::Dependency
|
210
243
|
name: cucumber
|
211
244
|
prerelease: false
|
212
|
-
requirement: &
|
245
|
+
requirement: &id015 !ruby/object:Gem::Requirement
|
213
246
|
none: false
|
214
247
|
requirements:
|
215
248
|
- - ">="
|
@@ -221,11 +254,11 @@ dependencies:
|
|
221
254
|
- 2
|
222
255
|
version: 0.7.2
|
223
256
|
type: :development
|
224
|
-
version_requirements: *
|
257
|
+
version_requirements: *id015
|
225
258
|
- !ruby/object:Gem::Dependency
|
226
259
|
name: daemon_controller
|
227
260
|
prerelease: false
|
228
|
-
requirement: &
|
261
|
+
requirement: &id016 !ruby/object:Gem::Requirement
|
229
262
|
none: false
|
230
263
|
requirements:
|
231
264
|
- - ">="
|
@@ -235,7 +268,7 @@ dependencies:
|
|
235
268
|
- 0
|
236
269
|
version: "0"
|
237
270
|
type: :development
|
238
|
-
version_requirements: *
|
271
|
+
version_requirements: *id016
|
239
272
|
description: A highly available, reliable messaging infrastructure
|
240
273
|
email: developers@xing.com
|
241
274
|
executables:
|
@@ -255,6 +288,7 @@ files:
|
|
255
288
|
- examples/handling_exceptions.rb
|
256
289
|
- examples/multiple_exchanges.rb
|
257
290
|
- examples/multiple_queues.rb
|
291
|
+
- examples/nonexistent_server.rb
|
258
292
|
- examples/pause_and_resume.rb
|
259
293
|
- examples/redundant.rb
|
260
294
|
- examples/rpc.rb
|
@@ -289,6 +323,7 @@ files:
|
|
289
323
|
- features/support/test_daemons/redis_configuration_client.rb
|
290
324
|
- features/support/test_daemons/redis_configuration_server.rb
|
291
325
|
- script/console
|
326
|
+
- script/console~
|
292
327
|
- script/start_rabbit
|
293
328
|
- beetle.gemspec
|
294
329
|
- Rakefile
|
@@ -297,6 +332,7 @@ files:
|
|
297
332
|
- REDIS_AUTO_FAILOVER.rdoc
|
298
333
|
- RELEASE_NOTES.rdoc
|
299
334
|
- MIT-LICENSE
|
335
|
+
- test/beetle/amqp_gem_behavior_test.rb
|
300
336
|
- test/beetle/base_test.rb
|
301
337
|
- test/beetle/client_test.rb
|
302
338
|
- test/beetle/configuration_test.rb
|
@@ -311,8 +347,10 @@ files:
|
|
311
347
|
- test/beetle/redis_master_file_test.rb
|
312
348
|
- test/beetle/subscriber_test.rb
|
313
349
|
- test/beetle_test.rb
|
350
|
+
- test/colorized_test_output.rb
|
314
351
|
- test/test_helper.rb
|
315
352
|
- bin/beetle
|
353
|
+
has_rdoc: true
|
316
354
|
homepage: http://xing.github.com/beetle/
|
317
355
|
licenses: []
|
318
356
|
|
@@ -344,11 +382,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
344
382
|
requirements: []
|
345
383
|
|
346
384
|
rubyforge_project:
|
347
|
-
rubygems_version: 1.
|
385
|
+
rubygems_version: 1.6.2
|
348
386
|
signing_key:
|
349
387
|
specification_version: 3
|
350
388
|
summary: High Availability AMQP Messaging with Redundant Queues
|
351
389
|
test_files:
|
390
|
+
- test/beetle/amqp_gem_behavior_test.rb
|
352
391
|
- test/beetle/base_test.rb
|
353
392
|
- test/beetle/client_test.rb
|
354
393
|
- test/beetle/configuration_test.rb
|
@@ -363,4 +402,5 @@ test_files:
|
|
363
402
|
- test/beetle/redis_master_file_test.rb
|
364
403
|
- test/beetle/subscriber_test.rb
|
365
404
|
- test/beetle_test.rb
|
405
|
+
- test/colorized_test_output.rb
|
366
406
|
- test/test_helper.rb
|