right_amqp 0.2.0
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/LICENSE +20 -0
- data/README.rdoc +216 -0
- data/Rakefile +70 -0
- data/lib/right_amqp.rb +28 -0
- data/lib/right_amqp/amqp.rb +115 -0
- data/lib/right_amqp/amqp/buffer.rb +395 -0
- data/lib/right_amqp/amqp/client.rb +282 -0
- data/lib/right_amqp/amqp/frame.rb +124 -0
- data/lib/right_amqp/amqp/protocol.rb +212 -0
- data/lib/right_amqp/amqp/server.rb +99 -0
- data/lib/right_amqp/amqp/spec.rb +832 -0
- data/lib/right_amqp/amqp/version.rb +3 -0
- data/lib/right_amqp/ext/blankslate.rb +7 -0
- data/lib/right_amqp/ext/em.rb +8 -0
- data/lib/right_amqp/ext/emfork.rb +69 -0
- data/lib/right_amqp/ha_client.rb +25 -0
- data/lib/right_amqp/ha_client/broker_client.rb +690 -0
- data/lib/right_amqp/ha_client/ha_broker_client.rb +1185 -0
- data/lib/right_amqp/mq.rb +866 -0
- data/lib/right_amqp/mq/exchange.rb +304 -0
- data/lib/right_amqp/mq/header.rb +33 -0
- data/lib/right_amqp/mq/logger.rb +89 -0
- data/lib/right_amqp/mq/queue.rb +456 -0
- data/lib/right_amqp/mq/rpc.rb +100 -0
- data/right_amqp.gemspec +57 -0
- data/spec/amqp/client_reconnect_spec.rb +105 -0
- data/spec/ha_client/broker_client_spec.rb +936 -0
- data/spec/ha_client/ha_broker_client_spec.rb +1385 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +56 -0
- metadata +141 -0
@@ -0,0 +1,1385 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2009-2012 RightScale Inc
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
|
23
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
24
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'lib', 'right_amqp'))
|
25
|
+
|
26
|
+
class PushMock; end
|
27
|
+
class RequestMock; end
|
28
|
+
|
29
|
+
describe RightAMQP::HABrokerClient do
|
30
|
+
|
31
|
+
include FlexMock::ArgumentTypes
|
32
|
+
include RightAMQP::SpecHelper
|
33
|
+
|
34
|
+
before(:each) do
|
35
|
+
setup_logger
|
36
|
+
@exceptions = RightSupport::Stats::Exceptions
|
37
|
+
@message = "message"
|
38
|
+
@packet = flexmock("packet", :class => RequestMock, :to_s => true, :version => [12, 12]).by_default
|
39
|
+
@serializer = flexmock("serializer")
|
40
|
+
@serializer.should_receive(:dump).and_return(@message).by_default
|
41
|
+
@serializer.should_receive(:load).with(@message).and_return(@packet).by_default
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "Context" do
|
45
|
+
|
46
|
+
before(:each) do
|
47
|
+
@packet1 = flexmock("packet1", :class => RequestMock, :name => "request", :type => "type1",
|
48
|
+
:from => "from1", :token => "token1", :one_way => false)
|
49
|
+
@packet2 = flexmock("packet2", :class => FlexMock, :name => "flexmock")
|
50
|
+
@brokers = ["broker"]
|
51
|
+
@options = {:option => "option"}
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should initialize context" do
|
55
|
+
context = RightAMQP::HABrokerClient::Context.new(@packet1, @options, @brokers)
|
56
|
+
context.name.should == "request"
|
57
|
+
context.type.should == "type1"
|
58
|
+
context.from.should == "from1"
|
59
|
+
context.token.should == "token1"
|
60
|
+
context.one_way.should be_false
|
61
|
+
context.options.should == @options
|
62
|
+
context.brokers.should == @brokers
|
63
|
+
context.failed.should == []
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should treat type, from, token, and one_way as optional members of packet but default one_way to true" do
|
67
|
+
context = RightAMQP::HABrokerClient::Context.new(@packet2, @options, @brokers)
|
68
|
+
context.name.should == "flexmock"
|
69
|
+
context.type.should be_nil
|
70
|
+
context.from.should be_nil
|
71
|
+
context.token.should be_nil
|
72
|
+
context.one_way.should be_true
|
73
|
+
context.options.should == @options
|
74
|
+
context.brokers.should == @brokers
|
75
|
+
context.failed.should == []
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
describe "Caching" do
|
81
|
+
|
82
|
+
require 'digest/md5'
|
83
|
+
|
84
|
+
before(:each) do
|
85
|
+
@now = Time.at(1000000)
|
86
|
+
@max_age = RightAMQP::HABrokerClient::Published::MAX_AGE
|
87
|
+
flexmock(Time).should_receive(:now).and_return(@now).by_default
|
88
|
+
@published = RightAMQP::HABrokerClient::Published.new
|
89
|
+
@message1 = JSON.dump({:data => "a message"})
|
90
|
+
@key1 = Digest::MD5.hexdigest(@message1)
|
91
|
+
@message2 = JSON.dump({:data => "another message"})
|
92
|
+
@key2 = Digest::MD5.hexdigest(@message2)
|
93
|
+
@message3 = JSON.dump({:data => "yet another message"})
|
94
|
+
@key3 = Digest::MD5.hexdigest(@message3)
|
95
|
+
@packet1 = flexmock("packet1", :class => RequestMock, :name => "request", :type => "type1",
|
96
|
+
:from => "from1", :token => "token1", :one_way => false)
|
97
|
+
@packet2 = flexmock("packet2", :class => RequestMock, :name => "request", :type => "type2",
|
98
|
+
:from => "from2", :token => "token2", :one_way => false)
|
99
|
+
@packet3 = flexmock("packet3", :class => PushMock, :name => "push", :type => "type3",
|
100
|
+
:from => "from3", :token => "token3", :one_way => true)
|
101
|
+
@brokers = ["broker"]
|
102
|
+
@options = {:option => "option"}
|
103
|
+
@context1 = RightAMQP::HABrokerClient::Context.new(@packet1, @options, @brokers)
|
104
|
+
@context2 = RightAMQP::HABrokerClient::Context.new(@packet2, @options, @brokers)
|
105
|
+
@context3 = RightAMQP::HABrokerClient::Context.new(@packet3, @options, @brokers)
|
106
|
+
end
|
107
|
+
|
108
|
+
it "should use message signature as cache hash key if it has one" do
|
109
|
+
@published.identify(@message1).should == @key1
|
110
|
+
@published.identify(@message2).should == @key2
|
111
|
+
@published.identify(@message3).should == @key3
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should store message info" do
|
115
|
+
@published.store(@message1, @context1)
|
116
|
+
@published.instance_variable_get(:@cache)[@key1].should == [@now.to_i, @context1]
|
117
|
+
@published.instance_variable_get(:@lru).should == [@key1]
|
118
|
+
end
|
119
|
+
|
120
|
+
it "should update timestamp and lru list when store to existing entry" do
|
121
|
+
@published.store(@message1, @context1)
|
122
|
+
@published.instance_variable_get(:@cache)[@key1].should == [@now.to_i, @context1]
|
123
|
+
@published.instance_variable_get(:@lru).should == [@key1]
|
124
|
+
@published.store(@message2, @context2)
|
125
|
+
@published.instance_variable_get(:@lru).should == [@key1, @key2]
|
126
|
+
flexmock(Time).should_receive(:now).and_return(Time.at(@now + @max_age - 1))
|
127
|
+
@published.store(@message1, @context1)
|
128
|
+
@published.instance_variable_get(:@cache)[@key1].should == [(@now + @max_age - 1).to_i, @context1]
|
129
|
+
@published.instance_variable_get(:@lru).should == [@key2, @key1]
|
130
|
+
end
|
131
|
+
|
132
|
+
it "should remove old cache entries when store new one" do
|
133
|
+
@published.store(@message1, @context1)
|
134
|
+
@published.store(@message2, @context2)
|
135
|
+
(@published.instance_variable_get(:@cache).keys - [@key1, @key2]).should == []
|
136
|
+
@published.instance_variable_get(:@lru).should == [@key1, @key2]
|
137
|
+
flexmock(Time).should_receive(:now).and_return(Time.at(@now + @max_age + 1))
|
138
|
+
@published.store(@message3, @context3)
|
139
|
+
@published.instance_variable_get(:@cache).keys.should == [@key3]
|
140
|
+
@published.instance_variable_get(:@lru).should == [@key3]
|
141
|
+
end
|
142
|
+
|
143
|
+
it "should fetch message info and make it the most recently used" do
|
144
|
+
@published.store(@message1, @context1)
|
145
|
+
@published.store(@message2, @context2)
|
146
|
+
@published.instance_variable_get(:@lru).should == [@key1, @key2]
|
147
|
+
@published.fetch(@message1).should == @context1
|
148
|
+
@published.instance_variable_get(:@lru).should == [@key2, @key1]
|
149
|
+
end
|
150
|
+
|
151
|
+
it "should fetch empty hash if entry not found" do
|
152
|
+
@published.fetch(@message1).should be_nil
|
153
|
+
@published.store(@message1, @context1)
|
154
|
+
@published.fetch(@message1).should_not be_nil
|
155
|
+
@published.fetch(@message2).should be_nil
|
156
|
+
end
|
157
|
+
|
158
|
+
end # Published
|
159
|
+
|
160
|
+
context "when initializing" do
|
161
|
+
|
162
|
+
before(:each) do
|
163
|
+
@identity = "rs-broker-localhost-5672"
|
164
|
+
@address = {:host => "localhost", :port => 5672, :index => 0}
|
165
|
+
@broker = flexmock("broker_client", :identity => @identity, :usable? => true)
|
166
|
+
@broker.should_receive(:return_message).by_default
|
167
|
+
@broker.should_receive(:update_status).by_default
|
168
|
+
flexmock(RightAMQP::BrokerClient).should_receive(:new).and_return(@broker).by_default
|
169
|
+
end
|
170
|
+
|
171
|
+
it "should create a broker client for default host and port" do
|
172
|
+
flexmock(RightAMQP::BrokerClient).should_receive(:new).with(@identity, @address, @serializer,
|
173
|
+
@exceptions, Hash, nil).and_return(@broker).once
|
174
|
+
ha = RightAMQP::HABrokerClient.new(@serializer)
|
175
|
+
ha.brokers.should == [@broker]
|
176
|
+
end
|
177
|
+
|
178
|
+
it "should create broker clients for specified hosts and ports and assign index in order of creation" do
|
179
|
+
address1 = {:host => "first", :port => 5672, :index => 0}
|
180
|
+
broker1 = flexmock("broker_client1", :identity => "rs-broker-first-5672", :usable? => true, :return_message => true)
|
181
|
+
flexmock(RightAMQP::BrokerClient).should_receive(:new).with("rs-broker-first-5672", address1, @serializer,
|
182
|
+
@exceptions, Hash, nil).and_return(broker1).once
|
183
|
+
address2 = {:host => "second", :port => 5672, :index => 1}
|
184
|
+
broker2 = flexmock("broker_client2", :identity => "rs-broker-second-5672", :usable? => true, :return_message => true)
|
185
|
+
flexmock(RightAMQP::BrokerClient).should_receive(:new).with("rs-broker-second-5672", address2, @serializer,
|
186
|
+
@exceptions, Hash, nil).and_return(broker2).once
|
187
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second", :port => 5672)
|
188
|
+
ha.brokers.should == [broker1, broker2]
|
189
|
+
end
|
190
|
+
|
191
|
+
it "should setup to receive returned messages from each usable broker client" do
|
192
|
+
@broker.should_receive(:return_message).twice
|
193
|
+
flexmock(RightAMQP::BrokerClient).should_receive(:new).and_return(@broker).twice
|
194
|
+
RightAMQP::HABrokerClient.new(@serializer, :host => "first, second", :port => 5672)
|
195
|
+
end
|
196
|
+
|
197
|
+
end # when initializing
|
198
|
+
|
199
|
+
context "when parsing user_data" do
|
200
|
+
|
201
|
+
it "should extra host list from RS_rn_url and RS_rn_host" do
|
202
|
+
RightAMQP::HABrokerClient.parse_user_data("RS_rn_url=rs@first/right_net&RS_rn_host=:0,second:1").should ==
|
203
|
+
["first:0,second:1", nil]
|
204
|
+
end
|
205
|
+
|
206
|
+
it "should extra port list from RS_rn_port" do
|
207
|
+
RightAMQP::HABrokerClient.parse_user_data("RS_rn_url=rs@host/right_net&RS_rn_host=:1,host:0&RS_rn_port=5673:1,5672:0").should ==
|
208
|
+
["host:1,host:0", "5673:1,5672:0"]
|
209
|
+
end
|
210
|
+
|
211
|
+
it "should raise an exception if there is no user data" do
|
212
|
+
lambda { RightAMQP::HABrokerClient.parse_user_data(nil) }.should raise_error(RightAMQP::HABrokerClient::NoUserData)
|
213
|
+
lambda { RightAMQP::HABrokerClient.parse_user_data("") }.should raise_error(RightAMQP::HABrokerClient::NoUserData)
|
214
|
+
end
|
215
|
+
|
216
|
+
it "should raise an exception if there are no broker hosts defined in the data" do
|
217
|
+
lambda { RightAMQP::HABrokerClient.parse_user_data("blah") }.should raise_error(RightAMQP::HABrokerClient::NoBrokerHosts)
|
218
|
+
end
|
219
|
+
|
220
|
+
it "should translate old host name to standard form" do
|
221
|
+
RightAMQP::HABrokerClient.parse_user_data("RS_rn_url=rs@broker.rightscale.com/right_net").should ==
|
222
|
+
["broker1-1.rightscale.com", nil]
|
223
|
+
end
|
224
|
+
|
225
|
+
end # when parsing user_data
|
226
|
+
|
227
|
+
context "when addressing" do
|
228
|
+
|
229
|
+
it "should form list of broker addresses from specified hosts and ports" do
|
230
|
+
RightAMQP::HABrokerClient.addresses("first,second", "5672, 5674").should ==
|
231
|
+
[{:host => "first", :port => 5672, :index => 0}, {:host => "second", :port => 5674, :index => 1}]
|
232
|
+
end
|
233
|
+
|
234
|
+
it "should form list of broker addresses from specified hosts and ports and use ids associated with hosts" do
|
235
|
+
RightAMQP::HABrokerClient.addresses("first:1,second:2", "5672, 5674").should ==
|
236
|
+
[{:host => "first", :port => 5672, :index => 1}, {:host => "second", :port => 5674, :index => 2}]
|
237
|
+
end
|
238
|
+
|
239
|
+
it "should form list of broker addresses from specified hosts and ports and use ids associated with ports" do
|
240
|
+
RightAMQP::HABrokerClient.addresses("host", "5672:0, 5674:2").should ==
|
241
|
+
[{:host => "host", :port => 5672, :index => 0}, {:host => "host", :port => 5674, :index => 2}]
|
242
|
+
end
|
243
|
+
|
244
|
+
it "should use default host and port for broker identity if none provided" do
|
245
|
+
RightAMQP::HABrokerClient.addresses(nil, nil).should == [{:host => "localhost", :port => 5672, :index => 0}]
|
246
|
+
end
|
247
|
+
|
248
|
+
it "should use default port when ports is an empty string" do
|
249
|
+
RightAMQP::HABrokerClient.addresses("first, second", "").should ==
|
250
|
+
[{:host => "first", :port => 5672, :index => 0}, {:host => "second", :port => 5672, :index => 1}]
|
251
|
+
end
|
252
|
+
|
253
|
+
it "should use default host when hosts is an empty string" do
|
254
|
+
RightAMQP::HABrokerClient.addresses("", "5672, 5673").should ==
|
255
|
+
[{:host => "localhost", :port => 5672, :index => 0}, {:host => "localhost", :port => 5673, :index => 1}]
|
256
|
+
end
|
257
|
+
|
258
|
+
it "should reuse host if there is only one but multiple ports" do
|
259
|
+
RightAMQP::HABrokerClient.addresses("first", "5672, 5674").should ==
|
260
|
+
[{:host => "first", :port => 5672, :index => 0}, {:host => "first", :port => 5674, :index => 1}]
|
261
|
+
end
|
262
|
+
|
263
|
+
it "should reuse port if there is only one but multiple hosts" do
|
264
|
+
RightAMQP::HABrokerClient.addresses("first, second", 5672).should ==
|
265
|
+
[{:host => "first", :port => 5672, :index => 0}, {:host => "second", :port => 5672, :index => 1}]
|
266
|
+
end
|
267
|
+
|
268
|
+
it "should apply ids associated with host" do
|
269
|
+
RightAMQP::HABrokerClient.addresses("first:0, third:2", 5672).should ==
|
270
|
+
[{:host => "first", :port => 5672, :index => 0}, {:host => "third", :port => 5672, :index => 2}]
|
271
|
+
end
|
272
|
+
|
273
|
+
it "should not allow mismatched number of hosts and ports" do
|
274
|
+
runner = lambda { RightAMQP::HABrokerClient.addresses("first, second", "5672, 5673, 5674") }
|
275
|
+
runner.should raise_exception(ArgumentError)
|
276
|
+
end
|
277
|
+
|
278
|
+
end # when addressing
|
279
|
+
|
280
|
+
context "when identifying" do
|
281
|
+
|
282
|
+
before(:each) do
|
283
|
+
@address1 = {:host => "first", :port => 5672, :index => 0}
|
284
|
+
@identity1 = "rs-broker-first-5672"
|
285
|
+
@broker1 = flexmock("broker_client1", :identity => @identity1, :usable? => true, :return_message => true,
|
286
|
+
:alias => "b0", :host => "first", :port => 5672, :index => 0)
|
287
|
+
flexmock(RightAMQP::BrokerClient).should_receive(:new).with(@identity1, @address1, @serializer,
|
288
|
+
@exceptions, Hash, nil).and_return(@broker1).by_default
|
289
|
+
|
290
|
+
@address2 = {:host => "second", :port => 5672, :index => 1}
|
291
|
+
@identity2 = "rs-broker-second-5672"
|
292
|
+
@broker2 = flexmock("broker_client2", :identity => @identity2, :usable? => true, :return_message => true,
|
293
|
+
:alias => "b1", :host => "second", :port => 5672, :index => 1)
|
294
|
+
flexmock(RightAMQP::BrokerClient).should_receive(:new).with(@identity2, @address2, @serializer,
|
295
|
+
@exceptions, Hash, nil).and_return(@broker2).by_default
|
296
|
+
|
297
|
+
@address3 = {:host => "third", :port => 5672, :index => 2}
|
298
|
+
@identity3 = "rs-broker-third-5672"
|
299
|
+
@broker3 = flexmock("broker_client3", :identity => @identity3, :usable? => true, :return_message => true,
|
300
|
+
:alias => "b2", :host => "third", :port => 5672, :index => 2)
|
301
|
+
flexmock(RightAMQP::BrokerClient).should_receive(:new).with(@identity3, @address3, @serializer,
|
302
|
+
@exceptions, Hash, nil).and_return(@broker3).by_default
|
303
|
+
end
|
304
|
+
|
305
|
+
it "should use host and port to uniquely identity broker in AgentIdentity format" do
|
306
|
+
RightAMQP::HABrokerClient.identity("localhost", 5672).should == "rs-broker-localhost-5672"
|
307
|
+
RightAMQP::HABrokerClient.identity("10.21.102.23", 1234).should == "rs-broker-10.21.102.23-1234"
|
308
|
+
end
|
309
|
+
|
310
|
+
it "should replace '-' with '~' in host names when forming broker identity" do
|
311
|
+
RightAMQP::HABrokerClient.identity("9-1-1", 5672).should == "rs-broker-9~1~1-5672"
|
312
|
+
end
|
313
|
+
|
314
|
+
it "should use default port when forming broker identity" do
|
315
|
+
RightAMQP::HABrokerClient.identity("10.21.102.23").should == "rs-broker-10.21.102.23-5672"
|
316
|
+
end
|
317
|
+
|
318
|
+
it "should list broker identities" do
|
319
|
+
RightAMQP::HABrokerClient.identities("first,second", "5672, 5674").should ==
|
320
|
+
["rs-broker-first-5672", "rs-broker-second-5674"]
|
321
|
+
end
|
322
|
+
|
323
|
+
it "should convert identities into aliases" do
|
324
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first:0, third:2", :port => 5672)
|
325
|
+
ha.aliases([@identity3]).should == ["b2"]
|
326
|
+
ha.aliases([@identity3, @identity1]).should == ["b2", "b0"]
|
327
|
+
end
|
328
|
+
|
329
|
+
it "should convert identities into nil alias when unknown" do
|
330
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first:0, third:2", :port => 5672)
|
331
|
+
ha.aliases(["rs-broker-second-5672", nil]).should == [nil, nil]
|
332
|
+
end
|
333
|
+
|
334
|
+
it "should convert identity into alias" do
|
335
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first:0, third:2", :port => 5672)
|
336
|
+
ha.alias_(@identity3).should == "b2"
|
337
|
+
end
|
338
|
+
|
339
|
+
it "should convert identity into nil alias when unknown" do
|
340
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first:0, third:2", :port => 5672)
|
341
|
+
ha.alias_("rs-broker-second-5672").should == nil
|
342
|
+
end
|
343
|
+
|
344
|
+
it "should convert identity into parts" do
|
345
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first:0, third:2", :port => 5672)
|
346
|
+
ha.identity_parts(@identity3).should == ["third", 5672, 2, 1]
|
347
|
+
end
|
348
|
+
|
349
|
+
it "should convert an alias into parts" do
|
350
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first:0, third:2", :port => 5672)
|
351
|
+
ha.identity_parts("b2").should == ["third", 5672, 2, 1]
|
352
|
+
end
|
353
|
+
|
354
|
+
it "should convert unknown identity into nil parts" do
|
355
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first:0, third:2", :port => 5672)
|
356
|
+
ha.identity_parts("rs-broker-second-5672").should == [nil, nil, nil, nil]
|
357
|
+
end
|
358
|
+
|
359
|
+
it "should get identity from identity" do
|
360
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first:0, third:2", :port => 5672)
|
361
|
+
ha.get(@identity1).should == @identity1
|
362
|
+
ha.get("rs-broker-second-5672").should be_nil
|
363
|
+
ha.get(@identity3).should == @identity3
|
364
|
+
end
|
365
|
+
|
366
|
+
it "should get identity from an alias" do
|
367
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first:0, third:2", :port => 5672)
|
368
|
+
ha.get("b0").should == @identity1
|
369
|
+
ha.get("b1").should be_nil
|
370
|
+
ha.get("b2").should == @identity3
|
371
|
+
end
|
372
|
+
|
373
|
+
it "should generate host:index list" do
|
374
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "second:1, first:0, third:2", :port => 5672)
|
375
|
+
ha.hosts.should == "second:1,first:0,third:2"
|
376
|
+
end
|
377
|
+
|
378
|
+
it "should generate port:index list" do
|
379
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "second:1, third:2, first:0", :port => 5672)
|
380
|
+
ha.ports.should == "5672:1,5672:2,5672:0"
|
381
|
+
end
|
382
|
+
|
383
|
+
end # when identifying
|
384
|
+
|
385
|
+
context "when" do
|
386
|
+
|
387
|
+
before(:each) do
|
388
|
+
# Generate mocking for three BrokerClients
|
389
|
+
# key index host alias
|
390
|
+
{ 1 => [0, "first", "b0"],
|
391
|
+
2 => [1, "second", "b1"],
|
392
|
+
3 => [2, "third", "b2"] }.each do |k, v|
|
393
|
+
i, h, a = v
|
394
|
+
eval("@identity#{k} = 'rs-broker-#{h}-5672'")
|
395
|
+
eval("@address#{k} = {:host => '#{h}', :port => 5672, :index => #{i}}")
|
396
|
+
eval("@broker#{k} = flexmock('broker_client#{k}', :identity => @identity#{k}, :alias => '#{a}', " +
|
397
|
+
":host => '#{h}', :port => 5672, :index => #{i})")
|
398
|
+
eval("@broker#{k}.should_receive(:status).and_return(:connected).by_default")
|
399
|
+
eval("@broker#{k}.should_receive(:usable?).and_return(true).by_default")
|
400
|
+
eval("@broker#{k}.should_receive(:connected?).and_return(true).by_default")
|
401
|
+
eval("@broker#{k}.should_receive(:subscribe).and_return(true).by_default")
|
402
|
+
eval("@broker#{k}.should_receive(:return_message).and_return(true).by_default")
|
403
|
+
eval("flexmock(RightAMQP::BrokerClient).should_receive(:new).with(@identity#{k}, @address#{k}, " +
|
404
|
+
"@serializer, @exceptions, Hash, nil).and_return(@broker#{k}).by_default")
|
405
|
+
end
|
406
|
+
end
|
407
|
+
|
408
|
+
context "connecting" do
|
409
|
+
|
410
|
+
it "should connect and add a new broker client to the end of the list" do
|
411
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first", :port => 5672)
|
412
|
+
ha.brokers.size.should == 1
|
413
|
+
ha.brokers[0].alias == "b0"
|
414
|
+
flexmock(RightAMQP::BrokerClient).should_receive(:new).with(@identity2, @address2, @serializer,
|
415
|
+
@exceptions, Hash, nil).and_return(@broker2).once
|
416
|
+
res = ha.connect("second", 5672, 1)
|
417
|
+
res.should be_true
|
418
|
+
ha.brokers.size.should == 2
|
419
|
+
ha.brokers[1].alias == "b1"
|
420
|
+
end
|
421
|
+
|
422
|
+
it "should reconnect an existing broker client after closing it if it is not connected" do
|
423
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second")
|
424
|
+
ha.brokers.size.should == 2
|
425
|
+
@broker1.should_receive(:usable?).and_return(false)
|
426
|
+
@broker1.should_receive(:close).and_return(true).once
|
427
|
+
flexmock(RightAMQP::BrokerClient).should_receive(:new).with(@identity1, @address1, @serializer,
|
428
|
+
@exceptions, Hash, ha.brokers[0]).and_return(@broker1).once
|
429
|
+
res = ha.connect("first", 5672, 0)
|
430
|
+
res.should be_true
|
431
|
+
ha.brokers.size.should == 2
|
432
|
+
ha.brokers[0].alias == "b0"
|
433
|
+
ha.brokers[1].alias == "b1"
|
434
|
+
end
|
435
|
+
|
436
|
+
it "should not do anything except log a message if asked to reconnect an already connected broker client" do
|
437
|
+
@logger.should_receive(:info).with(/Ignored request to reconnect/).once
|
438
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second")
|
439
|
+
ha.brokers.size.should == 2
|
440
|
+
@broker1.should_receive(:status).and_return(:connected).once
|
441
|
+
@broker1.should_receive(:close).and_return(true).never
|
442
|
+
flexmock(RightAMQP::BrokerClient).should_receive(:new).with(@identity1, @address1, @serializer,
|
443
|
+
@exceptions, Hash, ha.brokers[0]).and_return(@broker1).never
|
444
|
+
res = ha.connect("first", 5672, 0)
|
445
|
+
res.should be_false
|
446
|
+
ha.brokers.size.should == 2
|
447
|
+
ha.brokers[0].alias == "b0"
|
448
|
+
ha.brokers[1].alias == "b1"
|
449
|
+
end
|
450
|
+
|
451
|
+
it "should reconnect already connected broker client if force specified" do
|
452
|
+
@logger.should_receive(:info).with(/Ignored request to reconnect/).never
|
453
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second")
|
454
|
+
ha.brokers.size.should == 2
|
455
|
+
@broker1.should_receive(:close).and_return(true).once
|
456
|
+
flexmock(RightAMQP::BrokerClient).should_receive(:new).with(@identity1, @address1, @serializer,
|
457
|
+
@exceptions, Hash, ha.brokers[0]).and_return(@broker1).once
|
458
|
+
res = ha.connect("first", 5672, 0, nil, force = true)
|
459
|
+
res.should be_true
|
460
|
+
ha.brokers.size.should == 2
|
461
|
+
ha.brokers[0].alias == "b0"
|
462
|
+
ha.brokers[1].alias == "b1"
|
463
|
+
end
|
464
|
+
|
465
|
+
it "should be able to change host and port of an existing broker client" do
|
466
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second")
|
467
|
+
ha.brokers.size.should == 2
|
468
|
+
@broker1.should_receive(:close).and_return(true).once
|
469
|
+
flexmock(RightAMQP::BrokerClient).should_receive(:new).with(@identity3, @address3.merge(:index => 0),
|
470
|
+
@serializer, @exceptions, Hash, nil).and_return(@broker3).once
|
471
|
+
res = ha.connect("third", 5672, 0)
|
472
|
+
res.should be_true
|
473
|
+
ha.brokers.size.should == 2
|
474
|
+
ha.brokers[0].alias == "b0"
|
475
|
+
ha.brokers[0].identity == @address3
|
476
|
+
ha.brokers[1].alias == "b1"
|
477
|
+
ha.brokers[1].identity == @address_b
|
478
|
+
end
|
479
|
+
|
480
|
+
it "should slot broker client into specified priority position when at end of list" do
|
481
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second")
|
482
|
+
ha.brokers.size.should == 2
|
483
|
+
res = ha.connect("third", 5672, 2, 2)
|
484
|
+
res.should be_true
|
485
|
+
ha.brokers.size.should == 3
|
486
|
+
ha.brokers[0].alias == "b0"
|
487
|
+
ha.brokers[1].alias == "b1"
|
488
|
+
ha.brokers[2].alias == "b2"
|
489
|
+
end
|
490
|
+
|
491
|
+
it "should slot broker client into specified priority position when already is a client in that position" do
|
492
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second")
|
493
|
+
ha.brokers.size.should == 2
|
494
|
+
res = ha.connect("third", 5672, 2, 1)
|
495
|
+
res.should be_true
|
496
|
+
ha.brokers.size.should == 3
|
497
|
+
ha.brokers[0].alias == "b0"
|
498
|
+
ha.brokers[1].alias == "b2"
|
499
|
+
ha.brokers[2].alias == "b1"
|
500
|
+
end
|
501
|
+
|
502
|
+
it "should slot broker client into nex priority position if specified priority would leave a gap" do
|
503
|
+
@logger.should_receive(:info).with(/Reduced priority setting for broker/).once
|
504
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first")
|
505
|
+
ha.brokers.size.should == 1
|
506
|
+
res = ha.connect("third", 5672, 2, 2)
|
507
|
+
res.should be_true
|
508
|
+
ha.brokers.size.should == 2
|
509
|
+
ha.brokers[0].alias == "b0"
|
510
|
+
ha.brokers[1].alias == "b2"
|
511
|
+
end
|
512
|
+
|
513
|
+
it "should yield to the block provided with the newly connected broker identity" do
|
514
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first")
|
515
|
+
ha.brokers.size.should == 1
|
516
|
+
ha.brokers[0].alias == "b0"
|
517
|
+
identity = nil
|
518
|
+
res = ha.connect("second", 5672, 1) { |i| identity = i }
|
519
|
+
res.should be_true
|
520
|
+
identity.should == @identity2
|
521
|
+
ha.brokers.size.should == 2
|
522
|
+
ha.brokers[1].alias == "b1"
|
523
|
+
end
|
524
|
+
|
525
|
+
end # connecting
|
526
|
+
|
527
|
+
context "subscribing" do
|
528
|
+
|
529
|
+
it "should subscribe on all usable broker clients and return their identities" do
|
530
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
531
|
+
@broker1.should_receive(:usable?).and_return(false)
|
532
|
+
@broker1.should_receive(:subscribe).never
|
533
|
+
@broker2.should_receive(:subscribe).and_return(true).once
|
534
|
+
@broker3.should_receive(:subscribe).and_return(true).once
|
535
|
+
result = ha.subscribe({:name => "queue"}, {:type => :direct, :name => "exchange"})
|
536
|
+
result.should == [@identity2, @identity3]
|
537
|
+
end
|
538
|
+
|
539
|
+
it "should not return the identity if subscribe fails" do
|
540
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
541
|
+
@broker1.should_receive(:usable?).and_return(false)
|
542
|
+
@broker1.should_receive(:subscribe).never
|
543
|
+
@broker2.should_receive(:subscribe).and_return(true).once
|
544
|
+
@broker3.should_receive(:subscribe).and_return(false).once
|
545
|
+
result = ha.subscribe({:name => "queue"}, {:type => :direct, :name => "exchange"})
|
546
|
+
result.should == [@identity2]
|
547
|
+
end
|
548
|
+
|
549
|
+
it "should subscribe only on specified brokers" do
|
550
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
551
|
+
@broker1.should_receive(:usable?).and_return(false)
|
552
|
+
@broker1.should_receive(:subscribe).never
|
553
|
+
@broker2.should_receive(:subscribe).and_return(true).once
|
554
|
+
@broker3.should_receive(:subscribe).never
|
555
|
+
result = ha.subscribe({:name => "queue"}, {:type => :direct, :name => "exchange"},
|
556
|
+
:brokers => [@identity1, @identity2])
|
557
|
+
result.should == [@identity2]
|
558
|
+
end
|
559
|
+
|
560
|
+
end # subscribing
|
561
|
+
|
562
|
+
context "unsubscribing" do
|
563
|
+
|
564
|
+
before(:each) do
|
565
|
+
@timer = flexmock("timer", :cancel => true).by_default
|
566
|
+
flexmock(EM::Timer).should_receive(:new).and_return(@timer).by_default
|
567
|
+
@queue_name = "my_queue"
|
568
|
+
@queue = flexmock("queue", :name => @queue_name)
|
569
|
+
@queues = [@queue]
|
570
|
+
@broker1.should_receive(:queues).and_return(@queues).by_default
|
571
|
+
@broker1.should_receive(:unsubscribe).and_return(true).and_yield.by_default
|
572
|
+
@broker2.should_receive(:queues).and_return(@queues).by_default
|
573
|
+
@broker2.should_receive(:unsubscribe).and_return(true).and_yield.by_default
|
574
|
+
@broker3.should_receive(:queues).and_return(@queues).by_default
|
575
|
+
@broker3.should_receive(:unsubscribe).and_return(true).and_yield.by_default
|
576
|
+
end
|
577
|
+
|
578
|
+
it "should unsubscribe from named queues on all usable broker clients" do
|
579
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
580
|
+
@broker1.should_receive(:usable?).and_return(false)
|
581
|
+
@broker1.should_receive(:unsubscribe).never
|
582
|
+
@broker2.should_receive(:unsubscribe).and_return(true).once
|
583
|
+
@broker3.should_receive(:unsubscribe).and_return(true).once
|
584
|
+
ha.unsubscribe([@queue_name]).should be_true
|
585
|
+
end
|
586
|
+
|
587
|
+
it "should yield to supplied block after unsubscribing" do
|
588
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
589
|
+
ha.subscribe({:name => @queue_name}, {:type => :direct, :name => "exchange"})
|
590
|
+
called = 0
|
591
|
+
ha.unsubscribe([@queue_name]) { called += 1 }
|
592
|
+
called.should == 1
|
593
|
+
end
|
594
|
+
|
595
|
+
it "should yield to supplied block if timeout before finish unsubscribing" do
|
596
|
+
flexmock(EM::Timer).should_receive(:new).with(10, Proc).and_return(@timer).and_yield.once
|
597
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
598
|
+
ha.subscribe({:name => @queue_name}, {:type => :direct, :name => "exchange"})
|
599
|
+
called = 0
|
600
|
+
ha.unsubscribe([@queue_name], 10) { called += 1 }
|
601
|
+
called.should == 1
|
602
|
+
end
|
603
|
+
|
604
|
+
it "should cancel timer if finish unsubscribing before timer fires" do
|
605
|
+
@timer.should_receive(:cancel).once
|
606
|
+
flexmock(EM::Timer).should_receive(:new).with(10, Proc).and_return(@timer).once
|
607
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
608
|
+
ha.subscribe({:name => @queue_name}, {:type => :direct, :name => "exchange"})
|
609
|
+
called = 0
|
610
|
+
ha.unsubscribe([@queue_name], 10) { called += 1 }
|
611
|
+
called.should == 1
|
612
|
+
end
|
613
|
+
|
614
|
+
it "should yield to supplied block after unsubscribing even if no queues to unsubscribe" do
|
615
|
+
@broker1.should_receive(:queues).and_return([])
|
616
|
+
@broker2.should_receive(:queues).and_return([])
|
617
|
+
@broker3.should_receive(:queues).and_return([])
|
618
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
619
|
+
called = 0
|
620
|
+
ha.unsubscribe([@queue_name]) { called += 1 }
|
621
|
+
called.should == 1
|
622
|
+
end
|
623
|
+
|
624
|
+
it "should yield to supplied block once after unsubscribing all queues" do
|
625
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
626
|
+
ha.subscribe({:name => @queue_name}, {:type => :direct, :name => "exchange"})
|
627
|
+
called = 0
|
628
|
+
ha.unsubscribe([@queue_name]) { called += 1 }
|
629
|
+
called.should == 1
|
630
|
+
end
|
631
|
+
|
632
|
+
end # unsubscribing
|
633
|
+
|
634
|
+
context "declaring" do
|
635
|
+
|
636
|
+
it "should declare exchange on all usable broker clients and return their identities" do
|
637
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
638
|
+
@broker1.should_receive(:usable?).and_return(false)
|
639
|
+
@broker1.should_receive(:declare).never
|
640
|
+
@broker2.should_receive(:declare).and_return(true).once
|
641
|
+
@broker3.should_receive(:declare).and_return(true).once
|
642
|
+
result = ha.declare(:exchange, "x", :durable => true)
|
643
|
+
result.should == [@identity2, @identity3]
|
644
|
+
end
|
645
|
+
|
646
|
+
it "should not return the identity if declare fails" do
|
647
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
648
|
+
@broker1.should_receive(:usable?).and_return(false)
|
649
|
+
@broker1.should_receive(:declare).never
|
650
|
+
@broker2.should_receive(:declare).and_return(true).once
|
651
|
+
@broker3.should_receive(:declare).and_return(false).once
|
652
|
+
result = ha.declare(:exchange, "x", :durable => true)
|
653
|
+
result.should == [@identity2]
|
654
|
+
end
|
655
|
+
|
656
|
+
it "should declare exchange only on specified brokers" do
|
657
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
658
|
+
@broker1.should_receive(:usable?).and_return(false)
|
659
|
+
@broker1.should_receive(:declare).never
|
660
|
+
@broker2.should_receive(:declare).and_return(true).once
|
661
|
+
@broker3.should_receive(:declare).never
|
662
|
+
result = ha.declare(:exchange, "x", :durable => true, :brokers => [@identity1, @identity2])
|
663
|
+
result.should == [@identity2]
|
664
|
+
end
|
665
|
+
|
666
|
+
end # declaring
|
667
|
+
|
668
|
+
context "publishing" do
|
669
|
+
|
670
|
+
before(:each) do
|
671
|
+
@broker1.should_receive(:publish).and_return(true).by_default
|
672
|
+
@broker2.should_receive(:publish).and_return(true).by_default
|
673
|
+
@broker3.should_receive(:publish).and_return(true).by_default
|
674
|
+
end
|
675
|
+
|
676
|
+
it "should serialize message, publish it, and return list of broker identifiers" do
|
677
|
+
@serializer.should_receive(:dump).with(@packet).and_return(@message).once
|
678
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
679
|
+
ha.publish({:type => :direct, :name => "exchange", :options => {:durable => true}},
|
680
|
+
@packet, :persistent => true).should == [@identity1]
|
681
|
+
end
|
682
|
+
|
683
|
+
it "should try other broker clients if a publish fails" do
|
684
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
685
|
+
@broker1.should_receive(:publish).and_return(false)
|
686
|
+
ha.publish({:type => :direct, :name => "exchange"}, @packet).should == [@identity2]
|
687
|
+
end
|
688
|
+
|
689
|
+
it "should publish to a randomly selected broker if random requested" do
|
690
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
691
|
+
srand(100)
|
692
|
+
ha.publish({:type => :direct, :name => "exchange"}, @packet, :order => :random,
|
693
|
+
:brokers =>[@identity1, @identity2, @identity3]).should == [@identity2]
|
694
|
+
end
|
695
|
+
|
696
|
+
it "should publish to all connected brokers if fanout requested" do
|
697
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
698
|
+
ha.publish({:type => :direct, :name => "exchange"}, @packet, :fanout => true,
|
699
|
+
:brokers =>[@identity1, @identity2]).should == [@identity1, @identity2]
|
700
|
+
end
|
701
|
+
|
702
|
+
it "should publish only using specified brokers" do
|
703
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
704
|
+
ha.publish({:type => :direct, :name => "exchange"}, @packet,
|
705
|
+
:brokers =>[@identity1, @identity2]).should == [@identity1]
|
706
|
+
end
|
707
|
+
|
708
|
+
it "should log an error if a selected broker is unknown but still publish with any remaining brokers" do
|
709
|
+
@logger.should_receive(:error).with(/Invalid broker identity "rs-broker-fourth-5672"/).once
|
710
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
711
|
+
ha.publish({:type => :direct, :name => "exchange"}, @packet,
|
712
|
+
:brokers =>["rs-broker-fourth-5672", @identity1]).should == [@identity1]
|
713
|
+
end
|
714
|
+
|
715
|
+
it "should raise an exception if all available brokers fail to publish" do
|
716
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
717
|
+
@broker1.should_receive(:publish).and_return(false)
|
718
|
+
@broker2.should_receive(:publish).and_return(false)
|
719
|
+
@broker3.should_receive(:publish).and_return(false)
|
720
|
+
lambda { ha.publish({:type => :direct, :name => "exchange"}, @packet) }.
|
721
|
+
should raise_error(RightAMQP::HABrokerClient::NoConnectedBrokers)
|
722
|
+
end
|
723
|
+
|
724
|
+
it "should not serialize the message if it is already serialized" do
|
725
|
+
@serializer.should_receive(:dump).with(@packet).and_return(@message).never
|
726
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
727
|
+
ha.publish({:type => :direct, :name => "exchange"}, @packet, :no_serialize => true).should == [@identity1]
|
728
|
+
end
|
729
|
+
|
730
|
+
it "should store message info for use by message returns if :mandatory specified" do
|
731
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
732
|
+
ha.publish({:type => :direct, :name => "exchange"}, @packet, :mandatory => true).should == [@identity1]
|
733
|
+
ha.instance_variable_get(:@published).instance_variable_get(:@cache).size.should == 1
|
734
|
+
end
|
735
|
+
|
736
|
+
it "should not store message info for use by message returns if message already serialized" do
|
737
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
738
|
+
ha.publish({:type => :direct, :name => "exchange"}, @packet, :no_serialize => true).should == [@identity1]
|
739
|
+
ha.instance_variable_get(:@published).instance_variable_get(:@cache).size.should == 0
|
740
|
+
end
|
741
|
+
|
742
|
+
it "should not store message info for use by message returns if mandatory not specified" do
|
743
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
744
|
+
ha.publish({:type => :direct, :name => "exchange"}, @packet).should == [@identity1]
|
745
|
+
ha.instance_variable_get(:@published).instance_variable_get(:@cache).size.should == 0
|
746
|
+
end
|
747
|
+
|
748
|
+
end # publishing
|
749
|
+
|
750
|
+
context "returning" do
|
751
|
+
|
752
|
+
before(:each) do
|
753
|
+
@broker1.should_receive(:publish).and_return(true).by_default
|
754
|
+
@broker2.should_receive(:publish).and_return(true).by_default
|
755
|
+
@broker3.should_receive(:publish).and_return(true).by_default
|
756
|
+
end
|
757
|
+
|
758
|
+
it "should invoke return block" do
|
759
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
760
|
+
@broker1.should_receive(:return_message).and_yield("exchange", "NO_CONSUMERS", @message).once
|
761
|
+
called = 0
|
762
|
+
ha.return_message do |id, reason, message, to, context|
|
763
|
+
called += 1
|
764
|
+
id.should == @identity1
|
765
|
+
reason.should == "NO_CONSUMERS"
|
766
|
+
message.should == @message
|
767
|
+
to.should == "exchange"
|
768
|
+
end
|
769
|
+
called.should == 1
|
770
|
+
end
|
771
|
+
|
772
|
+
it "should record failure in message context if there is message context" do
|
773
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
774
|
+
ha.publish({:type => :direct, :name => "exchange", :options => {:durable => true}},
|
775
|
+
@packet, :mandatory => true).should == [@identity1]
|
776
|
+
@broker1.should_receive(:return_message).and_yield("exchange", "NO_CONSUMERS", @message).once
|
777
|
+
ha.return_message do |id, reason, message, to, context|
|
778
|
+
id.should == @identity1
|
779
|
+
reason.should == "NO_CONSUMERS"
|
780
|
+
message.should == @message
|
781
|
+
to.should == "exchange"
|
782
|
+
end
|
783
|
+
ha.instance_variable_get(:@published).fetch(@message).failed.should == [@identity1]
|
784
|
+
end
|
785
|
+
|
786
|
+
context "when non-delivery" do
|
787
|
+
|
788
|
+
it "should store non-delivery block for use by return handler" do
|
789
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
790
|
+
non_delivery = lambda {}
|
791
|
+
ha.non_delivery(&non_delivery)
|
792
|
+
ha.instance_variable_get(:@non_delivery).should == non_delivery
|
793
|
+
end
|
794
|
+
|
795
|
+
end
|
796
|
+
|
797
|
+
context "when handling return" do
|
798
|
+
|
799
|
+
before(:each) do
|
800
|
+
@options = {}
|
801
|
+
@brokers = [@identity1, @identity2]
|
802
|
+
@context = RightAMQP::HABrokerClient::Context.new(@packet, @options, @brokers)
|
803
|
+
end
|
804
|
+
|
805
|
+
it "should republish using a broker not yet tried if possible and log that re-routing" do
|
806
|
+
@logger.should_receive(:info).with(/RE-ROUTE/).once
|
807
|
+
@logger.should_receive(:info).with(/RETURN reason/).once
|
808
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second")
|
809
|
+
@context.record_failure(@identity1)
|
810
|
+
@broker2.should_receive(:publish).and_return(true).once
|
811
|
+
ha.__send__(:handle_return, @identity1, "reason", @message, "to", @context)
|
812
|
+
end
|
813
|
+
|
814
|
+
it "should republish to same broker without mandatory if message is persistent and no other brokers available" do
|
815
|
+
@logger.should_receive(:info).with(/RE-ROUTE/).once
|
816
|
+
@logger.should_receive(:info).with(/RETURN reason/).once
|
817
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second")
|
818
|
+
@context.record_failure(@identity1)
|
819
|
+
@context.record_failure(@identity2)
|
820
|
+
@packet.should_receive(:persistent).and_return(true)
|
821
|
+
@broker1.should_receive(:publish).and_return(true).once
|
822
|
+
ha.__send__(:handle_return, @identity2, "NO_CONSUMERS", @message, "to", @context)
|
823
|
+
end
|
824
|
+
|
825
|
+
it "should republish to same broker without mandatory if message is one-way and no other brokers available" do
|
826
|
+
@logger.should_receive(:info).with(/RE-ROUTE/).once
|
827
|
+
@logger.should_receive(:info).with(/RETURN reason/).once
|
828
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second")
|
829
|
+
@context.record_failure(@identity1)
|
830
|
+
@context.record_failure(@identity2)
|
831
|
+
@packet.should_receive(:one_way).and_return(true)
|
832
|
+
@broker1.should_receive(:publish).and_return(true).once
|
833
|
+
ha.__send__(:handle_return, @identity2, "NO_CONSUMERS", @message, "to", @context)
|
834
|
+
end
|
835
|
+
|
836
|
+
it "should update status to :stopping if message returned because access refused" do
|
837
|
+
@logger.should_receive(:info).with(/RE-ROUTE/).once
|
838
|
+
@logger.should_receive(:info).with(/RETURN reason/).once
|
839
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second")
|
840
|
+
@context.record_failure(@identity1)
|
841
|
+
@broker2.should_receive(:publish).and_return(true).once
|
842
|
+
@broker1.should_receive(:update_status).with(:stopping).and_return(true).once
|
843
|
+
ha.__send__(:handle_return, @identity1, "ACCESS_REFUSED", @message, "to", @context)
|
844
|
+
end
|
845
|
+
|
846
|
+
it "should log info and make non-delivery call even if persistent when returned because of no queue" do
|
847
|
+
@logger.should_receive(:info).with(/NO ROUTE/).once
|
848
|
+
@logger.should_receive(:info).with(/RETURN reason/).once
|
849
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second")
|
850
|
+
called = 0
|
851
|
+
ha.non_delivery { |reason, type, token, from, to| called += 1 }
|
852
|
+
@context.record_failure(@identity1)
|
853
|
+
@context.record_failure(@identity2)
|
854
|
+
@packet.should_receive(:persistent).and_return(true)
|
855
|
+
@broker1.should_receive(:publish).and_return(true).never
|
856
|
+
@broker2.should_receive(:publish).and_return(true).never
|
857
|
+
ha.__send__(:handle_return, @identity2, "NO_QUEUE", @message, "to", @context)
|
858
|
+
called.should == 1
|
859
|
+
end
|
860
|
+
|
861
|
+
it "should log info and make non-delivery call if no route can be found" do
|
862
|
+
@logger.should_receive(:info).with(/NO ROUTE/).once
|
863
|
+
@logger.should_receive(:info).with(/RETURN reason/).once
|
864
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second")
|
865
|
+
called = 0
|
866
|
+
ha.non_delivery { |reason, type, token, from, to| called += 1 }
|
867
|
+
@context.record_failure(@identity1)
|
868
|
+
@context.record_failure(@identity2)
|
869
|
+
@broker1.should_receive(:publish).and_return(true).never
|
870
|
+
@broker2.should_receive(:publish).and_return(true).never
|
871
|
+
ha.__send__(:handle_return, @identity2, "any reason", @message, "to", @context)
|
872
|
+
called.should == 1
|
873
|
+
end
|
874
|
+
|
875
|
+
it "should log info if no message context available for re-routing it" do
|
876
|
+
@logger.should_receive(:info).with(/Dropping/).once
|
877
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second")
|
878
|
+
ha.__send__(:handle_return, @identity2, "any reason", @message, "to", nil)
|
879
|
+
end
|
880
|
+
|
881
|
+
end
|
882
|
+
|
883
|
+
end # returning
|
884
|
+
|
885
|
+
context "deleting" do
|
886
|
+
|
887
|
+
it "should delete queue on all usable broker clients and return their identities" do
|
888
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
889
|
+
@broker1.should_receive(:usable?).and_return(false)
|
890
|
+
@broker1.should_receive(:delete).never
|
891
|
+
@broker2.should_receive(:delete).and_return(true).once
|
892
|
+
@broker3.should_receive(:delete).and_return(true).once
|
893
|
+
ha.delete("queue").should == [@identity2, @identity3]
|
894
|
+
end
|
895
|
+
|
896
|
+
it "should not return the identity if delete fails" do
|
897
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
898
|
+
@broker1.should_receive(:usable?).and_return(false)
|
899
|
+
@broker1.should_receive(:delete).never
|
900
|
+
@broker2.should_receive(:delete).and_return(true).once
|
901
|
+
@broker3.should_receive(:delete).and_return(false).once
|
902
|
+
ha.delete("queue").should == [@identity2]
|
903
|
+
end
|
904
|
+
|
905
|
+
it "should delete queue from cache on all usable broker clients and return their identities" do
|
906
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
907
|
+
@broker1.should_receive(:usable?).and_return(false)
|
908
|
+
@broker1.should_receive(:delete_amqp_resources).never
|
909
|
+
@broker2.should_receive(:delete_amqp_resources).and_return(true).once
|
910
|
+
@broker3.should_receive(:delete_amqp_resources).and_return(true).once
|
911
|
+
ha.delete_amqp_resources("queue").should == [@identity2, @identity3]
|
912
|
+
end
|
913
|
+
|
914
|
+
end # deleting
|
915
|
+
|
916
|
+
context "removing" do
|
917
|
+
|
918
|
+
it "should remove broker client after disconnecting and pass identity to block" do
|
919
|
+
@logger.should_receive(:info).with(/Removing/).once
|
920
|
+
@broker2.should_receive(:close).with(true, true, false).once
|
921
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
922
|
+
identity = nil
|
923
|
+
result = ha.remove("second", 5672) { |i| identity = i }
|
924
|
+
result.should == @identity2
|
925
|
+
identity.should == @identity2
|
926
|
+
ha.get(@identity1).should_not be_nil
|
927
|
+
ha.get(@identity2).should be_nil
|
928
|
+
ha.get(@identity3).should_not be_nil
|
929
|
+
ha.brokers.size.should == 2
|
930
|
+
end
|
931
|
+
|
932
|
+
it "should remove broker when no block supplied but still return a result" do
|
933
|
+
@logger.should_receive(:info).with(/Removing/).once
|
934
|
+
@broker2.should_receive(:close).once
|
935
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
936
|
+
result = ha.remove("second", 5672)
|
937
|
+
result.should == @identity2
|
938
|
+
ha.get(@identity1).should_not be_nil
|
939
|
+
ha.get(@identity2).should be_nil
|
940
|
+
ha.get(@identity3).should_not be_nil
|
941
|
+
ha.brokers.size.should == 2
|
942
|
+
end
|
943
|
+
|
944
|
+
it "should remove last broker if requested" do
|
945
|
+
@logger.should_receive(:info).with(/Removing/).times(3)
|
946
|
+
@broker1.should_receive(:close).once
|
947
|
+
@broker2.should_receive(:close).once
|
948
|
+
@broker3.should_receive(:close).once
|
949
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
950
|
+
result = ha.remove("second", 5672)
|
951
|
+
result.should == @identity2
|
952
|
+
ha.get(@identity2).should be_nil
|
953
|
+
result = ha.remove("third", 5672)
|
954
|
+
result.should == @identity3
|
955
|
+
ha.get(@identity3).should be_nil
|
956
|
+
ha.brokers.size.should == 1
|
957
|
+
identity = nil
|
958
|
+
result = ha.remove("first", 5672) { |i| identity = i }
|
959
|
+
result.should == @identity1
|
960
|
+
identity.should == @identity1
|
961
|
+
ha.get(@identity1).should be_nil
|
962
|
+
ha.brokers.size.should == 0
|
963
|
+
end
|
964
|
+
|
965
|
+
it "should return nil and not execute block if broker is unknown" do
|
966
|
+
@logger.should_receive(:info).with(/Ignored request to remove/).once
|
967
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
968
|
+
ha.remove("fourth", 5672).should be_nil
|
969
|
+
ha.brokers.size.should == 3
|
970
|
+
end
|
971
|
+
|
972
|
+
it "should close connection and mark as failed when told broker is not usable" do
|
973
|
+
@broker2.should_receive(:close).with(true, false, false).once
|
974
|
+
@broker3.should_receive(:close).with(true, false, false).once
|
975
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
976
|
+
result = ha.declare_unusable([@identity2, @identity3])
|
977
|
+
ha.brokers.size.should == 3
|
978
|
+
end
|
979
|
+
|
980
|
+
it "should raise an exception if broker that is declared not usable is unknown" do
|
981
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
982
|
+
lambda { ha.declare_unusable(["rs-broker-fourth-5672"]) }.should raise_error(Exception, /Cannot mark unknown/)
|
983
|
+
ha.brokers.size.should == 3
|
984
|
+
end
|
985
|
+
|
986
|
+
end # removing
|
987
|
+
|
988
|
+
context "monitoring" do
|
989
|
+
|
990
|
+
before(:each) do
|
991
|
+
@timer = flexmock("timer")
|
992
|
+
flexmock(EM::Timer).should_receive(:new).and_return(@timer).by_default
|
993
|
+
@timer.should_receive(:cancel).by_default
|
994
|
+
@identity = "rs-broker-localhost-5672"
|
995
|
+
@address = {:host => "localhost", :port => 5672, :index => 0}
|
996
|
+
@broker = flexmock("broker_client", :identity => @identity, :alias => "b0", :host => "localhost",
|
997
|
+
:port => 5672, :index => 0)
|
998
|
+
@broker.should_receive(:status).and_return(:connected).by_default
|
999
|
+
@broker.should_receive(:usable?).and_return(true).by_default
|
1000
|
+
@broker.should_receive(:connected?).and_return(true).by_default
|
1001
|
+
@broker.should_receive(:subscribe).and_return(true).by_default
|
1002
|
+
@broker.should_receive(:return_message).and_return(true).by_default
|
1003
|
+
flexmock(RightAMQP::BrokerClient).should_receive(:new).and_return(@broker).by_default
|
1004
|
+
@broker1.should_receive(:failed?).and_return(false).by_default
|
1005
|
+
@broker2.should_receive(:failed?).and_return(false).by_default
|
1006
|
+
@broker3.should_receive(:failed?).and_return(false).by_default
|
1007
|
+
end
|
1008
|
+
|
1009
|
+
it "should give access to or list usable brokers" do
|
1010
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
1011
|
+
aliases = []
|
1012
|
+
res = ha.__send__(:each_usable) { |b| aliases << b.alias }
|
1013
|
+
aliases.should == ["b0", "b1", "b2"]
|
1014
|
+
res.size.should == 3
|
1015
|
+
res[0].alias.should == "b0"
|
1016
|
+
res[1].alias.should == "b1"
|
1017
|
+
res[2].alias.should == "b2"
|
1018
|
+
|
1019
|
+
@broker1.should_receive(:usable?).and_return(true)
|
1020
|
+
@broker2.should_receive(:usable?).and_return(false)
|
1021
|
+
@broker3.should_receive(:usable?).and_return(false)
|
1022
|
+
aliases = []
|
1023
|
+
res = ha.__send__(:each_usable) { |b| aliases << b.alias }
|
1024
|
+
aliases.should == ["b0"]
|
1025
|
+
res.size.should == 1
|
1026
|
+
res[0].alias.should == "b0"
|
1027
|
+
end
|
1028
|
+
|
1029
|
+
it "should give list of unusable brokers" do
|
1030
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
1031
|
+
@broker1.should_receive(:usable?).and_return(true)
|
1032
|
+
@broker2.should_receive(:usable?).and_return(false)
|
1033
|
+
@broker3.should_receive(:usable?).and_return(false)
|
1034
|
+
ha.unusable.should == [@identity2, @identity3]
|
1035
|
+
end
|
1036
|
+
|
1037
|
+
it "should give access to each selected usable broker" do
|
1038
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
1039
|
+
@broker2.should_receive(:usable?).and_return(true)
|
1040
|
+
@broker3.should_receive(:usable?).and_return(false)
|
1041
|
+
aliases = []
|
1042
|
+
res = ha.__send__(:each_usable, [@identity2, @identity3]) { |b| aliases << b.alias }
|
1043
|
+
aliases.should == ["b1"]
|
1044
|
+
res.size.should == 1
|
1045
|
+
res[0].alias.should == "b1"
|
1046
|
+
end
|
1047
|
+
|
1048
|
+
it "should tell whether a broker is connected" do
|
1049
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
1050
|
+
@broker2.should_receive(:connected?).and_return(false)
|
1051
|
+
@broker3.should_receive(:connected?).and_return(true)
|
1052
|
+
ha.connected?(@identity2).should be_false
|
1053
|
+
ha.connected?(@identity3).should be_true
|
1054
|
+
ha.connected?("rs-broker-fourth-5672").should be_nil
|
1055
|
+
end
|
1056
|
+
|
1057
|
+
it "should give list of all brokers" do
|
1058
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
1059
|
+
ha.all.should == [@identity1, @identity2, @identity3]
|
1060
|
+
end
|
1061
|
+
|
1062
|
+
it "should give list of failed brokers" do
|
1063
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
1064
|
+
@broker1.should_receive(:failed?).and_return(true)
|
1065
|
+
@broker2.should_receive(:failed?).and_return(false)
|
1066
|
+
@broker3.should_receive(:failed?).and_return(true)
|
1067
|
+
ha.failed.should == [@identity1, @identity3]
|
1068
|
+
end
|
1069
|
+
|
1070
|
+
it "should give broker client status list" do
|
1071
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
1072
|
+
@broker1.should_receive(:summary).and_return("summary1")
|
1073
|
+
@broker2.should_receive(:summary).and_return("summary2")
|
1074
|
+
@broker3.should_receive(:summary).and_return("summary3")
|
1075
|
+
ha.status.should == ["summary1", "summary2", "summary3"]
|
1076
|
+
end
|
1077
|
+
|
1078
|
+
it "should give broker client statistics" do
|
1079
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
1080
|
+
@broker1.should_receive(:stats).and_return("stats1")
|
1081
|
+
@broker2.should_receive(:stats).and_return("stats2")
|
1082
|
+
@broker3.should_receive(:stats).and_return("stats3")
|
1083
|
+
ha.stats.should == {"brokers" => ["stats1", "stats2", "stats3"],
|
1084
|
+
"exceptions" => nil,
|
1085
|
+
"heartbeat" => nil,
|
1086
|
+
"returns" => nil}
|
1087
|
+
end
|
1088
|
+
|
1089
|
+
it "should log broker client status update if there is a change" do
|
1090
|
+
@logger.should_receive(:info).with(/Broker b0 is now connected/).once
|
1091
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
1092
|
+
ha.__send__(:update_status, @broker1, false)
|
1093
|
+
end
|
1094
|
+
|
1095
|
+
it "should not log broker client status update if there is no change" do
|
1096
|
+
@logger.should_receive(:info).with(/Broker b0 is now connected/).never
|
1097
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
1098
|
+
ha.__send__(:update_status, @broker1, true)
|
1099
|
+
end
|
1100
|
+
|
1101
|
+
it "should log broker client status update when become disconnected" do
|
1102
|
+
@logger.should_receive(:info).with(/Broker b0 is now disconnected/).once
|
1103
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
1104
|
+
@broker1.should_receive(:status).and_return(:disconnected)
|
1105
|
+
@broker1.should_receive(:connected?).and_return(false)
|
1106
|
+
ha.__send__(:update_status, @broker1, true)
|
1107
|
+
end
|
1108
|
+
|
1109
|
+
it "should provide connection status callback when cross 0/1 connection boundary" do
|
1110
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second")
|
1111
|
+
connected = 0
|
1112
|
+
disconnected = 0
|
1113
|
+
ha.connection_status do |status|
|
1114
|
+
if status == :connected
|
1115
|
+
(ha.brokers[0].status == :connected ||
|
1116
|
+
ha.brokers[1].status == :connected).should be_true
|
1117
|
+
connected += 1
|
1118
|
+
elsif status == :disconnected
|
1119
|
+
(ha.brokers[0].status == :disconnected &&
|
1120
|
+
ha.brokers[1].status == :disconnected).should be_true
|
1121
|
+
disconnected += 1
|
1122
|
+
end
|
1123
|
+
end
|
1124
|
+
ha.__send__(:update_status, @broker1, false)
|
1125
|
+
connected.should == 0
|
1126
|
+
disconnected.should == 0
|
1127
|
+
@broker1.should_receive(:status).and_return(:disconnected)
|
1128
|
+
@broker1.should_receive(:connected?).and_return(false)
|
1129
|
+
ha.__send__(:update_status, @broker1, true)
|
1130
|
+
connected.should == 0
|
1131
|
+
disconnected.should == 0
|
1132
|
+
@broker2.should_receive(:status).and_return(:disconnected)
|
1133
|
+
@broker2.should_receive(:connected?).and_return(false)
|
1134
|
+
ha.__send__(:update_status, @broker2, true)
|
1135
|
+
connected.should == 0
|
1136
|
+
disconnected.should == 1
|
1137
|
+
# TODO fix this test so that also checks crossing boundary as become connected
|
1138
|
+
end
|
1139
|
+
|
1140
|
+
it "should provide connection status callback when cross n/n-1 connection boundary when all specified" do
|
1141
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second")
|
1142
|
+
connected = 0
|
1143
|
+
disconnected = 0
|
1144
|
+
ha.connection_status(:boundary => :all) do |status|
|
1145
|
+
if status == :connected
|
1146
|
+
(ha.brokers[0].status == :connected &&
|
1147
|
+
ha.brokers[1].status == :connected).should be_true
|
1148
|
+
connected += 1
|
1149
|
+
elsif status == :disconnected
|
1150
|
+
(ha.brokers[0].status == :disconnected ||
|
1151
|
+
ha.brokers[1].status == :disconnected).should be_true
|
1152
|
+
disconnected += 1
|
1153
|
+
end
|
1154
|
+
end
|
1155
|
+
ha.__send__(:update_status, @broker1, false)
|
1156
|
+
connected.should == 1
|
1157
|
+
disconnected.should == 0
|
1158
|
+
@broker1.should_receive(:status).and_return(:disconnected)
|
1159
|
+
@broker1.should_receive(:connected?).and_return(false)
|
1160
|
+
ha.__send__(:update_status, @broker1, true)
|
1161
|
+
connected.should == 1
|
1162
|
+
disconnected.should == 1
|
1163
|
+
@broker2.should_receive(:status).and_return(:disconnected)
|
1164
|
+
@broker2.should_receive(:connected?).and_return(false)
|
1165
|
+
ha.__send__(:update_status, @broker2, true)
|
1166
|
+
connected.should == 1
|
1167
|
+
disconnected.should == 1
|
1168
|
+
# TODO fix this test so that also checks crossing boundary as become disconnected
|
1169
|
+
end
|
1170
|
+
|
1171
|
+
it "should provide connection status callback for specific broker set" do
|
1172
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
1173
|
+
connected = 0
|
1174
|
+
disconnected = 0
|
1175
|
+
ha.connection_status(:brokers => [@identity2, @identity3]) do |status|
|
1176
|
+
if status == :connected
|
1177
|
+
(ha.brokers[1].status == :connected ||
|
1178
|
+
ha.brokers[2].status == :connected).should be_true
|
1179
|
+
connected += 1
|
1180
|
+
elsif status == :disconnected
|
1181
|
+
(ha.brokers[1].status == :disconnected &&
|
1182
|
+
ha.brokers[2].status == :disconnected).should be_true
|
1183
|
+
disconnected += 1
|
1184
|
+
end
|
1185
|
+
end
|
1186
|
+
ha.__send__(:update_status, @broker1, false)
|
1187
|
+
connected.should == 0
|
1188
|
+
disconnected.should == 0
|
1189
|
+
@broker1.should_receive(:status).and_return(:disconnected)
|
1190
|
+
@broker1.should_receive(:connected?).and_return(false)
|
1191
|
+
ha.__send__(:update_status, @broker1, true)
|
1192
|
+
connected.should == 0
|
1193
|
+
disconnected.should == 0
|
1194
|
+
@broker2.should_receive(:status).and_return(:disconnected)
|
1195
|
+
@broker2.should_receive(:connected?).and_return(false)
|
1196
|
+
ha.__send__(:update_status, @broker2, true)
|
1197
|
+
connected.should == 0
|
1198
|
+
disconnected.should == 0
|
1199
|
+
@broker3.should_receive(:status).and_return(:disconnected)
|
1200
|
+
@broker3.should_receive(:connected?).and_return(false)
|
1201
|
+
ha.__send__(:update_status, @broker3, true)
|
1202
|
+
connected.should == 0
|
1203
|
+
disconnected.should == 1
|
1204
|
+
end
|
1205
|
+
|
1206
|
+
it "should provide connection status callback only once when one-off is requested" do
|
1207
|
+
flexmock(RightAMQP::BrokerClient).should_receive(:new).with(@identity, @address, @serializer,
|
1208
|
+
@exceptions, Hash, nil).and_return(@broker).once
|
1209
|
+
ha = RightAMQP::HABrokerClient.new(@serializer)
|
1210
|
+
called = 0
|
1211
|
+
ha.connection_status(:one_off => 10) { |_| called += 1 }
|
1212
|
+
ha.__send__(:update_status, @broker, false)
|
1213
|
+
called.should == 1
|
1214
|
+
@broker.should_receive(:status).and_return(:disconnected)
|
1215
|
+
@broker.should_receive(:connected?).and_return(false)
|
1216
|
+
ha.__send__(:update_status, @broker, true)
|
1217
|
+
called.should == 1
|
1218
|
+
end
|
1219
|
+
|
1220
|
+
it "should use connection status timer when one-off is requested" do
|
1221
|
+
flexmock(EM::Timer).should_receive(:new).and_return(@timer).once
|
1222
|
+
@timer.should_receive(:cancel).once
|
1223
|
+
flexmock(RightAMQP::BrokerClient).should_receive(:new).with(@identity, @address, @serializer,
|
1224
|
+
@exceptions, Hash, nil).and_return(@broker).once
|
1225
|
+
ha = RightAMQP::HABrokerClient.new(@serializer)
|
1226
|
+
called = 0
|
1227
|
+
ha.connection_status(:one_off => 10) { |_| called += 1 }
|
1228
|
+
ha.__send__(:update_status, @broker, false)
|
1229
|
+
called.should == 1
|
1230
|
+
end
|
1231
|
+
|
1232
|
+
it "should give timeout connection status if one-off request times out" do
|
1233
|
+
flexmock(EM::Timer).should_receive(:new).and_return(@timer).and_yield.once
|
1234
|
+
@timer.should_receive(:cancel).never
|
1235
|
+
flexmock(RightAMQP::BrokerClient).should_receive(:new).with(@identity, @address, @serializer,
|
1236
|
+
@exceptions, Hash, nil).and_return(@broker).once
|
1237
|
+
ha = RightAMQP::HABrokerClient.new(@serializer)
|
1238
|
+
called = 0
|
1239
|
+
ha.connection_status(:one_off => 10) { |status| called += 1; status.should == :timeout }
|
1240
|
+
called.should == 1
|
1241
|
+
end
|
1242
|
+
|
1243
|
+
it "should be able to have multiple connection status callbacks" do
|
1244
|
+
flexmock(RightAMQP::BrokerClient).should_receive(:new).with(@identity, @address, @serializer,
|
1245
|
+
@exceptions, Hash, nil).and_return(@broker).once
|
1246
|
+
ha = RightAMQP::HABrokerClient.new(@serializer)
|
1247
|
+
called1 = 0
|
1248
|
+
called2 = 0
|
1249
|
+
ha.connection_status(:one_off => 10) { |_| called1 += 1 }
|
1250
|
+
ha.connection_status(:boundary => :all) { |_| called2 += 1 }
|
1251
|
+
ha.__send__(:update_status, @broker, false)
|
1252
|
+
@broker.should_receive(:status).and_return(:disconnected)
|
1253
|
+
@broker.should_receive(:connected?).and_return(false)
|
1254
|
+
ha.__send__(:update_status, @broker, true)
|
1255
|
+
called1.should == 1
|
1256
|
+
called2.should == 2
|
1257
|
+
end
|
1258
|
+
|
1259
|
+
it "should provide failed connection status callback when all brokers fail to connect" do
|
1260
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
1261
|
+
connected = disconnected = failed = 0
|
1262
|
+
ha.connection_status(:boundary => :all) do |status|
|
1263
|
+
if status == :connected
|
1264
|
+
connected += 1
|
1265
|
+
elsif status == :disconnected
|
1266
|
+
disconnected += 1
|
1267
|
+
elsif status == :failed
|
1268
|
+
(ha.brokers[0].failed? &&
|
1269
|
+
ha.brokers[1].failed? &&
|
1270
|
+
ha.brokers[2].failed?).should be_true
|
1271
|
+
failed += 1
|
1272
|
+
end
|
1273
|
+
end
|
1274
|
+
@broker1.should_receive(:failed?).and_return(true)
|
1275
|
+
@broker1.should_receive(:connected?).and_return(false)
|
1276
|
+
ha.__send__(:update_status, @broker1, false)
|
1277
|
+
connected.should == 0
|
1278
|
+
disconnected.should == 0
|
1279
|
+
failed.should == 0
|
1280
|
+
@broker2.should_receive(:failed?).and_return(true)
|
1281
|
+
@broker2.should_receive(:connected?).and_return(false)
|
1282
|
+
ha.__send__(:update_status, @broker2, false)
|
1283
|
+
connected.should == 0
|
1284
|
+
disconnected.should == 0
|
1285
|
+
failed.should == 0
|
1286
|
+
@broker3.should_receive(:failed?).and_return(true)
|
1287
|
+
@broker3.should_receive(:connected?).and_return(false)
|
1288
|
+
ha.__send__(:update_status, @broker3, false)
|
1289
|
+
connected.should == 0
|
1290
|
+
disconnected.should == 0
|
1291
|
+
failed.should == 1
|
1292
|
+
end
|
1293
|
+
|
1294
|
+
it "should provide failed connection status callback when brokers selected and all brokers fail to connect" do
|
1295
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
1296
|
+
connected = disconnected = failed = 0
|
1297
|
+
ha.connection_status(:boundary => :all, :brokers => [@broker2.identity, @broker3.identity]) do |status|
|
1298
|
+
if status == :connected
|
1299
|
+
connected += 1
|
1300
|
+
elsif status == :disconnected
|
1301
|
+
disconnected += 1
|
1302
|
+
elsif status == :failed
|
1303
|
+
(ha.brokers[0].failed? &&
|
1304
|
+
ha.brokers[1].failed?).should be_true
|
1305
|
+
failed += 1
|
1306
|
+
end
|
1307
|
+
end
|
1308
|
+
@broker1.should_receive(:failed?).and_return(true)
|
1309
|
+
@broker2.should_receive(:failed?).and_return(true)
|
1310
|
+
@broker2.should_receive(:connected?).and_return(false)
|
1311
|
+
ha.__send__(:update_status, @broker2, false)
|
1312
|
+
connected.should == 0
|
1313
|
+
disconnected.should == 0
|
1314
|
+
failed.should == 0
|
1315
|
+
@broker3.should_receive(:failed?).and_return(true)
|
1316
|
+
@broker3.should_receive(:connected?).and_return(false)
|
1317
|
+
ha.__send__(:update_status, @broker3, false)
|
1318
|
+
connected.should == 0
|
1319
|
+
disconnected.should == 0
|
1320
|
+
failed.should == 1
|
1321
|
+
end
|
1322
|
+
|
1323
|
+
end # monitoring
|
1324
|
+
|
1325
|
+
context "closing" do
|
1326
|
+
|
1327
|
+
it "should close all broker connections and execute block after all connections are closed" do
|
1328
|
+
@broker1.should_receive(:close).with(false, Proc).and_return(true).and_yield.once
|
1329
|
+
@broker2.should_receive(:close).with(false, Proc).and_return(true).and_yield.once
|
1330
|
+
@broker3.should_receive(:close).with(false, Proc).and_return(true).and_yield.once
|
1331
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
1332
|
+
called = 0
|
1333
|
+
ha.close { called += 1 }
|
1334
|
+
called.should == 1
|
1335
|
+
end
|
1336
|
+
|
1337
|
+
it "should close broker connections when no block supplied" do
|
1338
|
+
@broker1.should_receive(:close).with(false, Proc).and_return(true).and_yield.once
|
1339
|
+
@broker2.should_receive(:close).with(false, Proc).and_return(true).and_yield.once
|
1340
|
+
@broker3.should_receive(:close).with(false, Proc).and_return(true).and_yield.once
|
1341
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
1342
|
+
ha.close
|
1343
|
+
end
|
1344
|
+
|
1345
|
+
it "should close all broker connections even if encounter an exception" do
|
1346
|
+
@logger.should_receive(:error).with(/Failed to close/).once
|
1347
|
+
@broker1.should_receive(:close).and_return(true).and_yield.once
|
1348
|
+
@broker2.should_receive(:close).and_raise(Exception).once
|
1349
|
+
@broker3.should_receive(:close).and_return(true).and_yield.once
|
1350
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
1351
|
+
called = 0
|
1352
|
+
ha.close { called += 1 }
|
1353
|
+
called.should == 1
|
1354
|
+
end
|
1355
|
+
|
1356
|
+
it "should close an individual broker connection" do
|
1357
|
+
@broker1.should_receive(:close).with(true).and_return(true).once
|
1358
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
1359
|
+
ha.close_one(@identity1)
|
1360
|
+
end
|
1361
|
+
|
1362
|
+
it "should not propagate connection status change if requested not to" do
|
1363
|
+
@broker1.should_receive(:close).with(false).and_return(true).once
|
1364
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
1365
|
+
ha.close_one(@identity1, propagate = false)
|
1366
|
+
end
|
1367
|
+
|
1368
|
+
it "should close an individual broker connection and execute block if given" do
|
1369
|
+
@broker1.should_receive(:close).with(true, Proc).and_return(true).and_yield.once
|
1370
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
1371
|
+
called = 0
|
1372
|
+
ha.close_one(@identity1) { called += 1 }
|
1373
|
+
called.should == 1
|
1374
|
+
end
|
1375
|
+
|
1376
|
+
it "should raise exception if unknown broker" do
|
1377
|
+
ha = RightAMQP::HABrokerClient.new(@serializer, :host => "first, second, third")
|
1378
|
+
lambda { ha.close_one("rs-broker-fourth-5672") }.should raise_error(Exception, /Cannot close unknown broker/)
|
1379
|
+
end
|
1380
|
+
|
1381
|
+
end # closing
|
1382
|
+
|
1383
|
+
end # when
|
1384
|
+
|
1385
|
+
end # RightAMQP::HABrokerClient
|