right_agent 0.5.1
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 +78 -0
- data/Rakefile +86 -0
- data/lib/right_agent.rb +66 -0
- data/lib/right_agent/actor.rb +163 -0
- data/lib/right_agent/actor_registry.rb +76 -0
- data/lib/right_agent/actors/agent_manager.rb +189 -0
- data/lib/right_agent/agent.rb +735 -0
- data/lib/right_agent/agent_config.rb +403 -0
- data/lib/right_agent/agent_identity.rb +209 -0
- data/lib/right_agent/agent_tags_manager.rb +213 -0
- data/lib/right_agent/audit_formatter.rb +107 -0
- data/lib/right_agent/broker_client.rb +683 -0
- data/lib/right_agent/command.rb +30 -0
- data/lib/right_agent/command/agent_manager_commands.rb +134 -0
- data/lib/right_agent/command/command_client.rb +136 -0
- data/lib/right_agent/command/command_constants.rb +42 -0
- data/lib/right_agent/command/command_io.rb +128 -0
- data/lib/right_agent/command/command_parser.rb +87 -0
- data/lib/right_agent/command/command_runner.rb +105 -0
- data/lib/right_agent/command/command_serializer.rb +63 -0
- data/lib/right_agent/console.rb +65 -0
- data/lib/right_agent/core_payload_types.rb +42 -0
- data/lib/right_agent/core_payload_types/cookbook.rb +61 -0
- data/lib/right_agent/core_payload_types/cookbook_position.rb +46 -0
- data/lib/right_agent/core_payload_types/cookbook_repository.rb +116 -0
- data/lib/right_agent/core_payload_types/cookbook_sequence.rb +70 -0
- data/lib/right_agent/core_payload_types/dev_repositories.rb +90 -0
- data/lib/right_agent/core_payload_types/event_categories.rb +38 -0
- data/lib/right_agent/core_payload_types/executable_bundle.rb +138 -0
- data/lib/right_agent/core_payload_types/login_policy.rb +72 -0
- data/lib/right_agent/core_payload_types/login_user.rb +62 -0
- data/lib/right_agent/core_payload_types/planned_volume.rb +94 -0
- data/lib/right_agent/core_payload_types/recipe_instantiation.rb +60 -0
- data/lib/right_agent/core_payload_types/repositories_bundle.rb +50 -0
- data/lib/right_agent/core_payload_types/right_script_attachment.rb +95 -0
- data/lib/right_agent/core_payload_types/right_script_instantiation.rb +73 -0
- data/lib/right_agent/core_payload_types/secure_document.rb +66 -0
- data/lib/right_agent/core_payload_types/secure_document_location.rb +63 -0
- data/lib/right_agent/core_payload_types/software_repository_instantiation.rb +61 -0
- data/lib/right_agent/daemonize.rb +35 -0
- data/lib/right_agent/dispatcher.rb +348 -0
- data/lib/right_agent/enrollment_result.rb +217 -0
- data/lib/right_agent/exceptions.rb +30 -0
- data/lib/right_agent/ha_broker_client.rb +1278 -0
- data/lib/right_agent/idempotent_request.rb +140 -0
- data/lib/right_agent/log.rb +418 -0
- data/lib/right_agent/monkey_patches.rb +29 -0
- data/lib/right_agent/monkey_patches/amqp_patch.rb +274 -0
- data/lib/right_agent/monkey_patches/ruby_patch.rb +49 -0
- data/lib/right_agent/monkey_patches/ruby_patch/array_patch.rb +29 -0
- data/lib/right_agent/monkey_patches/ruby_patch/darwin_patch.rb +24 -0
- data/lib/right_agent/monkey_patches/ruby_patch/linux_patch.rb +24 -0
- data/lib/right_agent/monkey_patches/ruby_patch/linux_patch/file_patch.rb +30 -0
- data/lib/right_agent/monkey_patches/ruby_patch/object_patch.rb +49 -0
- data/lib/right_agent/monkey_patches/ruby_patch/singleton_patch.rb +46 -0
- data/lib/right_agent/monkey_patches/ruby_patch/string_patch.rb +107 -0
- data/lib/right_agent/monkey_patches/ruby_patch/windows_patch.rb +32 -0
- data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/file_patch.rb +90 -0
- data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/process_patch.rb +63 -0
- data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/stdio_patch.rb +27 -0
- data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/time_patch.rb +55 -0
- data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/win32ole_patch.rb +34 -0
- data/lib/right_agent/multiplexer.rb +91 -0
- data/lib/right_agent/operation_result.rb +270 -0
- data/lib/right_agent/packets.rb +637 -0
- data/lib/right_agent/payload_formatter.rb +104 -0
- data/lib/right_agent/pid_file.rb +159 -0
- data/lib/right_agent/platform.rb +319 -0
- data/lib/right_agent/platform/darwin.rb +227 -0
- data/lib/right_agent/platform/linux.rb +268 -0
- data/lib/right_agent/platform/windows.rb +1204 -0
- data/lib/right_agent/scripts/agent_controller.rb +522 -0
- data/lib/right_agent/scripts/agent_deployer.rb +379 -0
- data/lib/right_agent/scripts/common_parser.rb +153 -0
- data/lib/right_agent/scripts/log_level_manager.rb +193 -0
- data/lib/right_agent/scripts/stats_manager.rb +256 -0
- data/lib/right_agent/scripts/usage.rb +58 -0
- data/lib/right_agent/secure_identity.rb +92 -0
- data/lib/right_agent/security.rb +32 -0
- data/lib/right_agent/security/cached_certificate_store_proxy.rb +63 -0
- data/lib/right_agent/security/certificate.rb +102 -0
- data/lib/right_agent/security/certificate_cache.rb +89 -0
- data/lib/right_agent/security/distinguished_name.rb +56 -0
- data/lib/right_agent/security/encrypted_document.rb +84 -0
- data/lib/right_agent/security/rsa_key_pair.rb +76 -0
- data/lib/right_agent/security/signature.rb +86 -0
- data/lib/right_agent/security/static_certificate_store.rb +69 -0
- data/lib/right_agent/sender.rb +937 -0
- data/lib/right_agent/serialize.rb +29 -0
- data/lib/right_agent/serialize/message_pack.rb +102 -0
- data/lib/right_agent/serialize/secure_serializer.rb +131 -0
- data/lib/right_agent/serialize/secure_serializer_initializer.rb +47 -0
- data/lib/right_agent/serialize/serializable.rb +135 -0
- data/lib/right_agent/serialize/serializer.rb +149 -0
- data/lib/right_agent/stats_helper.rb +731 -0
- data/lib/right_agent/subprocess.rb +38 -0
- data/lib/right_agent/tracer.rb +124 -0
- data/right_agent.gemspec +60 -0
- data/spec/actor_registry_spec.rb +81 -0
- data/spec/actor_spec.rb +99 -0
- data/spec/agent_config_spec.rb +226 -0
- data/spec/agent_identity_spec.rb +75 -0
- data/spec/agent_spec.rb +571 -0
- data/spec/broker_client_spec.rb +961 -0
- data/spec/command/agent_manager_commands_spec.rb +51 -0
- data/spec/command/command_io_spec.rb +93 -0
- data/spec/command/command_parser_spec.rb +79 -0
- data/spec/command/command_runner_spec.rb +72 -0
- data/spec/command/command_serializer_spec.rb +51 -0
- data/spec/core_payload_types/dev_repositories_spec.rb +64 -0
- data/spec/core_payload_types/executable_bundle_spec.rb +59 -0
- data/spec/core_payload_types/login_user_spec.rb +98 -0
- data/spec/core_payload_types/right_script_attachment_spec.rb +65 -0
- data/spec/core_payload_types/spec_helper.rb +23 -0
- data/spec/dispatcher_spec.rb +372 -0
- data/spec/enrollment_result_spec.rb +53 -0
- data/spec/ha_broker_client_spec.rb +1673 -0
- data/spec/idempotent_request_spec.rb +136 -0
- data/spec/log_spec.rb +177 -0
- data/spec/monkey_patches/amqp_patch_spec.rb +100 -0
- data/spec/monkey_patches/eventmachine_spec.rb +62 -0
- data/spec/monkey_patches/string_patch_spec.rb +99 -0
- data/spec/multiplexer_spec.rb +48 -0
- data/spec/operation_result_spec.rb +171 -0
- data/spec/packets_spec.rb +418 -0
- data/spec/platform/platform_spec.rb +60 -0
- data/spec/results_mock.rb +45 -0
- data/spec/secure_identity_spec.rb +50 -0
- data/spec/security/cached_certificate_store_proxy_spec.rb +56 -0
- data/spec/security/certificate_cache_spec.rb +71 -0
- data/spec/security/certificate_spec.rb +49 -0
- data/spec/security/distinguished_name_spec.rb +46 -0
- data/spec/security/encrypted_document_spec.rb +55 -0
- data/spec/security/rsa_key_pair_spec.rb +55 -0
- data/spec/security/signature_spec.rb +66 -0
- data/spec/security/static_certificate_store_spec.rb +52 -0
- data/spec/sender_spec.rb +887 -0
- data/spec/serialize/message_pack_spec.rb +131 -0
- data/spec/serialize/secure_serializer_spec.rb +102 -0
- data/spec/serialize/serializable_spec.rb +90 -0
- data/spec/serialize/serializer_spec.rb +174 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +77 -0
- data/spec/stats_helper_spec.rb +681 -0
- data/spec/tracer_spec.rb +114 -0
- metadata +320 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (c) 2009-2011 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
|
+
|
|
25
|
+
describe RightScale::Signature do
|
|
26
|
+
|
|
27
|
+
include RightScale::SpecHelper
|
|
28
|
+
|
|
29
|
+
before(:all) do
|
|
30
|
+
@test_data = "Test Data"
|
|
31
|
+
@cert, @key = issue_cert
|
|
32
|
+
@sig = RightScale::Signature.new(@test_data, @cert, @key)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it 'should create signed data' do
|
|
36
|
+
@sig.to_s.should_not be_empty
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it 'should create signed data using either PEM or DER format' do
|
|
40
|
+
@sig.data(:pem).should_not be_empty
|
|
41
|
+
@sig.data(:der).should_not be_empty
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it 'should verify the signature' do
|
|
45
|
+
cert2, key2 = issue_cert
|
|
46
|
+
|
|
47
|
+
@sig.should be_a_match(@cert)
|
|
48
|
+
@sig.should_not be_a_match(cert2)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it 'should load from serialized signature' do
|
|
52
|
+
sig2 = RightScale::Signature.from_data(@sig.data)
|
|
53
|
+
sig2.should_not be_nil
|
|
54
|
+
sig2.should be_a_match(@cert)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it 'should load from serialized signature using either PEM or DER format' do
|
|
58
|
+
sig2 = RightScale::Signature.from_data(@sig.data(:pem))
|
|
59
|
+
sig2.should_not be_nil
|
|
60
|
+
sig2.should be_a_match(@cert)
|
|
61
|
+
sig2 = RightScale::Signature.from_data(@sig.data(:der))
|
|
62
|
+
sig2.should_not be_nil
|
|
63
|
+
sig2.should be_a_match(@cert)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (c) 2009-2011 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
|
+
|
|
25
|
+
describe RightScale::StaticCertificateStore do
|
|
26
|
+
|
|
27
|
+
include RightScale::SpecHelper
|
|
28
|
+
|
|
29
|
+
before(:all) do
|
|
30
|
+
@signer, key = issue_cert
|
|
31
|
+
@recipient, key = issue_cert
|
|
32
|
+
@cert, @key = issue_cert
|
|
33
|
+
@store = RightScale::StaticCertificateStore.new(@signer, @recipient)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it 'should not raise when passed nil objects' do
|
|
37
|
+
res = nil
|
|
38
|
+
lambda { res = @store.get_signer(nil) }.should_not raise_error
|
|
39
|
+
res.should == [ @signer ]
|
|
40
|
+
lambda { res = @store.get_recipients(nil) }.should_not raise_error
|
|
41
|
+
res.should == [ @recipient ]
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it 'should return signer certificates' do
|
|
45
|
+
@store.get_signer('anything').should == [ @signer ]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it 'should return recipient certificates' do
|
|
49
|
+
@store.get_recipients('anything').should == [ @recipient ]
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
end
|
data/spec/sender_spec.rb
ADDED
|
@@ -0,0 +1,887 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (c) 2009-2011 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
|
+
|
|
25
|
+
describe RightScale::Sender do
|
|
26
|
+
|
|
27
|
+
include FlexMock::ArgumentTypes
|
|
28
|
+
|
|
29
|
+
before(:each) do
|
|
30
|
+
@log = flexmock(RightScale::Log)
|
|
31
|
+
@log.should_receive(:error).by_default.and_return { |m| raise RightScale::Log.format(*m) }
|
|
32
|
+
@log.should_receive(:warning).by_default.and_return { |m| raise RightScale::Log.format(*m) }
|
|
33
|
+
@timer = flexmock("timer", :cancel => true).by_default
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
describe "when fetching the instance" do
|
|
37
|
+
before do
|
|
38
|
+
RightScale::Sender.class_eval do
|
|
39
|
+
if class_variable_defined?(:@@instance)
|
|
40
|
+
remove_class_variable(:@@instance)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "should return nil when the instance is undefined" do
|
|
46
|
+
RightScale::Sender.instance.should == nil
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it "should return the instance if defined" do
|
|
50
|
+
instance = flexmock
|
|
51
|
+
RightScale::Sender.class_eval do
|
|
52
|
+
@@instance = "instance"
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
RightScale::Sender.instance.should_not == nil
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
describe "when monitoring broker connectivity" do
|
|
60
|
+
before(:each) do
|
|
61
|
+
flexmock(EM).should_receive(:next_tick).and_yield.by_default
|
|
62
|
+
@broker = flexmock("Broker", :subscribe => true, :publish => ["broker"], :connected? => true,
|
|
63
|
+
:identity_parts => ["host", 123, 0, 0, nil]).by_default
|
|
64
|
+
@agent = flexmock("Agent", :identity => "agent", :broker => @broker, :options => {:ping_interval => 0}).by_default
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it "should start inactivity timer at initialization time" do
|
|
68
|
+
@agent.should_receive(:options).and_return(:ping_interval => 1000)
|
|
69
|
+
flexmock(EM::Timer).should_receive(:new).with(1000, Proc).and_return(@timer).once
|
|
70
|
+
RightScale::Sender.new(@agent)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
it "should not start inactivity timer at initialization time if ping disabled" do
|
|
74
|
+
flexmock(EM::Timer).should_receive(:new).never
|
|
75
|
+
RightScale::Sender.new(@agent)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it "should restart inactivity timer only if sufficient time has elapsed since last restart" do
|
|
79
|
+
@agent.should_receive(:options).and_return(:ping_interval => 1000)
|
|
80
|
+
flexmock(EM::Timer).should_receive(:new).with(1000, Proc).and_return(@timer).once
|
|
81
|
+
instance = RightScale::Sender.new(@agent)
|
|
82
|
+
flexmock(instance).should_receive(:restart_inactivity_timer).once
|
|
83
|
+
instance.message_received
|
|
84
|
+
instance.message_received
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it "should check connectivity if the inactivity timer times out" do
|
|
88
|
+
@agent.should_receive(:options).and_return(:ping_interval => 1000)
|
|
89
|
+
flexmock(EM::Timer).should_receive(:new).and_return(@timer).once.by_default
|
|
90
|
+
RightScale::Sender.new(@agent)
|
|
91
|
+
instance = RightScale::Sender.instance
|
|
92
|
+
flexmock(EM::Timer).should_receive(:new).and_return(@timer).and_yield.once
|
|
93
|
+
flexmock(instance).should_receive(:check_connection).once
|
|
94
|
+
instance.message_received
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
it "should ignore messages received if ping disabled" do
|
|
98
|
+
@agent.should_receive(:options).and_return(:ping_interval => 0)
|
|
99
|
+
flexmock(EM::Timer).should_receive(:new).never
|
|
100
|
+
RightScale::Sender.new(@agent)
|
|
101
|
+
RightScale::Sender.instance.message_received
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
it "should log an exception if the connectivity check fails" do
|
|
105
|
+
@log.should_receive(:error).with(/Failed connectivity check/, Exception, :trace).once
|
|
106
|
+
@agent.should_receive(:options).and_return(:ping_interval => 1000)
|
|
107
|
+
flexmock(EM::Timer).should_receive(:new).and_return(@timer).once.by_default
|
|
108
|
+
RightScale::Sender.new(@agent)
|
|
109
|
+
instance = RightScale::Sender.instance
|
|
110
|
+
flexmock(EM::Timer).should_receive(:new).and_return(@timer).and_yield.once
|
|
111
|
+
flexmock(instance).should_receive(:check_connection).and_raise(Exception)
|
|
112
|
+
instance.message_received
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
it "should attempt to reconnect if mapper ping times out" do
|
|
116
|
+
@log.should_receive(:warning).with(/Mapper ping via broker/).once
|
|
117
|
+
@agent.should_receive(:options).and_return(:ping_interval => 1000)
|
|
118
|
+
broker_id = "rs-broker-localhost-5672"
|
|
119
|
+
@broker.should_receive(:identity_parts).with(broker_id).and_return(["localhost", 5672, 0, 0, nil]).once
|
|
120
|
+
@agent.should_receive(:connect).with("localhost", 5672, 0, 0, true).once
|
|
121
|
+
old_ping_timeout = RightScale::Sender::PING_TIMEOUT
|
|
122
|
+
begin
|
|
123
|
+
RightScale::Sender.const_set(:PING_TIMEOUT, 0.5)
|
|
124
|
+
EM.run do
|
|
125
|
+
EM.add_timer(1) { EM.stop }
|
|
126
|
+
RightScale::Sender.new(@agent)
|
|
127
|
+
instance = RightScale::Sender.instance
|
|
128
|
+
flexmock(instance).should_receive(:publish).with(RightScale::Request, nil).and_return([broker_id])
|
|
129
|
+
instance.__send__(:check_connection)
|
|
130
|
+
end
|
|
131
|
+
ensure
|
|
132
|
+
RightScale::Sender.const_set(:PING_TIMEOUT, old_ping_timeout)
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
describe "when making a push request" do
|
|
138
|
+
before(:each) do
|
|
139
|
+
@timer = flexmock("timer")
|
|
140
|
+
flexmock(EM::Timer).should_receive(:new).and_return(@timer)
|
|
141
|
+
@broker = flexmock("Broker", :subscribe => true, :publish => true).by_default
|
|
142
|
+
@agent = flexmock("Agent", :identity => "agent", :broker => @broker).by_default
|
|
143
|
+
@agent.should_receive(:options).and_return({}).by_default
|
|
144
|
+
RightScale::Sender.new(@agent)
|
|
145
|
+
@instance = RightScale::Sender.instance
|
|
146
|
+
@instance.initialize_offline_queue
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
it "should validate target" do
|
|
150
|
+
@broker.should_receive(:publish)
|
|
151
|
+
lambda { @instance.send_push('/foo/bar', nil) }.should be_true
|
|
152
|
+
lambda { @instance.send_push('/foo/bar', nil, "target") }.should be_true
|
|
153
|
+
lambda { @instance.send_push('/foo/bar', nil, {}) }.should be_true
|
|
154
|
+
lambda { @instance.send_push('/foo/bar', nil, :tags => "tags") }.should be_true
|
|
155
|
+
lambda { @instance.send_push('/foo/bar', nil, "tags" => "tags") }.should be_true
|
|
156
|
+
lambda { @instance.send_push('/foo/bar', nil, :tags => "tags", :scope => {:shard => 1}) }.should be_true
|
|
157
|
+
lambda { @instance.send_push('/foo/bar', nil, "scope" => {:shard => 1, "account" => 1}) }.should be_true
|
|
158
|
+
lambda { @instance.send_push('/foo/bar', nil, :scope => {:deployment => 1}) }.should be_true
|
|
159
|
+
lambda { @instance.send_push('/foo/bar', nil, :scope => {}) }.should be_true
|
|
160
|
+
lambda { @instance.send_push('/foo/bar', nil, :selector => :all) }.should be_true
|
|
161
|
+
lambda { @instance.send_push('/foo/bar', nil, "selector" => "any") }.should be_true
|
|
162
|
+
lambda { @instance.send_push('/foo/bar', nil, 1) }.should raise_error(ArgumentError)
|
|
163
|
+
lambda { @instance.send_push('/foo/bar', nil, []) }.should raise_error(ArgumentError)
|
|
164
|
+
lambda { @instance.send_push('/foo/bar', nil, :bogus => 1) }.should raise_error(ArgumentError)
|
|
165
|
+
lambda { @instance.send_push('/foo/bar', nil, :scope => 1) }.should raise_error(ArgumentError)
|
|
166
|
+
lambda { @instance.send_push('/foo/bar', nil, :scope => {:bogus => 1}) }.should raise_error(ArgumentError)
|
|
167
|
+
lambda { @instance.send_push('/foo/bar', nil, :selector => :bogus) }.should raise_error(ArgumentError)
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
it "should create a Push object" do
|
|
171
|
+
@broker.should_receive(:publish).with(hsh(:name => "request"), on do |push|
|
|
172
|
+
push.class.should == RightScale::Push
|
|
173
|
+
end, hsh(:persistent => false, :mandatory => true)).once
|
|
174
|
+
@instance.send_push('/welcome/aboard', 'iZac')
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
it "should set the correct target if specified" do
|
|
178
|
+
@broker.should_receive(:publish).with(hsh(:name => "request"), on do |push|
|
|
179
|
+
push.target.should == 'my-target'
|
|
180
|
+
end, hsh(:persistent => false, :mandatory => true)).once
|
|
181
|
+
@instance.send_push('/welcome/aboard', 'iZac', 'my-target')
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
it "should set the correct target selectors for fanout if specified" do
|
|
185
|
+
@broker.should_receive(:publish).with(hsh(:name => "request"), on do |push|
|
|
186
|
+
push.tags.should == ['tag']
|
|
187
|
+
push.selector.should == :all
|
|
188
|
+
push.scope.should == {:account => 123}
|
|
189
|
+
end, hsh(:persistent => false, :mandatory => true)).once
|
|
190
|
+
@instance.send_push('/welcome/aboard', 'iZac', :tags => ['tag'], :selector => :all, :scope => {:account => 123})
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
it "should default the target selector to any" do
|
|
194
|
+
@broker.should_receive(:publish).with(hsh(:name => "request"), on do |push|
|
|
195
|
+
push.tags.should == ['tag']
|
|
196
|
+
push.scope.should == {:account => 123}
|
|
197
|
+
end, hsh(:persistent => false, :mandatory => true)).once
|
|
198
|
+
@instance.send_push('/welcome/aboard', 'iZac', :tags => ['tag'], :scope => {:account => 123})
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
it "should set correct attributes on the push message" do
|
|
202
|
+
@broker.should_receive(:publish).with(hsh(:name => "request"), on do |push|
|
|
203
|
+
push.type.should == '/welcome/aboard'
|
|
204
|
+
push.token.should_not be_nil
|
|
205
|
+
push.persistent.should be_false
|
|
206
|
+
push.from.should == 'agent'
|
|
207
|
+
push.target.should be_nil
|
|
208
|
+
push.expires_at.should == 0
|
|
209
|
+
end, hsh(:persistent => false, :mandatory => true)).once
|
|
210
|
+
@instance.send_push('/welcome/aboard', 'iZac')
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
it 'should queue the push if in offline mode and :offline_queueing enabled' do
|
|
214
|
+
@agent.should_receive(:options).and_return({:offline_queueing => true})
|
|
215
|
+
RightScale::Sender.new(@agent)
|
|
216
|
+
@instance = RightScale::Sender.instance
|
|
217
|
+
@instance.initialize_offline_queue
|
|
218
|
+
@broker.should_receive(:publish).never
|
|
219
|
+
@instance.enable_offline_mode
|
|
220
|
+
@instance.instance_variable_get(:@queueing_mode).should == :offline
|
|
221
|
+
@instance.send_push('/welcome/aboard', 'iZac')
|
|
222
|
+
@instance.instance_variable_get(:@queue).size.should == 1
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
it "should store the response handler if given" do
|
|
226
|
+
response_handler = lambda {}
|
|
227
|
+
flexmock(RightScale::AgentIdentity).should_receive(:generate).and_return('abc').once
|
|
228
|
+
@instance.send_push('/welcome/aboard', 'iZac', &response_handler)
|
|
229
|
+
@instance.pending_requests['abc'][:response_handler].should == response_handler
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
it "should store the request receive time if there is a response handler" do
|
|
233
|
+
response_handler = lambda {}
|
|
234
|
+
flexmock(RightScale::AgentIdentity).should_receive(:generate).and_return('abc').once
|
|
235
|
+
flexmock(Time).should_receive(:now).and_return(Time.at(1000000)).by_default
|
|
236
|
+
@instance.request_age.should be_nil
|
|
237
|
+
@instance.send_push('/welcome/aboard', 'iZac', &response_handler)
|
|
238
|
+
@instance.pending_requests['abc'][:receive_time].should == Time.at(1000000)
|
|
239
|
+
flexmock(Time).should_receive(:now).and_return(Time.at(1000100))
|
|
240
|
+
@instance.request_age.should == 100
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
describe "when making a send_persistent_push request" do
|
|
245
|
+
before(:each) do
|
|
246
|
+
@timer = flexmock("timer")
|
|
247
|
+
flexmock(EM::Timer).should_receive(:new).and_return(@timer)
|
|
248
|
+
@broker = flexmock("Broker", :subscribe => true, :publish => true).by_default
|
|
249
|
+
@agent = flexmock("Agent", :identity => "agent", :broker => @broker, :options => {}).by_default
|
|
250
|
+
RightScale::Sender.new(@agent)
|
|
251
|
+
@instance = RightScale::Sender.instance
|
|
252
|
+
@instance.initialize_offline_queue
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
it "should create a Push object" do
|
|
256
|
+
@broker.should_receive(:publish).with(hsh(:name => "request"), on do |push|
|
|
257
|
+
push.class.should == RightScale::Push
|
|
258
|
+
end, hsh(:persistent => true, :mandatory => true)).once
|
|
259
|
+
@instance.send_persistent_push('/welcome/aboard', 'iZac')
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
it "should set correct attributes on the push message" do
|
|
263
|
+
@broker.should_receive(:publish).with(hsh(:name => "request"), on do |push|
|
|
264
|
+
push.type.should == '/welcome/aboard'
|
|
265
|
+
push.token.should_not be_nil
|
|
266
|
+
push.persistent.should be_true
|
|
267
|
+
push.from.should == 'agent'
|
|
268
|
+
push.target.should be_nil
|
|
269
|
+
push.expires_at.should == 0
|
|
270
|
+
end, hsh(:persistent => true, :mandatory => true)).once
|
|
271
|
+
@instance.send_persistent_push('/welcome/aboard', 'iZac')
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
it "should default the target selector to any" do
|
|
275
|
+
@broker.should_receive(:publish).with(hsh(:name => "request"), on do |push|
|
|
276
|
+
push.tags.should == ['tag']
|
|
277
|
+
push.scope.should == {:account => 123}
|
|
278
|
+
end, hsh(:persistent => true, :mandatory => true)).once
|
|
279
|
+
@instance.send_persistent_push('/welcome/aboard', 'iZac', :tags => ['tag'], :scope => {:account => 123})
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
it "should store the response handler if given" do
|
|
283
|
+
response_handler = lambda {}
|
|
284
|
+
flexmock(RightScale::AgentIdentity).should_receive(:generate).and_return('abc').once
|
|
285
|
+
@instance.send_persistent_push('/welcome/aboard', 'iZac', &response_handler)
|
|
286
|
+
@instance.pending_requests['abc'][:response_handler].should == response_handler
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
it "should store the request receive time if there is a response handler" do
|
|
290
|
+
response_handler = lambda {}
|
|
291
|
+
flexmock(RightScale::AgentIdentity).should_receive(:generate).and_return('abc').once
|
|
292
|
+
flexmock(Time).should_receive(:now).and_return(Time.at(1000000)).by_default
|
|
293
|
+
@instance.request_age.should be_nil
|
|
294
|
+
@instance.send_persistent_push('/welcome/aboard', 'iZac', &response_handler)
|
|
295
|
+
@instance.pending_requests['abc'][:receive_time].should == Time.at(1000000)
|
|
296
|
+
flexmock(Time).should_receive(:now).and_return(Time.at(1000100))
|
|
297
|
+
@instance.request_age.should == 100
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
describe "when making a send_retryable_request request" do
|
|
302
|
+
before(:each) do
|
|
303
|
+
@timer = flexmock("timer")
|
|
304
|
+
flexmock(EM::Timer).should_receive(:new).and_return(@timer).by_default
|
|
305
|
+
flexmock(EM).should_receive(:next_tick).and_yield.by_default
|
|
306
|
+
@broker_id = "broker"
|
|
307
|
+
@broker_ids = [@broker_id]
|
|
308
|
+
@broker = flexmock("Broker", :subscribe => true, :publish => @broker_ids, :connected? => true,
|
|
309
|
+
:identity_parts => ["host", 123, 0, 0, nil]).by_default
|
|
310
|
+
@agent = flexmock("Agent", :identity => "agent", :broker => @broker).by_default
|
|
311
|
+
@agent.should_receive(:options).and_return({:ping_interval => 0, :time_to_live => 100}).by_default
|
|
312
|
+
RightScale::Sender.new(@agent)
|
|
313
|
+
@instance = RightScale::Sender.instance
|
|
314
|
+
@instance.initialize_offline_queue
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
it "should validate target" do
|
|
318
|
+
@broker.should_receive(:publish)
|
|
319
|
+
lambda { @instance.send_retryable_request('/foo/bar', nil) }.should be_true
|
|
320
|
+
lambda { @instance.send_retryable_request('/foo/bar', nil, "target") }.should be_true
|
|
321
|
+
lambda { @instance.send_retryable_request('/foo/bar', nil, {}) }.should be_true
|
|
322
|
+
lambda { @instance.send_retryable_request('/foo/bar', nil, :tags => "tags") }.should be_true
|
|
323
|
+
lambda { @instance.send_retryable_request('/foo/bar', nil, "tags" => "tags") }.should be_true
|
|
324
|
+
lambda { @instance.send_retryable_request('/foo/bar', nil, :tags => "tags", :scope => {:shard => 1}) }.should be_true
|
|
325
|
+
lambda { @instance.send_retryable_request('/foo/bar', nil, "scope" => {:shard => 1, "account" => 1}) }.should be_true
|
|
326
|
+
lambda { @instance.send_retryable_request('/foo/bar', nil, :scope => {:deployment => 1}) }.should be_true
|
|
327
|
+
lambda { @instance.send_retryable_request('/foo/bar', nil, :scope => {}) }.should be_true
|
|
328
|
+
lambda { @instance.send_retryable_request('/foo/bar', nil, :selector => :all) }.should raise_error(ArgumentError)
|
|
329
|
+
lambda { @instance.send_retryable_request('/foo/bar', nil, 1) }.should raise_error(ArgumentError)
|
|
330
|
+
lambda { @instance.send_retryable_request('/foo/bar', nil, []) }.should raise_error(ArgumentError)
|
|
331
|
+
lambda { @instance.send_retryable_request('/foo/bar', nil, :bogus => 1) }.should raise_error(ArgumentError)
|
|
332
|
+
lambda { @instance.send_retryable_request('/foo/bar', nil, :scope => 1) }.should raise_error(ArgumentError)
|
|
333
|
+
lambda { @instance.send_retryable_request('/foo/bar', nil, :scope => {:bogus => 1}) }.should raise_error(ArgumentError)
|
|
334
|
+
lambda { @instance.send_retryable_request('/foo/bar', nil, :selector => :bogus) }.should raise_error(ArgumentError)
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
it "should create a Request object" do
|
|
338
|
+
@broker.should_receive(:publish).with(hsh(:name => "request"), on do |request|
|
|
339
|
+
request.class.should == RightScale::Request
|
|
340
|
+
end, hsh(:persistent => false, :mandatory => true)).once
|
|
341
|
+
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|response|}
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
it "should process request in next tick to preserve pending request data integrity" do
|
|
345
|
+
flexmock(EM).should_receive(:next_tick).and_yield.once
|
|
346
|
+
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|response|}
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
it "should set correct attributes on the request message" do
|
|
350
|
+
flexmock(Time).should_receive(:now).and_return(Time.at(1000000))
|
|
351
|
+
@broker.should_receive(:publish).with(hsh(:name => "request"), on do |request|
|
|
352
|
+
request.type.should == '/welcome/aboard'
|
|
353
|
+
request.token.should_not be_nil
|
|
354
|
+
request.persistent.should be_false
|
|
355
|
+
request.from.should == 'agent'
|
|
356
|
+
request.target.should be_nil
|
|
357
|
+
request.expires_at.should == 1000100
|
|
358
|
+
end, hsh(:persistent => false, :mandatory => true)).once
|
|
359
|
+
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|response|}
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
it "should disable time-to-live if disabled in configuration" do
|
|
363
|
+
@agent.should_receive(:options).and_return({:ping_interval => 0, :time_to_live => 0})
|
|
364
|
+
RightScale::Sender.new(@agent)
|
|
365
|
+
@instance = RightScale::Sender.instance
|
|
366
|
+
@instance.initialize_offline_queue
|
|
367
|
+
flexmock(Time).should_receive(:now).and_return(Time.at(1000000))
|
|
368
|
+
@broker.should_receive(:publish).with(hsh(:name => "request"), on do |request|
|
|
369
|
+
request.expires_at.should == 0
|
|
370
|
+
end, hsh(:persistent => false, :mandatory => true)).once
|
|
371
|
+
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|response|}
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
it "should set the correct target if specified" do
|
|
375
|
+
@broker.should_receive(:publish).with(hsh(:name => "request"), on do |request|
|
|
376
|
+
request.target.should == 'my-target'
|
|
377
|
+
end, hsh(:persistent => false, :mandatory => true)).once
|
|
378
|
+
@instance.send_retryable_request('/welcome/aboard', 'iZac', 'my-target') {|response|}
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
it "should set the correct target selectors if specified" do
|
|
382
|
+
@broker.should_receive(:publish).with(hsh(:name => "request"), on do |request|
|
|
383
|
+
request.tags.should == ['tag']
|
|
384
|
+
request.selector.should == :any
|
|
385
|
+
request.scope.should == {:account => 123}
|
|
386
|
+
end, hsh(:persistent => false, :mandatory => true)).once
|
|
387
|
+
@instance.send_retryable_request('/welcome/aboard', 'iZac', :tags => ['tag'], :scope => {:account => 123})
|
|
388
|
+
end
|
|
389
|
+
|
|
390
|
+
it "should set up for retrying the request if necessary by default" do
|
|
391
|
+
flexmock(@instance).should_receive(:publish_with_timeout_retry).once
|
|
392
|
+
@instance.send_retryable_request('/welcome/aboard', 'iZac', 'my-target') {|response|}
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
it "should store the response handler" do
|
|
396
|
+
response_handler = lambda {}
|
|
397
|
+
flexmock(RightScale::AgentIdentity).should_receive(:generate).and_return('abc').once
|
|
398
|
+
@instance.send_retryable_request('/welcome/aboard', 'iZac', &response_handler)
|
|
399
|
+
@instance.pending_requests['abc'][:response_handler].should == response_handler
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
it "should store the request receive time" do
|
|
403
|
+
flexmock(RightScale::AgentIdentity).should_receive(:generate).and_return('abc').once
|
|
404
|
+
flexmock(Time).should_receive(:now).and_return(Time.at(1000000)).by_default
|
|
405
|
+
@instance.request_age.should be_nil
|
|
406
|
+
@instance.send_retryable_request('/welcome/aboard', 'iZac')
|
|
407
|
+
@instance.pending_requests['abc'][:receive_time].should == Time.at(1000000)
|
|
408
|
+
flexmock(Time).should_receive(:now).and_return(Time.at(1000100))
|
|
409
|
+
@instance.request_age.should == 100
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
it 'should queue the request if in offline mode and :offline_queueing enabled' do
|
|
413
|
+
@agent.should_receive(:options).and_return({:offline_queueing => true})
|
|
414
|
+
RightScale::Sender.new(@agent)
|
|
415
|
+
@instance = RightScale::Sender.instance
|
|
416
|
+
@instance.initialize_offline_queue
|
|
417
|
+
@broker.should_receive(:publish).never
|
|
418
|
+
@instance.enable_offline_mode
|
|
419
|
+
@instance.instance_variable_get(:@queueing_mode).should == :offline
|
|
420
|
+
@instance.send_retryable_request('/welcome/aboard', 'iZac')
|
|
421
|
+
@instance.instance_variable_get(:@queue).size.should == 1
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
it "should dump the pending requests" do
|
|
425
|
+
flexmock(RightScale::AgentIdentity).should_receive(:generate).and_return('abc').once
|
|
426
|
+
flexmock(Time).should_receive(:now).and_return(Time.at(1000000))
|
|
427
|
+
@instance.send_retryable_request('/welcome/aboard', 'iZac')
|
|
428
|
+
@instance.dump_requests.should == ["#{Time.at(1000000).localtime} <abc>"]
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
describe "with retry" do
|
|
432
|
+
it "should convert value to nil if 0" do
|
|
433
|
+
@instance.__send__(:nil_if_zero, 0).should == nil
|
|
434
|
+
end
|
|
435
|
+
|
|
436
|
+
it "should not convert value to nil if not 0" do
|
|
437
|
+
@instance.__send__(:nil_if_zero, 1).should == 1
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
it "should leave value as nil if nil" do
|
|
441
|
+
@instance.__send__(:nil_if_zero, nil).should == nil
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
it "should not setup for retry if retry_timeout nil" do
|
|
445
|
+
flexmock(EM).should_receive(:add_timer).never
|
|
446
|
+
@agent.should_receive(:options).and_return({:retry_timeout => nil})
|
|
447
|
+
RightScale::Sender.new(@agent)
|
|
448
|
+
@instance = RightScale::Sender.instance
|
|
449
|
+
@broker.should_receive(:publish).once
|
|
450
|
+
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|response|}
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
it "should not setup for retry if retry_interval nil" do
|
|
454
|
+
flexmock(EM).should_receive(:add_timer).never
|
|
455
|
+
@agent.should_receive(:options).and_return({:retry_interval => nil})
|
|
456
|
+
RightScale::Sender.new(@agent)
|
|
457
|
+
@instance = RightScale::Sender.instance
|
|
458
|
+
@broker.should_receive(:publish).once
|
|
459
|
+
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|response|}
|
|
460
|
+
end
|
|
461
|
+
|
|
462
|
+
it "should not setup for retry if publish failed" do
|
|
463
|
+
flexmock(EM).should_receive(:add_timer).never
|
|
464
|
+
@agent.should_receive(:options).and_return({:retry_timeout => 60, :retry_interval => 60})
|
|
465
|
+
RightScale::Sender.new(@agent)
|
|
466
|
+
@instance = RightScale::Sender.instance
|
|
467
|
+
@broker.should_receive(:publish).and_return([]).once
|
|
468
|
+
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|response|}
|
|
469
|
+
end
|
|
470
|
+
|
|
471
|
+
it "should setup for retry if retry_timeout and retry_interval not nil and publish successful" do
|
|
472
|
+
flexmock(EM).should_receive(:add_timer).with(60, any).once
|
|
473
|
+
@agent.should_receive(:options).and_return({:retry_timeout => 60, :retry_interval => 60})
|
|
474
|
+
RightScale::Sender.new(@agent)
|
|
475
|
+
@instance = RightScale::Sender.instance
|
|
476
|
+
@broker.should_receive(:publish).and_return(@broker_ids).once
|
|
477
|
+
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|response|}
|
|
478
|
+
end
|
|
479
|
+
|
|
480
|
+
it "should adjust retry interval by recent request duration" do
|
|
481
|
+
|
|
482
|
+
end
|
|
483
|
+
|
|
484
|
+
it "should succeed after retrying once" do
|
|
485
|
+
EM.run do
|
|
486
|
+
token = 'abc'
|
|
487
|
+
result = RightScale::OperationResult.non_delivery(RightScale::OperationResult::RETRY_TIMEOUT)
|
|
488
|
+
flexmock(RightScale::AgentIdentity).should_receive(:generate).and_return(token).twice
|
|
489
|
+
@agent.should_receive(:options).and_return({:retry_timeout => 0.3, :retry_interval => 0.1})
|
|
490
|
+
RightScale::Sender.new(@agent)
|
|
491
|
+
@instance = RightScale::Sender.instance
|
|
492
|
+
flexmock(@instance).should_receive(:check_connection).once
|
|
493
|
+
@broker.should_receive(:publish).and_return(@broker_ids).twice
|
|
494
|
+
@instance.send_retryable_request('/welcome/aboard', 'iZac') do |response|
|
|
495
|
+
result = RightScale::OperationResult.from_results(response)
|
|
496
|
+
end
|
|
497
|
+
EM.add_timer(0.15) do
|
|
498
|
+
@instance.pending_requests.empty?.should be_false
|
|
499
|
+
@instance.handle_response(RightScale::Result.new(token, nil, {'from' => RightScale::OperationResult.success}, nil))
|
|
500
|
+
end
|
|
501
|
+
EM.add_timer(0.3) do
|
|
502
|
+
EM.stop
|
|
503
|
+
result.success?.should be_true
|
|
504
|
+
@instance.pending_requests.empty?.should be_true
|
|
505
|
+
end
|
|
506
|
+
end
|
|
507
|
+
end
|
|
508
|
+
|
|
509
|
+
it "should timeout after retrying twice" do
|
|
510
|
+
pending 'Too difficult to get timing right for Windows' if RightScale::Platform.windows?
|
|
511
|
+
EM.run do
|
|
512
|
+
result = RightScale::OperationResult.success
|
|
513
|
+
@log.should_receive(:warning).once
|
|
514
|
+
@agent.should_receive(:options).and_return({:retry_timeout => 0.6, :retry_interval => 0.1})
|
|
515
|
+
RightScale::Sender.new(@agent)
|
|
516
|
+
@instance = RightScale::Sender.instance
|
|
517
|
+
flexmock(@instance).should_receive(:check_connection).once
|
|
518
|
+
@broker.should_receive(:publish).and_return(@broker_ids).times(3)
|
|
519
|
+
@instance.send_retryable_request('/welcome/aboard', 'iZac') do |response|
|
|
520
|
+
result = RightScale::OperationResult.from_results(response)
|
|
521
|
+
end
|
|
522
|
+
@instance.pending_requests.empty?.should be_false
|
|
523
|
+
EM.add_timer(1) do
|
|
524
|
+
EM.stop
|
|
525
|
+
result.non_delivery?.should be_true
|
|
526
|
+
result.content.should == RightScale::OperationResult::RETRY_TIMEOUT
|
|
527
|
+
@instance.pending_requests.empty?.should be_true
|
|
528
|
+
end
|
|
529
|
+
end
|
|
530
|
+
end
|
|
531
|
+
|
|
532
|
+
it "should retry with same request expires_at value" do
|
|
533
|
+
EM.run do
|
|
534
|
+
token = 'abc'
|
|
535
|
+
expires_at = nil
|
|
536
|
+
flexmock(RightScale::AgentIdentity).should_receive(:generate).and_return(token).twice
|
|
537
|
+
@agent.should_receive(:options).and_return({:retry_timeout => 0.5, :retry_interval => 0.1})
|
|
538
|
+
RightScale::Sender.new(@agent)
|
|
539
|
+
@instance = RightScale::Sender.instance
|
|
540
|
+
flexmock(@instance).should_receive(:check_connection).once
|
|
541
|
+
@broker.should_receive(:publish).with(hsh(:name => "request"), on do |request|
|
|
542
|
+
request.expires_at.should == (expires_at ||= request.expires_at)
|
|
543
|
+
end, hsh(:persistent => false, :mandatory => true)).and_return(@broker_ids).twice
|
|
544
|
+
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|response|}
|
|
545
|
+
EM.add_timer(0.2) { EM.stop }
|
|
546
|
+
end
|
|
547
|
+
end
|
|
548
|
+
|
|
549
|
+
describe "and checking connection status" do
|
|
550
|
+
before(:each) do
|
|
551
|
+
@broker_id = "broker"
|
|
552
|
+
@broker_ids = [@broker_id]
|
|
553
|
+
end
|
|
554
|
+
|
|
555
|
+
it "should not check connection if check already in progress" do
|
|
556
|
+
flexmock(EM::Timer).should_receive(:new).and_return(@timer).never
|
|
557
|
+
@instance.pending_ping = true
|
|
558
|
+
flexmock(@instance).should_receive(:publish).never
|
|
559
|
+
@instance.__send__(:check_connection, @broker_ids)
|
|
560
|
+
end
|
|
561
|
+
|
|
562
|
+
it "should publish ping to mapper" do
|
|
563
|
+
flexmock(EM::Timer).should_receive(:new).and_return(@timer).once
|
|
564
|
+
flexmock(@instance).should_receive(:publish).with(on { |request| request.type.should == "/mapper/ping" },
|
|
565
|
+
@broker_ids).and_return(@broker_ids).once
|
|
566
|
+
@instance.__send__(:check_connection, @broker_id)
|
|
567
|
+
@instance.pending_requests.size.should == 1
|
|
568
|
+
end
|
|
569
|
+
|
|
570
|
+
it "should not make any connection changes if receive ping response" do
|
|
571
|
+
flexmock(RightScale::AgentIdentity).should_receive(:generate).and_return('abc').once
|
|
572
|
+
@timer.should_receive(:cancel).once
|
|
573
|
+
flexmock(EM::Timer).should_receive(:new).and_return(@timer).once
|
|
574
|
+
flexmock(@instance).should_receive(:publish).and_return(@broker_ids).once
|
|
575
|
+
@instance.__send__(:check_connection, @broker_id)
|
|
576
|
+
@instance.pending_ping.should == @timer
|
|
577
|
+
@instance.pending_requests.size.should == 1
|
|
578
|
+
@instance.pending_requests['abc'][:response_handler].call(nil)
|
|
579
|
+
@instance.pending_ping.should == nil
|
|
580
|
+
end
|
|
581
|
+
|
|
582
|
+
it "should try to reconnect if ping times out" do
|
|
583
|
+
@log.should_receive(:warning).once
|
|
584
|
+
flexmock(EM::Timer).should_receive(:new).and_yield.once
|
|
585
|
+
flexmock(@agent).should_receive(:connect).once
|
|
586
|
+
@instance.__send__(:check_connection, @broker_id)
|
|
587
|
+
@instance.pending_ping.should == nil
|
|
588
|
+
end
|
|
589
|
+
|
|
590
|
+
it "should log error if attempt to reconnect fails" do
|
|
591
|
+
@log.should_receive(:warning).once
|
|
592
|
+
@log.should_receive(:error).with(/Failed to reconnect/, Exception, :trace).once
|
|
593
|
+
flexmock(@agent).should_receive(:connect).and_raise(Exception)
|
|
594
|
+
flexmock(EM::Timer).should_receive(:new).and_yield.once
|
|
595
|
+
@instance.__send__(:check_connection, @broker_id)
|
|
596
|
+
end
|
|
597
|
+
end
|
|
598
|
+
end
|
|
599
|
+
end
|
|
600
|
+
|
|
601
|
+
describe "when making a send_persistent_request" do
|
|
602
|
+
before(:each) do
|
|
603
|
+
@timer = flexmock("timer")
|
|
604
|
+
flexmock(EM::Timer).should_receive(:new).and_return(@timer).by_default
|
|
605
|
+
flexmock(EM).should_receive(:next_tick).and_yield.by_default
|
|
606
|
+
@broker_id = "broker"
|
|
607
|
+
@broker_ids = [@broker_id]
|
|
608
|
+
@broker = flexmock("Broker", :subscribe => true, :publish => @broker_ids, :connected? => true,
|
|
609
|
+
:identity_parts => ["host", 123, 0, 0, nil]).by_default
|
|
610
|
+
@agent = flexmock("Agent", :identity => "agent", :broker => @broker,
|
|
611
|
+
:options => {:ping_interval => 0, :time_to_live => 100}).by_default
|
|
612
|
+
RightScale::Sender.new(@agent)
|
|
613
|
+
@instance = RightScale::Sender.instance
|
|
614
|
+
@instance.initialize_offline_queue
|
|
615
|
+
end
|
|
616
|
+
|
|
617
|
+
it "should create a Request object" do
|
|
618
|
+
@broker.should_receive(:publish).with(hsh(:name => "request"), on do |request|
|
|
619
|
+
request.class.should == RightScale::Request
|
|
620
|
+
end, hsh(:persistent => true, :mandatory => true)).once
|
|
621
|
+
@instance.send_persistent_request('/welcome/aboard', 'iZac') {|response|}
|
|
622
|
+
end
|
|
623
|
+
|
|
624
|
+
it "should set correct attributes on the request message" do
|
|
625
|
+
flexmock(Time).should_receive(:now).and_return(Time.at(1000000))
|
|
626
|
+
@broker.should_receive(:publish).with(hsh(:name => "request"), on do |request|
|
|
627
|
+
request.type.should == '/welcome/aboard'
|
|
628
|
+
request.token.should_not be_nil
|
|
629
|
+
request.persistent.should be_true
|
|
630
|
+
request.from.should == 'agent'
|
|
631
|
+
request.target.should be_nil
|
|
632
|
+
request.expires_at.should == 0
|
|
633
|
+
end, hsh(:persistent => true, :mandatory => true)).once
|
|
634
|
+
@instance.send_persistent_request('/welcome/aboard', 'iZac') {|response|}
|
|
635
|
+
end
|
|
636
|
+
|
|
637
|
+
it "should set the correct target if specified" do
|
|
638
|
+
@broker.should_receive(:publish).with(hsh(:name => "request"), on do |request|
|
|
639
|
+
request.target.should == 'my-target'
|
|
640
|
+
end, hsh(:persistent => true, :mandatory => true)).once
|
|
641
|
+
@instance.send_persistent_request('/welcome/aboard', 'iZac', 'my-target') {|response|}
|
|
642
|
+
end
|
|
643
|
+
|
|
644
|
+
it "should set the correct target selectors if specified" do
|
|
645
|
+
@broker.should_receive(:publish).with(hsh(:name => "request"), on do |request|
|
|
646
|
+
request.tags.should == ['tag']
|
|
647
|
+
request.selector.should == :any
|
|
648
|
+
request.scope.should == {:account => 123}
|
|
649
|
+
end, hsh(:persistent => true, :mandatory => true)).once
|
|
650
|
+
@instance.send_persistent_request('/welcome/aboard', 'iZac', :tags => ['tag'], :scope => {:account => 123})
|
|
651
|
+
end
|
|
652
|
+
|
|
653
|
+
it "should not set up for retrying the request" do
|
|
654
|
+
flexmock(@instance).should_receive(:publish_with_timeout_retry).never
|
|
655
|
+
@instance.send_persistent_request('/welcome/aboard', 'iZac', 'my-target') {|response|}
|
|
656
|
+
end
|
|
657
|
+
end
|
|
658
|
+
|
|
659
|
+
describe "when handling a response" do
|
|
660
|
+
before(:each) do
|
|
661
|
+
flexmock(EM).should_receive(:next_tick).and_yield.by_default
|
|
662
|
+
flexmock(EM).should_receive(:defer).and_yield.by_default
|
|
663
|
+
@broker = flexmock("Broker", :subscribe => true, :publish => ["broker"], :connected? => true,
|
|
664
|
+
:identity_parts => ["host", 123, 0, 0, nil]).by_default
|
|
665
|
+
@agent = flexmock("Agent", :identity => "agent", :broker => @broker, :options => {:ping_interval => 0}).by_default
|
|
666
|
+
RightScale::Sender.new(@agent)
|
|
667
|
+
@instance = RightScale::Sender.instance
|
|
668
|
+
flexmock(RightScale::AgentIdentity, :generate => 'token1')
|
|
669
|
+
end
|
|
670
|
+
|
|
671
|
+
it "should deliver the response" do
|
|
672
|
+
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|_|}
|
|
673
|
+
response = RightScale::Result.new('token1', 'to', RightScale::OperationResult.success, 'target1')
|
|
674
|
+
flexmock(@instance).should_receive(:deliver).with(response, Hash).once
|
|
675
|
+
@instance.handle_response(response)
|
|
676
|
+
end
|
|
677
|
+
|
|
678
|
+
it "should not deliver TARGET_NOT_CONNECTED and TTL_EXPIRATION responses for send_retryable_request" do
|
|
679
|
+
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|_|}
|
|
680
|
+
flexmock(@instance).should_receive(:deliver).never
|
|
681
|
+
non_delivery = RightScale::OperationResult.non_delivery(RightScale::OperationResult::TARGET_NOT_CONNECTED)
|
|
682
|
+
response = RightScale::Result.new('token1', 'to', non_delivery, 'target1')
|
|
683
|
+
@instance.handle_response(response)
|
|
684
|
+
non_delivery = RightScale::OperationResult.non_delivery(RightScale::OperationResult::TTL_EXPIRATION)
|
|
685
|
+
response = RightScale::Result.new('token1', 'to', non_delivery, 'target1')
|
|
686
|
+
@instance.handle_response(response)
|
|
687
|
+
end
|
|
688
|
+
|
|
689
|
+
it "should record non-delivery regardless of whether there is a response handler" do
|
|
690
|
+
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|_|}
|
|
691
|
+
non_delivery = RightScale::OperationResult.non_delivery(RightScale::OperationResult::NO_ROUTE_TO_TARGET)
|
|
692
|
+
response = RightScale::Result.new('token1', 'to', non_delivery, 'target1')
|
|
693
|
+
@instance.handle_response(response)
|
|
694
|
+
@instance.instance_variable_get(:@non_deliveries).total.should == 1
|
|
695
|
+
end
|
|
696
|
+
|
|
697
|
+
it "should log non-delivery if there is no response handler" do
|
|
698
|
+
@log.should_receive(:info).with(/Non-delivery of/).once
|
|
699
|
+
@instance.send_push('/welcome/aboard', 'iZac')
|
|
700
|
+
non_delivery = RightScale::OperationResult.non_delivery(RightScale::OperationResult::NO_ROUTE_TO_TARGET)
|
|
701
|
+
response = RightScale::Result.new('token1', 'to', non_delivery, 'target1')
|
|
702
|
+
@instance.handle_response(response)
|
|
703
|
+
end
|
|
704
|
+
|
|
705
|
+
it "should log a debug message if request no longer pending" do
|
|
706
|
+
@log.should_receive(:debug).with(/No pending request for response/).once
|
|
707
|
+
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|_|}
|
|
708
|
+
@instance.pending_requests['token1'].should_not be_nil
|
|
709
|
+
@instance.pending_requests['token2'].should be_nil
|
|
710
|
+
response = RightScale::Result.new('token2', 'to', RightScale::OperationResult.success, 'target1')
|
|
711
|
+
@instance.handle_response(response)
|
|
712
|
+
end
|
|
713
|
+
end
|
|
714
|
+
|
|
715
|
+
describe "when delivering a response" do
|
|
716
|
+
before(:each) do
|
|
717
|
+
flexmock(EM).should_receive(:next_tick).and_yield.by_default
|
|
718
|
+
flexmock(EM).should_receive(:defer).and_yield.by_default
|
|
719
|
+
@broker = flexmock("Broker", :subscribe => true, :publish => ["broker"], :connected? => true,
|
|
720
|
+
:identity_parts => ["host", 123, 0, 0, nil]).by_default
|
|
721
|
+
@agent = flexmock("Agent", :identity => "agent", :broker => @broker, :options => {:ping_interval => 0}).by_default
|
|
722
|
+
RightScale::Sender.new(@agent)
|
|
723
|
+
@instance = RightScale::Sender.instance
|
|
724
|
+
flexmock(RightScale::AgentIdentity, :generate => 'token1')
|
|
725
|
+
end
|
|
726
|
+
|
|
727
|
+
it "should delete all associated pending requests" do
|
|
728
|
+
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|_|}
|
|
729
|
+
@instance.pending_requests['token1'].should_not be_nil
|
|
730
|
+
response = RightScale::Result.new('token1', 'to', RightScale::OperationResult.success, 'target1')
|
|
731
|
+
@instance.handle_response(response)
|
|
732
|
+
@instance.pending_requests['token1'].should be_nil
|
|
733
|
+
end
|
|
734
|
+
|
|
735
|
+
it "should delete any associated retry requests" do
|
|
736
|
+
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|_|}
|
|
737
|
+
@instance.pending_requests['token1'].should_not be_nil
|
|
738
|
+
@instance.pending_requests['token2'] = @instance.pending_requests['token1'].dup
|
|
739
|
+
@instance.pending_requests['token2'][:retry_parent] = 'token1'
|
|
740
|
+
response = RightScale::Result.new('token2', 'to', RightScale::OperationResult.success, 'target1')
|
|
741
|
+
@instance.handle_response(response)
|
|
742
|
+
@instance.pending_requests['token1'].should be_nil
|
|
743
|
+
@instance.pending_requests['token2'].should be_nil
|
|
744
|
+
end
|
|
745
|
+
|
|
746
|
+
it "should call the response handler" do
|
|
747
|
+
called = 0
|
|
748
|
+
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|response| called += 1}
|
|
749
|
+
response = RightScale::Result.new('token1', 'to', RightScale::OperationResult.success, 'target1')
|
|
750
|
+
@instance.handle_response(response)
|
|
751
|
+
called.should == 1
|
|
752
|
+
end
|
|
753
|
+
|
|
754
|
+
it "should defer the response handler call if not single threaded" do
|
|
755
|
+
@agent.should_receive(:options).and_return({:single_threaded => false})
|
|
756
|
+
RightScale::Sender.new(@agent)
|
|
757
|
+
@instance = RightScale::Sender.instance
|
|
758
|
+
called = 0
|
|
759
|
+
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|response| called += 1}
|
|
760
|
+
response = RightScale::Result.new('token1', 'to', RightScale::OperationResult.success, 'target1')
|
|
761
|
+
flexmock(EM).should_receive(:defer).and_yield.once
|
|
762
|
+
flexmock(EM).should_receive(:next_tick).never
|
|
763
|
+
@instance.handle_response(response)
|
|
764
|
+
called.should == 1
|
|
765
|
+
end
|
|
766
|
+
|
|
767
|
+
it "should not defer the response handler call if single threaded" do
|
|
768
|
+
@agent.should_receive(:options).and_return({:single_threaded => true})
|
|
769
|
+
RightScale::Sender.new(@agent)
|
|
770
|
+
@instance = RightScale::Sender.instance
|
|
771
|
+
called = 0
|
|
772
|
+
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|response| called += 1}
|
|
773
|
+
response = RightScale::Result.new('token1', 'to', RightScale::OperationResult.success, 'target1')
|
|
774
|
+
flexmock(EM).should_receive(:next_tick).and_yield.once
|
|
775
|
+
flexmock(EM).should_receive(:defer).never
|
|
776
|
+
@instance.handle_response(response)
|
|
777
|
+
called.should == 1
|
|
778
|
+
end
|
|
779
|
+
|
|
780
|
+
it "should log an error if the response handler raises an exception but still delete pending request" do
|
|
781
|
+
@agent.should_receive(:options).and_return({:single_threaded => true})
|
|
782
|
+
@log.should_receive(:error).with(/Failed processing response/, Exception, :trace).once
|
|
783
|
+
@instance.send_retryable_request('/welcome/aboard', 'iZac') {|_| raise Exception}
|
|
784
|
+
@instance.pending_requests['token1'].should_not be_nil
|
|
785
|
+
response = RightScale::Result.new('token1', 'to', RightScale::OperationResult.success, 'target1')
|
|
786
|
+
@instance.handle_response(response)
|
|
787
|
+
@instance.pending_requests['token1'].should be_nil
|
|
788
|
+
end
|
|
789
|
+
end
|
|
790
|
+
|
|
791
|
+
describe "when use offline queueing" do
|
|
792
|
+
before(:each) do
|
|
793
|
+
@broker = flexmock("Broker", :subscribe => true, :publish => ["broker"], :connected? => true,
|
|
794
|
+
:identity_parts => ["host", 123, 0, 0, nil]).by_default
|
|
795
|
+
@agent = flexmock("Agent", :identity => "agent", :broker => @broker, :options => {:offline_queueing => true}).by_default
|
|
796
|
+
RightScale::Sender.new(@agent)
|
|
797
|
+
@instance = RightScale::Sender.instance
|
|
798
|
+
@instance.initialize_offline_queue
|
|
799
|
+
end
|
|
800
|
+
|
|
801
|
+
it 'should vote for restart after the maximum number of queued requests is reached' do
|
|
802
|
+
@instance.instance_variable_get(:@restart_vote_count).should == 0
|
|
803
|
+
EM.run do
|
|
804
|
+
@instance.enable_offline_mode
|
|
805
|
+
@instance.instance_variable_set(:@queue, ('*' * (RightScale::Sender::MAX_QUEUED_REQUESTS - 1)).split(//))
|
|
806
|
+
@instance.send_push('/dummy', 'payload')
|
|
807
|
+
EM.next_tick { EM.stop }
|
|
808
|
+
end
|
|
809
|
+
@instance.instance_variable_get(:@queue).size.should == RightScale::Sender::MAX_QUEUED_REQUESTS
|
|
810
|
+
@instance.instance_variable_get(:@restart_vote_count).should == 1
|
|
811
|
+
end
|
|
812
|
+
|
|
813
|
+
it 'should vote for restart after the threshold delay is reached' do
|
|
814
|
+
old_vote_delay = RightScale::Sender::RESTART_VOTE_DELAY
|
|
815
|
+
begin
|
|
816
|
+
RightScale::Sender.const_set(:RESTART_VOTE_DELAY, 0.1)
|
|
817
|
+
@instance.instance_variable_get(:@restart_vote_count).should == 0
|
|
818
|
+
EM.run do
|
|
819
|
+
@instance.enable_offline_mode
|
|
820
|
+
@instance.send_push('/dummy', 'payload')
|
|
821
|
+
EM.add_timer(0.5) { EM.stop }
|
|
822
|
+
end
|
|
823
|
+
@instance.instance_variable_get(:@restart_vote_count).should == 1
|
|
824
|
+
ensure
|
|
825
|
+
RightScale::Sender.const_set(:RESTART_VOTE_DELAY, old_vote_delay)
|
|
826
|
+
end
|
|
827
|
+
end
|
|
828
|
+
|
|
829
|
+
it 'should not flush queued requests until back online' do
|
|
830
|
+
old_flush_delay = RightScale::Sender::MAX_QUEUE_FLUSH_DELAY
|
|
831
|
+
begin
|
|
832
|
+
RightScale::Sender.const_set(:MAX_QUEUE_FLUSH_DELAY, 0.1)
|
|
833
|
+
EM.run do
|
|
834
|
+
@instance.enable_offline_mode
|
|
835
|
+
@instance.send_push('/dummy', 'payload')
|
|
836
|
+
EM.add_timer(0.5) { EM.stop }
|
|
837
|
+
end
|
|
838
|
+
ensure
|
|
839
|
+
RightScale::Sender.const_set(:MAX_QUEUE_FLUSH_DELAY, old_flush_delay)
|
|
840
|
+
end
|
|
841
|
+
end
|
|
842
|
+
|
|
843
|
+
it 'should flush queued requests once back online' do
|
|
844
|
+
old_flush_delay = RightScale::Sender::MAX_QUEUE_FLUSH_DELAY
|
|
845
|
+
@broker.should_receive(:publish).once.and_return { EM.stop }
|
|
846
|
+
begin
|
|
847
|
+
RightScale::Sender.const_set(:MAX_QUEUE_FLUSH_DELAY, 0.1)
|
|
848
|
+
EM.run do
|
|
849
|
+
@instance.enable_offline_mode
|
|
850
|
+
@instance.send_push('/dummy', 'payload')
|
|
851
|
+
@instance.disable_offline_mode
|
|
852
|
+
EM.add_timer(1) { EM.stop }
|
|
853
|
+
end
|
|
854
|
+
ensure
|
|
855
|
+
RightScale::Sender.const_set(:MAX_QUEUE_FLUSH_DELAY, old_flush_delay)
|
|
856
|
+
end
|
|
857
|
+
end
|
|
858
|
+
|
|
859
|
+
it 'should stop flushing when going back to offline mode' do
|
|
860
|
+
old_flush_delay = RightScale::Sender::MAX_QUEUE_FLUSH_DELAY
|
|
861
|
+
begin
|
|
862
|
+
RightScale::Sender.const_set(:MAX_QUEUE_FLUSH_DELAY, 0.1)
|
|
863
|
+
EM.run do
|
|
864
|
+
@instance.enable_offline_mode
|
|
865
|
+
@instance.send_push('/dummy', 'payload')
|
|
866
|
+
@instance.disable_offline_mode
|
|
867
|
+
@instance.instance_variable_get(:@flushing_queue).should be_true
|
|
868
|
+
@instance.instance_variable_get(:@stop_flushing_queue).should be_false
|
|
869
|
+
@instance.instance_variable_get(:@queueing_mode).should == :offline
|
|
870
|
+
@instance.enable_offline_mode
|
|
871
|
+
@instance.instance_variable_get(:@flushing_queue).should be_true
|
|
872
|
+
@instance.instance_variable_get(:@stop_flushing_queue).should be_true
|
|
873
|
+
@instance.instance_variable_get(:@queueing_mode).should == :offline
|
|
874
|
+
EM.add_timer(1) do
|
|
875
|
+
@instance.instance_variable_get(:@flushing_queue).should be_false
|
|
876
|
+
@instance.instance_variable_get(:@stop_flushing_queue).should be_false
|
|
877
|
+
@instance.instance_variable_get(:@queueing_mode).should == :offline
|
|
878
|
+
EM.stop
|
|
879
|
+
end
|
|
880
|
+
end
|
|
881
|
+
ensure
|
|
882
|
+
RightScale::Sender.const_set(:MAX_QUEUE_FLUSH_DELAY, old_flush_delay)
|
|
883
|
+
end
|
|
884
|
+
end
|
|
885
|
+
end
|
|
886
|
+
|
|
887
|
+
end
|