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