right_agent 0.13.5 → 0.14.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/lib/right_agent/actors/agent_manager.rb +1 -32
- data/lib/right_agent/agent.rb +243 -230
- data/lib/right_agent/dispatched_cache.rb +4 -5
- data/lib/right_agent/dispatcher.rb +146 -157
- data/lib/right_agent/pid_file.rb +1 -1
- data/lib/right_agent/platform.rb +14 -14
- data/lib/right_agent/scripts/agent_controller.rb +2 -4
- data/lib/right_agent/sender.rb +214 -223
- data/lib/right_agent/serialize/secure_serializer.rb +2 -2
- data/right_agent.gemspec +3 -3
- data/spec/agent_spec.rb +50 -171
- data/spec/dispatched_cache_spec.rb +13 -19
- data/spec/dispatcher_spec.rb +192 -254
- data/spec/sender_spec.rb +212 -168
- metadata +7 -4
data/spec/sender_spec.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#
|
2
|
-
# Copyright (c) 2009-
|
2
|
+
# Copyright (c) 2009-2012 RightScale Inc
|
3
3
|
#
|
4
4
|
# Permission is hereby granted, free of charge, to any person obtaining
|
5
5
|
# a copy of this software and associated documentation files (the
|
@@ -58,7 +58,6 @@ describe RightScale::Sender do
|
|
58
58
|
|
59
59
|
describe "when monitoring broker connectivity" do
|
60
60
|
before(:each) do
|
61
|
-
flexmock(EM).should_receive(:next_tick).and_yield.by_default
|
62
61
|
@now = Time.at(1000000)
|
63
62
|
flexmock(Time).should_receive(:now).and_return(@now).by_default
|
64
63
|
@broker = flexmock("Broker", :subscribe => true, :publish => ["broker"], :connected? => true,
|
@@ -193,7 +192,135 @@ describe RightScale::Sender do
|
|
193
192
|
end
|
194
193
|
end
|
195
194
|
end
|
196
|
-
|
195
|
+
|
196
|
+
describe "when validating a target" do
|
197
|
+
before(:each) do
|
198
|
+
@timer = flexmock("timer")
|
199
|
+
flexmock(EM::Timer).should_receive(:new).and_return(@timer)
|
200
|
+
flexmock(Time).should_receive(:now).and_return(Time.at(1000000)).by_default
|
201
|
+
@broker = flexmock("Broker", :subscribe => true, :publish => true).by_default
|
202
|
+
@agent = flexmock("Agent", :identity => "agent", :broker => @broker).by_default
|
203
|
+
@agent.should_receive(:options).and_return({}).by_default
|
204
|
+
RightScale::Sender.new(@agent)
|
205
|
+
@instance = RightScale::Sender.instance
|
206
|
+
@instance.initialize_offline_queue
|
207
|
+
end
|
208
|
+
|
209
|
+
it "should accept nil target" do
|
210
|
+
@instance.__send__(:validate_target, nil, true).should be_true
|
211
|
+
end
|
212
|
+
|
213
|
+
it "should accept named target" do
|
214
|
+
@instance.__send__(:validate_target, "name", true).should be_true
|
215
|
+
end
|
216
|
+
|
217
|
+
describe "and target is a hash" do
|
218
|
+
|
219
|
+
describe "and selector is allowed" do
|
220
|
+
|
221
|
+
it "should accept :all or :any selector" do
|
222
|
+
@instance.__send__(:validate_target, {:selector => :all}, true).should be_true
|
223
|
+
@instance.__send__(:validate_target, {"selector" => "any"}, true).should be_true
|
224
|
+
end
|
225
|
+
|
226
|
+
it "should reject values other than :all or :any" do
|
227
|
+
lambda { @instance.__send__(:validate_target, {:selector => :other}, true) }.
|
228
|
+
should raise_error(ArgumentError, /Invalid target selector/)
|
229
|
+
end
|
230
|
+
|
231
|
+
end
|
232
|
+
|
233
|
+
describe "and selector is not allowed" do
|
234
|
+
|
235
|
+
it "should reject selector" do
|
236
|
+
lambda { @instance.__send__(:validate_target, {:selector => :all}, false) }.
|
237
|
+
should raise_error(ArgumentError, /Invalid target hash/)
|
238
|
+
end
|
239
|
+
|
240
|
+
end
|
241
|
+
|
242
|
+
describe "and tags is specified" do
|
243
|
+
|
244
|
+
it "should accept tags" do
|
245
|
+
@instance.__send__(:validate_target, {:tags => []}, true).should be_true
|
246
|
+
@instance.__send__(:validate_target, {"tags" => ["tag"]}, true).should be_true
|
247
|
+
end
|
248
|
+
|
249
|
+
it "should reject non-array" do
|
250
|
+
lambda { @instance.__send__(:validate_target, {:tags => {}}, true) }.
|
251
|
+
should raise_error(ArgumentError, /Invalid target tags/)
|
252
|
+
end
|
253
|
+
|
254
|
+
end
|
255
|
+
|
256
|
+
describe "and scope is specified" do
|
257
|
+
|
258
|
+
it "should accept account" do
|
259
|
+
@instance.__send__(:validate_target, {:scope => {:account => 1}}, true).should be_true
|
260
|
+
@instance.__send__(:validate_target, {"scope" => {"account" => 1}}, true).should be_true
|
261
|
+
end
|
262
|
+
|
263
|
+
it "should accept shard" do
|
264
|
+
@instance.__send__(:validate_target, {:scope => {:shard => 1}}, true).should be_true
|
265
|
+
@instance.__send__(:validate_target, {"scope" => {"shard" => 1}}, true).should be_true
|
266
|
+
end
|
267
|
+
|
268
|
+
it "should accept account and shard" do
|
269
|
+
@instance.__send__(:validate_target, {"scope" => {:shard => 1, "account" => 1}}, true).should be_true
|
270
|
+
end
|
271
|
+
|
272
|
+
it "should reject keys other than account and shard" do
|
273
|
+
target = {"scope" => {:shard => 1, "account" => 1, :other => 2}}
|
274
|
+
lambda { @instance.__send__(:validate_target, target, true) }.
|
275
|
+
should raise_error(ArgumentError, /Invalid target scope/)
|
276
|
+
end
|
277
|
+
|
278
|
+
it "should reject empty hash" do
|
279
|
+
lambda { @instance.__send__(:validate_target, {:scope => {}}, true) }.
|
280
|
+
should raise_error(ArgumentError, /Invalid target scope/)
|
281
|
+
end
|
282
|
+
|
283
|
+
end
|
284
|
+
|
285
|
+
describe "and multiple are specified" do
|
286
|
+
|
287
|
+
it "should accept scope and tags" do
|
288
|
+
@instance.__send__(:validate_target, {:scope => {:shard => 1}, :tags => []}, true).should be_true
|
289
|
+
end
|
290
|
+
|
291
|
+
it "should accept scope, tags, and selector" do
|
292
|
+
target = {:scope => {:shard => 1}, :tags => ["tag"], :selector => :all}
|
293
|
+
@instance.__send__(:validate_target, target, true).should be_true
|
294
|
+
end
|
295
|
+
|
296
|
+
it "should reject selector if not allowed" do
|
297
|
+
target = {:scope => {:shard => 1}, :tags => ["tag"], :selector => :all}
|
298
|
+
lambda { @instance.__send__(:validate_target, target, false) }.
|
299
|
+
should raise_error(ArgumentError, /Invalid target hash/)
|
300
|
+
end
|
301
|
+
|
302
|
+
end
|
303
|
+
|
304
|
+
it "should reject keys other than selector, scope, and tags" do
|
305
|
+
target = {:scope => {:shard => 1}, :tags => [], :selector => :all, :other => 2}
|
306
|
+
lambda { @instance.__send__(:validate_target, target, true) }.
|
307
|
+
should raise_error(ArgumentError, /Invalid target hash/)
|
308
|
+
end
|
309
|
+
|
310
|
+
it "should reject empty hash" do
|
311
|
+
lambda { @instance.__send__(:validate_target, {}, true) }.
|
312
|
+
should raise_error(ArgumentError, /Invalid target hash/)
|
313
|
+
end
|
314
|
+
|
315
|
+
it "should reject value that is not nil, string, or hash" do
|
316
|
+
lambda { @instance.__send__(:validate_target, [], true) }.
|
317
|
+
should raise_error(ArgumentError, /Invalid target/)
|
318
|
+
end
|
319
|
+
|
320
|
+
end
|
321
|
+
|
322
|
+
end
|
323
|
+
|
197
324
|
describe "when making a push request" do
|
198
325
|
before(:each) do
|
199
326
|
@timer = flexmock("timer")
|
@@ -209,22 +336,8 @@ describe RightScale::Sender do
|
|
209
336
|
|
210
337
|
it "should validate target" do
|
211
338
|
@broker.should_receive(:publish)
|
212
|
-
|
213
|
-
|
214
|
-
lambda { @instance.send_push('/foo/bar', nil, {}) }.should be_true
|
215
|
-
lambda { @instance.send_push('/foo/bar', nil, :tags => "tags") }.should be_true
|
216
|
-
lambda { @instance.send_push('/foo/bar', nil, "tags" => "tags") }.should be_true
|
217
|
-
lambda { @instance.send_push('/foo/bar', nil, :tags => "tags", :scope => {:shard => 1}) }.should be_true
|
218
|
-
lambda { @instance.send_push('/foo/bar', nil, "scope" => {:shard => 1, "account" => 1}) }.should be_true
|
219
|
-
lambda { @instance.send_push('/foo/bar', nil, :scope => {}) }.should be_true
|
220
|
-
lambda { @instance.send_push('/foo/bar', nil, :selector => :all) }.should be_true
|
221
|
-
lambda { @instance.send_push('/foo/bar', nil, "selector" => "any") }.should be_true
|
222
|
-
lambda { @instance.send_push('/foo/bar', nil, 1) }.should raise_error(ArgumentError)
|
223
|
-
lambda { @instance.send_push('/foo/bar', nil, []) }.should raise_error(ArgumentError)
|
224
|
-
lambda { @instance.send_push('/foo/bar', nil, :bogus => 1) }.should raise_error(ArgumentError)
|
225
|
-
lambda { @instance.send_push('/foo/bar', nil, :scope => 1) }.should raise_error(ArgumentError)
|
226
|
-
lambda { @instance.send_push('/foo/bar', nil, :scope => {:bogus => 1}) }.should raise_error(ArgumentError)
|
227
|
-
lambda { @instance.send_push('/foo/bar', nil, :selector => :bogus) }.should raise_error(ArgumentError)
|
339
|
+
flexmock(@instance).should_receive(:validate_target).with("target", true).once
|
340
|
+
@instance.send_push('/foo/bar', nil, "target").should be_true
|
228
341
|
end
|
229
342
|
|
230
343
|
it "should create a Push object" do
|
@@ -283,6 +396,15 @@ describe RightScale::Sender do
|
|
283
396
|
@instance.offline_handler.queue.size.should == 1
|
284
397
|
end
|
285
398
|
|
399
|
+
it 'should raise exception if not connected to any brokers and :offline_queueing disabled' do
|
400
|
+
@log.should_receive(:error).with(/Failed to publish request/, RightAMQP::HABrokerClient::NoConnectedBrokers).once
|
401
|
+
@broker.should_receive(:publish).and_raise(RightAMQP::HABrokerClient::NoConnectedBrokers)
|
402
|
+
@agent.should_receive(:options).and_return({:offline_queueing => false})
|
403
|
+
RightScale::Sender.new(@agent)
|
404
|
+
@instance = RightScale::Sender.instance
|
405
|
+
lambda { @instance.send_push('/welcome/aboard', 'iZac') }.should raise_error(RightScale::Sender::TemporarilyOffline)
|
406
|
+
end
|
407
|
+
|
286
408
|
it "should store the response handler if given" do
|
287
409
|
response_handler = lambda {}
|
288
410
|
flexmock(RightScale::AgentIdentity).should_receive(:generate).and_return('abc').once
|
@@ -313,6 +435,12 @@ describe RightScale::Sender do
|
|
313
435
|
@instance.pending_requests['xyz'].should_not be_nil
|
314
436
|
@instance.pending_requests['abc'].should be_nil
|
315
437
|
end
|
438
|
+
|
439
|
+
it "should log exceptions and re-raise them" do
|
440
|
+
@log.should_receive(:error).with(/Failed to publish request/, Exception, :trace).once
|
441
|
+
@broker.should_receive(:publish).and_raise(Exception)
|
442
|
+
lambda { @instance.send_push('/welcome/aboard', 'iZac') }.should raise_error(RightScale::Sender::SendFailure)
|
443
|
+
end
|
316
444
|
end
|
317
445
|
|
318
446
|
describe "when making a send_persistent_push request" do
|
@@ -380,7 +508,6 @@ describe RightScale::Sender do
|
|
380
508
|
before(:each) do
|
381
509
|
@timer = flexmock("timer")
|
382
510
|
flexmock(EM::Timer).should_receive(:new).and_return(@timer).by_default
|
383
|
-
flexmock(EM).should_receive(:next_tick).and_yield.by_default
|
384
511
|
@broker_id = "broker"
|
385
512
|
@broker_ids = [@broker_id]
|
386
513
|
@broker = flexmock("Broker", :subscribe => true, :publish => @broker_ids, :connected? => true,
|
@@ -394,33 +521,15 @@ describe RightScale::Sender do
|
|
394
521
|
|
395
522
|
it "should validate target" do
|
396
523
|
@broker.should_receive(:publish)
|
397
|
-
|
398
|
-
|
399
|
-
lambda { @instance.send_retryable_request('/foo/bar', nil, {}) }.should be_true
|
400
|
-
lambda { @instance.send_retryable_request('/foo/bar', nil, :tags => "tags") }.should be_true
|
401
|
-
lambda { @instance.send_retryable_request('/foo/bar', nil, "tags" => "tags") }.should be_true
|
402
|
-
lambda { @instance.send_retryable_request('/foo/bar', nil, :tags => "tags", :scope => {:shard => 1}) }.should be_true
|
403
|
-
lambda { @instance.send_retryable_request('/foo/bar', nil, "scope" => {:shard => 1, "account" => 1}) }.should be_true
|
404
|
-
lambda { @instance.send_retryable_request('/foo/bar', nil, :scope => {}) }.should be_true
|
405
|
-
lambda { @instance.send_retryable_request('/foo/bar', nil, :selector => :all) }.should raise_error(ArgumentError)
|
406
|
-
lambda { @instance.send_retryable_request('/foo/bar', nil, 1) }.should raise_error(ArgumentError)
|
407
|
-
lambda { @instance.send_retryable_request('/foo/bar', nil, []) }.should raise_error(ArgumentError)
|
408
|
-
lambda { @instance.send_retryable_request('/foo/bar', nil, :bogus => 1) }.should raise_error(ArgumentError)
|
409
|
-
lambda { @instance.send_retryable_request('/foo/bar', nil, :scope => 1) }.should raise_error(ArgumentError)
|
410
|
-
lambda { @instance.send_retryable_request('/foo/bar', nil, :scope => {:bogus => 1}) }.should raise_error(ArgumentError)
|
411
|
-
lambda { @instance.send_retryable_request('/foo/bar', nil, :selector => :bogus) }.should raise_error(ArgumentError)
|
524
|
+
flexmock(@instance).should_receive(:validate_target).with("target", false).once
|
525
|
+
@instance.send_retryable_request('/foo/bar', nil, "target") {_}.should be_true
|
412
526
|
end
|
413
527
|
|
414
528
|
it "should create a Request object" do
|
415
529
|
@broker.should_receive(:publish).with(hsh(:name => "request"), on do |request|
|
416
530
|
request.class.should == RightScale::Request
|
417
531
|
end, hsh(:persistent => false, :mandatory => true)).once
|
418
|
-
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|
|
419
|
-
end
|
420
|
-
|
421
|
-
it "should process request in next tick to preserve pending request data integrity" do
|
422
|
-
flexmock(EM).should_receive(:next_tick).and_yield.once
|
423
|
-
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|response|}
|
532
|
+
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|_|}
|
424
533
|
end
|
425
534
|
|
426
535
|
it "should set correct attributes on the request message" do
|
@@ -433,7 +542,7 @@ describe RightScale::Sender do
|
|
433
542
|
request.target.should be_nil
|
434
543
|
request.expires_at.should == 1000100
|
435
544
|
end, hsh(:persistent => false, :mandatory => true)).once
|
436
|
-
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|
|
545
|
+
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|_|}
|
437
546
|
end
|
438
547
|
|
439
548
|
it "should disable time-to-live if disabled in configuration" do
|
@@ -445,14 +554,14 @@ describe RightScale::Sender do
|
|
445
554
|
@broker.should_receive(:publish).with(hsh(:name => "request"), on do |request|
|
446
555
|
request.expires_at.should == 0
|
447
556
|
end, hsh(:persistent => false, :mandatory => true)).once
|
448
|
-
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|
|
557
|
+
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|_|}
|
449
558
|
end
|
450
559
|
|
451
560
|
it "should set the correct target if specified" do
|
452
561
|
@broker.should_receive(:publish).with(hsh(:name => "request"), on do |request|
|
453
562
|
request.target.should == 'my-target'
|
454
563
|
end, hsh(:persistent => false, :mandatory => true)).once
|
455
|
-
@instance.send_retryable_request('/welcome/aboard', 'iZac', 'my-target') {|
|
564
|
+
@instance.send_retryable_request('/welcome/aboard', 'iZac', 'my-target') {|_|}
|
456
565
|
end
|
457
566
|
|
458
567
|
it "should set the correct target selectors if specified" do
|
@@ -461,12 +570,12 @@ describe RightScale::Sender do
|
|
461
570
|
request.selector.should == :any
|
462
571
|
request.scope.should == {:account => 123}
|
463
572
|
end, hsh(:persistent => false, :mandatory => true)).once
|
464
|
-
@instance.send_retryable_request('/welcome/aboard', 'iZac', :tags => ['tag'], :scope => {:account => 123})
|
573
|
+
@instance.send_retryable_request('/welcome/aboard', 'iZac', :tags => ['tag'], :scope => {:account => 123}) {|_|}
|
465
574
|
end
|
466
575
|
|
467
576
|
it "should set up for retrying the request if necessary by default" do
|
468
577
|
flexmock(@instance).should_receive(:publish_with_timeout_retry).once
|
469
|
-
@instance.send_retryable_request('/welcome/aboard', 'iZac', 'my-target') {|
|
578
|
+
@instance.send_retryable_request('/welcome/aboard', 'iZac', 'my-target') {|_|}
|
470
579
|
end
|
471
580
|
|
472
581
|
it "should store the response handler" do
|
@@ -480,7 +589,7 @@ describe RightScale::Sender do
|
|
480
589
|
flexmock(RightScale::AgentIdentity).should_receive(:generate).and_return('abc').once
|
481
590
|
flexmock(Time).should_receive(:now).and_return(Time.at(1000000)).by_default
|
482
591
|
@instance.pending_requests.kind(RightScale::Sender::PendingRequests::REQUEST_KINDS).youngest_age.should be_nil
|
483
|
-
@instance.send_retryable_request('/welcome/aboard', 'iZac')
|
592
|
+
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|_|}
|
484
593
|
@instance.pending_requests['abc'].receive_time.should == Time.at(1000000)
|
485
594
|
flexmock(Time).should_receive(:now).and_return(Time.at(1000100))
|
486
595
|
@instance.pending_requests.kind(RightScale::Sender::PendingRequests::REQUEST_KINDS).youngest_age.should == 100
|
@@ -494,17 +603,40 @@ describe RightScale::Sender do
|
|
494
603
|
@broker.should_receive(:publish).never
|
495
604
|
@instance.enable_offline_mode
|
496
605
|
@instance.offline_handler.mode.should == :offline
|
497
|
-
@instance.send_retryable_request('/welcome/aboard', 'iZac')
|
606
|
+
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|_|}
|
498
607
|
@instance.offline_handler.queue.size.should == 1
|
499
608
|
end
|
500
609
|
|
610
|
+
it 'should raise exception if not connected to any brokers and :offline_queueing disabled' do
|
611
|
+
@log.should_receive(:error).with(/Failed to publish request/, RightAMQP::HABrokerClient::NoConnectedBrokers).once
|
612
|
+
@broker.should_receive(:publish).and_raise(RightAMQP::HABrokerClient::NoConnectedBrokers)
|
613
|
+
@agent.should_receive(:options).and_return({:offline_queueing => false})
|
614
|
+
RightScale::Sender.new(@agent)
|
615
|
+
@instance = RightScale::Sender.instance
|
616
|
+
lambda { @instance.send_retryable_request('/welcome/aboard', 'iZac') {|_|} }.should raise_error(RightScale::Sender::TemporarilyOffline)
|
617
|
+
end
|
618
|
+
|
501
619
|
it "should dump the pending requests" do
|
502
620
|
flexmock(RightScale::AgentIdentity).should_receive(:generate).and_return('abc').once
|
503
621
|
flexmock(Time).should_receive(:now).and_return(Time.at(1000000))
|
504
|
-
@instance.send_retryable_request('/welcome/aboard', 'iZac')
|
622
|
+
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|_|}
|
505
623
|
@instance.dump_requests.should == ["#{Time.at(1000000).localtime} <abc>"]
|
506
624
|
end
|
507
625
|
|
626
|
+
it "should not allow a selector target" do
|
627
|
+
lambda { @instance.send_retryable_request('/welcome/aboard', 'iZac', :selector => :all) }.should raise_error(ArgumentError)
|
628
|
+
end
|
629
|
+
|
630
|
+
it "should raise error if there is no callback block" do
|
631
|
+
lambda { @instance.send_retryable_request('/welcome/aboard', 'iZac') }.should raise_error(ArgumentError)
|
632
|
+
end
|
633
|
+
|
634
|
+
it "should log exceptions and re-raise them" do
|
635
|
+
@log.should_receive(:error).with(/Failed to publish request/, Exception, :trace).once
|
636
|
+
@broker.should_receive(:publish).and_raise(Exception)
|
637
|
+
lambda { @instance.send_retryable_request('/welcome/aboard', 'iZac') {|r|} }.should raise_error(RightScale::Sender::SendFailure)
|
638
|
+
end
|
639
|
+
|
508
640
|
describe "with retry" do
|
509
641
|
it "should not setup for retry if retry_timeout nil" do
|
510
642
|
flexmock(EM).should_receive(:add_timer).never
|
@@ -512,7 +644,7 @@ describe RightScale::Sender do
|
|
512
644
|
RightScale::Sender.new(@agent)
|
513
645
|
@instance = RightScale::Sender.instance
|
514
646
|
@broker.should_receive(:publish).once
|
515
|
-
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|
|
647
|
+
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|_|}
|
516
648
|
end
|
517
649
|
|
518
650
|
it "should not setup for retry if retry_interval nil" do
|
@@ -521,7 +653,7 @@ describe RightScale::Sender do
|
|
521
653
|
RightScale::Sender.new(@agent)
|
522
654
|
@instance = RightScale::Sender.instance
|
523
655
|
@broker.should_receive(:publish).once
|
524
|
-
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|
|
656
|
+
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|_|}
|
525
657
|
end
|
526
658
|
|
527
659
|
it "should not setup for retry if publish failed" do
|
@@ -530,7 +662,7 @@ describe RightScale::Sender do
|
|
530
662
|
RightScale::Sender.new(@agent)
|
531
663
|
@instance = RightScale::Sender.instance
|
532
664
|
@broker.should_receive(:publish).and_return([]).once
|
533
|
-
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|
|
665
|
+
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|_|}
|
534
666
|
end
|
535
667
|
|
536
668
|
it "should setup for retry if retry_timeout and retry_interval not nil and publish successful" do
|
@@ -539,7 +671,7 @@ describe RightScale::Sender do
|
|
539
671
|
RightScale::Sender.new(@agent)
|
540
672
|
@instance = RightScale::Sender.instance
|
541
673
|
@broker.should_receive(:publish).and_return(@broker_ids).once
|
542
|
-
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|
|
674
|
+
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|_|}
|
543
675
|
end
|
544
676
|
|
545
677
|
it "should adjust retry interval by recent request duration" do
|
@@ -559,12 +691,10 @@ describe RightScale::Sender do
|
|
559
691
|
@instance.send_retryable_request('/welcome/aboard', 'iZac') do |response|
|
560
692
|
result = RightScale::OperationResult.from_results(response)
|
561
693
|
end
|
562
|
-
header = flexmock("amqp header")
|
563
|
-
header.should_receive(:ack).once
|
564
694
|
EM.add_timer(0.15) do
|
565
695
|
@instance.pending_requests.empty?.should be_false
|
566
696
|
result = RightScale::Result.new(token, nil, {'from' => RightScale::OperationResult.success}, nil)
|
567
|
-
@instance.handle_response(result
|
697
|
+
@instance.handle_response(result)
|
568
698
|
end
|
569
699
|
EM.add_timer(0.3) do
|
570
700
|
EM.stop
|
@@ -609,7 +739,7 @@ describe RightScale::Sender do
|
|
609
739
|
@broker.should_receive(:publish).with(hsh(:name => "request"), on do |request|
|
610
740
|
request.expires_at.should == (expires_at ||= request.expires_at)
|
611
741
|
end, hsh(:persistent => false, :mandatory => true)).and_return(@broker_ids).twice
|
612
|
-
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|
|
742
|
+
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|_|}
|
613
743
|
EM.add_timer(0.2) { EM.stop }
|
614
744
|
end
|
615
745
|
end
|
@@ -675,7 +805,6 @@ describe RightScale::Sender do
|
|
675
805
|
before(:each) do
|
676
806
|
@timer = flexmock("timer")
|
677
807
|
flexmock(EM::Timer).should_receive(:new).and_return(@timer).by_default
|
678
|
-
flexmock(EM).should_receive(:next_tick).and_yield.by_default
|
679
808
|
@broker_id = "broker"
|
680
809
|
@broker_ids = [@broker_id]
|
681
810
|
@broker = flexmock("Broker", :subscribe => true, :publish => @broker_ids, :connected? => true,
|
@@ -691,7 +820,7 @@ describe RightScale::Sender do
|
|
691
820
|
@broker.should_receive(:publish).with(hsh(:name => "request"), on do |request|
|
692
821
|
request.class.should == RightScale::Request
|
693
822
|
end, hsh(:persistent => true, :mandatory => true)).once
|
694
|
-
@instance.send_persistent_request('/welcome/aboard', 'iZac') {|
|
823
|
+
@instance.send_persistent_request('/welcome/aboard', 'iZac') {|_|}
|
695
824
|
end
|
696
825
|
|
697
826
|
it "should set correct attributes on the request message" do
|
@@ -704,14 +833,14 @@ describe RightScale::Sender do
|
|
704
833
|
request.target.should be_nil
|
705
834
|
request.expires_at.should == 0
|
706
835
|
end, hsh(:persistent => true, :mandatory => true)).once
|
707
|
-
@instance.send_persistent_request('/welcome/aboard', 'iZac') {|
|
836
|
+
@instance.send_persistent_request('/welcome/aboard', 'iZac') {|_|}
|
708
837
|
end
|
709
838
|
|
710
839
|
it "should set the correct target if specified" do
|
711
840
|
@broker.should_receive(:publish).with(hsh(:name => "request"), on do |request|
|
712
841
|
request.target.should == 'my-target'
|
713
842
|
end, hsh(:persistent => true, :mandatory => true)).once
|
714
|
-
@instance.send_persistent_request('/welcome/aboard', 'iZac', 'my-target') {|
|
843
|
+
@instance.send_persistent_request('/welcome/aboard', 'iZac', 'my-target') {|_|}
|
715
844
|
end
|
716
845
|
|
717
846
|
it "should set the correct target selectors if specified" do
|
@@ -720,18 +849,25 @@ describe RightScale::Sender do
|
|
720
849
|
request.selector.should == :any
|
721
850
|
request.scope.should == {:account => 123}
|
722
851
|
end, hsh(:persistent => true, :mandatory => true)).once
|
723
|
-
@instance.send_persistent_request('/welcome/aboard', 'iZac', :tags => ['tag'], :scope => {:account => 123})
|
852
|
+
@instance.send_persistent_request('/welcome/aboard', 'iZac', :tags => ['tag'], :scope => {:account => 123}) {|_|}
|
724
853
|
end
|
725
854
|
|
726
855
|
it "should not set up for retrying the request" do
|
727
856
|
flexmock(@instance).should_receive(:publish_with_timeout_retry).never
|
728
|
-
@instance.send_persistent_request('/welcome/aboard', 'iZac', 'my-target') {|
|
857
|
+
@instance.send_persistent_request('/welcome/aboard', 'iZac', 'my-target') {|_|}
|
858
|
+
end
|
859
|
+
|
860
|
+
it "should not allow a selector target" do
|
861
|
+
lambda { @instance.send_retryable_request('/welcome/aboard', 'iZac', :selector => :all) }.should raise_error(ArgumentError)
|
862
|
+
end
|
863
|
+
|
864
|
+
it "should raise error if there is no callback block" do
|
865
|
+
lambda { @instance.send_persistent_request('/welcome/aboard', 'iZac') }.should raise_error(ArgumentError)
|
729
866
|
end
|
730
867
|
end
|
731
868
|
|
732
869
|
describe "when handling a response" do
|
733
870
|
before(:each) do
|
734
|
-
flexmock(EM).should_receive(:next_tick).and_yield.by_default
|
735
871
|
flexmock(EM).should_receive(:defer).and_yield.by_default
|
736
872
|
@broker = flexmock("Broker", :subscribe => true, :publish => ["broker"], :connected? => true,
|
737
873
|
:identity_parts => ["host", 123, 0, 0]).by_default
|
@@ -739,92 +875,61 @@ describe RightScale::Sender do
|
|
739
875
|
RightScale::Sender.new(@agent)
|
740
876
|
@instance = RightScale::Sender.instance
|
741
877
|
flexmock(RightScale::AgentIdentity, :generate => 'token1')
|
742
|
-
@header = flexmock("amqp header")
|
743
878
|
end
|
744
879
|
|
745
880
|
it "should deliver the response for a Request" do
|
746
881
|
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|_|}
|
747
882
|
response = RightScale::Result.new('token1', 'to', RightScale::OperationResult.success, 'target1')
|
748
|
-
flexmock(@instance).should_receive(:deliver).with(response, RightScale::Sender::PendingRequest
|
749
|
-
@instance.handle_response(response
|
883
|
+
flexmock(@instance).should_receive(:deliver).with(response, RightScale::Sender::PendingRequest).once
|
884
|
+
@instance.handle_response(response)
|
750
885
|
end
|
751
886
|
|
752
887
|
it "should deliver the response for a Push" do
|
753
888
|
@instance.send_push('/welcome/aboard', 'iZac') {|_|}
|
754
889
|
response = RightScale::Result.new('token1', 'to', RightScale::OperationResult.success, 'target1')
|
755
|
-
flexmock(@instance).should_receive(:deliver).with(response, RightScale::Sender::PendingRequest
|
756
|
-
@instance.handle_response(response
|
890
|
+
flexmock(@instance).should_receive(:deliver).with(response, RightScale::Sender::PendingRequest).once
|
891
|
+
@instance.handle_response(response)
|
757
892
|
end
|
758
893
|
|
759
894
|
it "should not deliver TARGET_NOT_CONNECTED and TTL_EXPIRATION responses for send_retryable_request" do
|
760
|
-
@header.should_receive(:ack).twice
|
761
895
|
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|_|}
|
762
896
|
flexmock(@instance).should_receive(:deliver).never
|
763
897
|
non_delivery = RightScale::OperationResult.non_delivery(RightScale::OperationResult::TARGET_NOT_CONNECTED)
|
764
898
|
response = RightScale::Result.new('token1', 'to', non_delivery, 'target1')
|
765
|
-
@instance.handle_response(response
|
899
|
+
@instance.handle_response(response)
|
766
900
|
non_delivery = RightScale::OperationResult.non_delivery(RightScale::OperationResult::TTL_EXPIRATION)
|
767
901
|
response = RightScale::Result.new('token1', 'to', non_delivery, 'target1')
|
768
|
-
@instance.handle_response(response
|
902
|
+
@instance.handle_response(response)
|
769
903
|
end
|
770
904
|
|
771
905
|
it "should record non-delivery regardless of whether there is a response handler" do
|
772
|
-
@header.should_receive(:ack).once
|
773
906
|
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|_|}
|
774
907
|
non_delivery = RightScale::OperationResult.non_delivery(RightScale::OperationResult::NO_ROUTE_TO_TARGET)
|
775
908
|
response = RightScale::Result.new('token1', 'to', non_delivery, 'target1')
|
776
|
-
@instance.handle_response(response
|
909
|
+
@instance.handle_response(response)
|
777
910
|
@instance.instance_variable_get(:@non_delivery_stats).total.should == 1
|
778
911
|
end
|
779
912
|
|
780
913
|
it "should log non-delivery if there is no response handler" do
|
781
|
-
@header.should_receive(:ack).once
|
782
914
|
@log.should_receive(:info).with(/Non-delivery of/).once
|
783
915
|
@instance.send_push('/welcome/aboard', 'iZac')
|
784
916
|
non_delivery = RightScale::OperationResult.non_delivery(RightScale::OperationResult::NO_ROUTE_TO_TARGET)
|
785
917
|
response = RightScale::Result.new('token1', 'to', non_delivery, 'target1')
|
786
|
-
@instance.handle_response(response
|
918
|
+
@instance.handle_response(response)
|
787
919
|
end
|
788
920
|
|
789
921
|
it "should log a debug message if request no longer pending" do
|
790
|
-
@header.should_receive(:ack).once
|
791
922
|
@log.should_receive(:debug).with(/No pending request for response/).once
|
792
923
|
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|_|}
|
793
924
|
@instance.pending_requests['token1'].should_not be_nil
|
794
925
|
@instance.pending_requests['token2'].should be_nil
|
795
926
|
response = RightScale::Result.new('token2', 'to', RightScale::OperationResult.success, 'target1')
|
796
|
-
@instance.handle_response(response, @header)
|
797
|
-
end
|
798
|
-
|
799
|
-
it "should ack response even if fail while handling it" do
|
800
|
-
@header.should_receive(:ack).once
|
801
|
-
@instance.send_push('/welcome/aboard', 'iZac') {|_|}
|
802
|
-
response = RightScale::Result.new('token1', 'to', RightScale::OperationResult.success, 'target1')
|
803
|
-
flexmock(response).should_receive(:token).and_raise(Exception).once
|
804
|
-
flexmock(@instance).should_receive(:deliver).never
|
805
|
-
lambda { @instance.handle_response(response, @header) }.should raise_error(Exception)
|
806
|
-
end
|
807
|
-
|
808
|
-
it "should not attempt to ack response if fail while handling it and there is no header" do
|
809
|
-
@instance.send_push('/welcome/aboard', 'iZac') {|_|}
|
810
|
-
response = RightScale::Result.new('token1', 'to', RightScale::OperationResult.success, 'target1')
|
811
|
-
exception = Exception.new("test")
|
812
|
-
flexmock(response).should_receive(:token).and_raise(exception).once
|
813
|
-
flexmock(@instance).should_receive(:deliver).never
|
814
|
-
lambda { @instance.handle_response(response, nil) }.should raise_error(Exception, "test")
|
815
|
-
end
|
816
|
-
|
817
|
-
it "should not attempt to ack response if there is no header" do
|
818
|
-
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|_|}
|
819
|
-
response = RightScale::Result.new('token1', 'to', RightScale::OperationResult.success, 'target1')
|
820
|
-
flexmock(@instance).should_receive(:deliver).with(response, RightScale::Sender::PendingRequest, nil).once
|
821
927
|
@instance.handle_response(response)
|
822
928
|
end
|
823
929
|
end
|
824
930
|
|
825
931
|
describe "when delivering a response" do
|
826
932
|
before(:each) do
|
827
|
-
flexmock(EM).should_receive(:next_tick).and_yield.by_default
|
828
933
|
flexmock(EM).should_receive(:defer).and_yield.by_default
|
829
934
|
@broker = flexmock("Broker", :subscribe => true, :publish => ["broker"], :connected? => true,
|
830
935
|
:identity_parts => ["host", 123, 0, 0]).by_default
|
@@ -832,15 +937,13 @@ describe RightScale::Sender do
|
|
832
937
|
RightScale::Sender.new(@agent)
|
833
938
|
@instance = RightScale::Sender.instance
|
834
939
|
flexmock(RightScale::AgentIdentity, :generate => 'token1')
|
835
|
-
@header = flexmock("amqp header")
|
836
|
-
@header.should_receive(:ack).once.by_default
|
837
940
|
end
|
838
941
|
|
839
942
|
it "should delete all associated pending Request requests" do
|
840
943
|
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|_|}
|
841
944
|
@instance.pending_requests['token1'].should_not be_nil
|
842
945
|
response = RightScale::Result.new('token1', 'to', RightScale::OperationResult.success, 'target1')
|
843
|
-
@instance.handle_response(response
|
946
|
+
@instance.handle_response(response)
|
844
947
|
@instance.pending_requests['token1'].should be_nil
|
845
948
|
end
|
846
949
|
|
@@ -848,7 +951,7 @@ describe RightScale::Sender do
|
|
848
951
|
@instance.send_push('/welcome/aboard', 'iZac') {|_|}
|
849
952
|
@instance.pending_requests['token1'].should_not be_nil
|
850
953
|
response = RightScale::Result.new('token1', 'to', RightScale::OperationResult.success, 'target1')
|
851
|
-
@instance.handle_response(response
|
954
|
+
@instance.handle_response(response)
|
852
955
|
@instance.pending_requests['token1'].should_not be_nil
|
853
956
|
end
|
854
957
|
|
@@ -858,7 +961,7 @@ describe RightScale::Sender do
|
|
858
961
|
@instance.pending_requests['token2'] = @instance.pending_requests['token1'].dup
|
859
962
|
@instance.pending_requests['token2'].retry_parent = 'token1'
|
860
963
|
response = RightScale::Result.new('token2', 'to', RightScale::OperationResult.success, 'target1')
|
861
|
-
@instance.handle_response(response
|
964
|
+
@instance.handle_response(response)
|
862
965
|
@instance.pending_requests['token1'].should be_nil
|
863
966
|
@instance.pending_requests['token2'].should be_nil
|
864
967
|
end
|
@@ -867,67 +970,8 @@ describe RightScale::Sender do
|
|
867
970
|
called = 0
|
868
971
|
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|response| called += 1}
|
869
972
|
response = RightScale::Result.new('token1', 'to', RightScale::OperationResult.success, 'target1')
|
870
|
-
@instance.handle_response(response, @header)
|
871
|
-
called.should == 1
|
872
|
-
end
|
873
|
-
|
874
|
-
it "should defer the response handler call if not single threaded" do
|
875
|
-
@agent.should_receive(:options).and_return({:single_threaded => false})
|
876
|
-
RightScale::Sender.new(@agent)
|
877
|
-
@instance = RightScale::Sender.instance
|
878
|
-
called = 0
|
879
|
-
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|response| called += 1}
|
880
|
-
response = RightScale::Result.new('token1', 'to', RightScale::OperationResult.success, 'target1')
|
881
|
-
flexmock(EM).should_receive(:defer).and_yield.once
|
882
|
-
flexmock(EM).should_receive(:next_tick).never
|
883
|
-
@instance.handle_response(response, @header)
|
884
|
-
called.should == 1
|
885
|
-
end
|
886
|
-
|
887
|
-
it "should not defer the response handler call if single threaded" do
|
888
|
-
@agent.should_receive(:options).and_return({:single_threaded => true})
|
889
|
-
RightScale::Sender.new(@agent)
|
890
|
-
@instance = RightScale::Sender.instance
|
891
|
-
called = 0
|
892
|
-
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|response| called += 1}
|
893
|
-
response = RightScale::Result.new('token1', 'to', RightScale::OperationResult.success, 'target1')
|
894
|
-
flexmock(EM).should_receive(:next_tick).and_yield.once
|
895
|
-
flexmock(EM).should_receive(:defer).never
|
896
|
-
@instance.handle_response(response, @header)
|
897
|
-
called.should == 1
|
898
|
-
end
|
899
|
-
|
900
|
-
it "should log an error if the response handler raises an exception but still delete pending request" do
|
901
|
-
@agent.should_receive(:options).and_return({:single_threaded => true})
|
902
|
-
@log.should_receive(:error).with(/Failed processing response/, Exception, :trace).once
|
903
|
-
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|_| raise Exception}
|
904
|
-
@instance.pending_requests['token1'].should_not be_nil
|
905
|
-
response = RightScale::Result.new('token1', 'to', RightScale::OperationResult.success, 'target1')
|
906
|
-
@instance.handle_response(response, @header)
|
907
|
-
@instance.pending_requests['token1'].should be_nil
|
908
|
-
end
|
909
|
-
|
910
|
-
it "should ack response even if fail while delivering it" do
|
911
|
-
flexmock(EM).should_receive(:defer).and_raise(Exception).once
|
912
|
-
@instance.send_push('/welcome/aboard', 'iZac') {|_|}
|
913
|
-
response = RightScale::Result.new('token1', 'to', RightScale::OperationResult.success, 'target1')
|
914
|
-
lambda { @instance.handle_response(response, @header) }.should raise_error(Exception)
|
915
|
-
end
|
916
|
-
|
917
|
-
it "should not attempt to ack response if fail while delivering it and there is no header" do
|
918
|
-
@header.should_receive(:ack).never
|
919
|
-
exception = Exception.new("test")
|
920
|
-
flexmock(EM).should_receive(:defer).and_raise(exception).once
|
921
|
-
@instance.send_push('/welcome/aboard', 'iZac') {|_|}
|
922
|
-
response = RightScale::Result.new('token1', 'to', RightScale::OperationResult.success, 'target1')
|
923
|
-
lambda { @instance.handle_response(response, nil) }.should raise_error(Exception, "test")
|
924
|
-
end
|
925
|
-
|
926
|
-
it "should not attempt to ack response if there is no header" do
|
927
|
-
@header.should_receive(:ack).never
|
928
|
-
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|_|}
|
929
|
-
response = RightScale::Result.new('token1', 'to', RightScale::OperationResult.success, 'target1')
|
930
973
|
@instance.handle_response(response)
|
974
|
+
called.should == 1
|
931
975
|
end
|
932
976
|
end
|
933
977
|
|