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.
Files changed (147) hide show
  1. data/LICENSE +20 -0
  2. data/README.rdoc +78 -0
  3. data/Rakefile +86 -0
  4. data/lib/right_agent.rb +66 -0
  5. data/lib/right_agent/actor.rb +163 -0
  6. data/lib/right_agent/actor_registry.rb +76 -0
  7. data/lib/right_agent/actors/agent_manager.rb +189 -0
  8. data/lib/right_agent/agent.rb +735 -0
  9. data/lib/right_agent/agent_config.rb +403 -0
  10. data/lib/right_agent/agent_identity.rb +209 -0
  11. data/lib/right_agent/agent_tags_manager.rb +213 -0
  12. data/lib/right_agent/audit_formatter.rb +107 -0
  13. data/lib/right_agent/broker_client.rb +683 -0
  14. data/lib/right_agent/command.rb +30 -0
  15. data/lib/right_agent/command/agent_manager_commands.rb +134 -0
  16. data/lib/right_agent/command/command_client.rb +136 -0
  17. data/lib/right_agent/command/command_constants.rb +42 -0
  18. data/lib/right_agent/command/command_io.rb +128 -0
  19. data/lib/right_agent/command/command_parser.rb +87 -0
  20. data/lib/right_agent/command/command_runner.rb +105 -0
  21. data/lib/right_agent/command/command_serializer.rb +63 -0
  22. data/lib/right_agent/console.rb +65 -0
  23. data/lib/right_agent/core_payload_types.rb +42 -0
  24. data/lib/right_agent/core_payload_types/cookbook.rb +61 -0
  25. data/lib/right_agent/core_payload_types/cookbook_position.rb +46 -0
  26. data/lib/right_agent/core_payload_types/cookbook_repository.rb +116 -0
  27. data/lib/right_agent/core_payload_types/cookbook_sequence.rb +70 -0
  28. data/lib/right_agent/core_payload_types/dev_repositories.rb +90 -0
  29. data/lib/right_agent/core_payload_types/event_categories.rb +38 -0
  30. data/lib/right_agent/core_payload_types/executable_bundle.rb +138 -0
  31. data/lib/right_agent/core_payload_types/login_policy.rb +72 -0
  32. data/lib/right_agent/core_payload_types/login_user.rb +62 -0
  33. data/lib/right_agent/core_payload_types/planned_volume.rb +94 -0
  34. data/lib/right_agent/core_payload_types/recipe_instantiation.rb +60 -0
  35. data/lib/right_agent/core_payload_types/repositories_bundle.rb +50 -0
  36. data/lib/right_agent/core_payload_types/right_script_attachment.rb +95 -0
  37. data/lib/right_agent/core_payload_types/right_script_instantiation.rb +73 -0
  38. data/lib/right_agent/core_payload_types/secure_document.rb +66 -0
  39. data/lib/right_agent/core_payload_types/secure_document_location.rb +63 -0
  40. data/lib/right_agent/core_payload_types/software_repository_instantiation.rb +61 -0
  41. data/lib/right_agent/daemonize.rb +35 -0
  42. data/lib/right_agent/dispatcher.rb +348 -0
  43. data/lib/right_agent/enrollment_result.rb +217 -0
  44. data/lib/right_agent/exceptions.rb +30 -0
  45. data/lib/right_agent/ha_broker_client.rb +1278 -0
  46. data/lib/right_agent/idempotent_request.rb +140 -0
  47. data/lib/right_agent/log.rb +418 -0
  48. data/lib/right_agent/monkey_patches.rb +29 -0
  49. data/lib/right_agent/monkey_patches/amqp_patch.rb +274 -0
  50. data/lib/right_agent/monkey_patches/ruby_patch.rb +49 -0
  51. data/lib/right_agent/monkey_patches/ruby_patch/array_patch.rb +29 -0
  52. data/lib/right_agent/monkey_patches/ruby_patch/darwin_patch.rb +24 -0
  53. data/lib/right_agent/monkey_patches/ruby_patch/linux_patch.rb +24 -0
  54. data/lib/right_agent/monkey_patches/ruby_patch/linux_patch/file_patch.rb +30 -0
  55. data/lib/right_agent/monkey_patches/ruby_patch/object_patch.rb +49 -0
  56. data/lib/right_agent/monkey_patches/ruby_patch/singleton_patch.rb +46 -0
  57. data/lib/right_agent/monkey_patches/ruby_patch/string_patch.rb +107 -0
  58. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch.rb +32 -0
  59. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/file_patch.rb +90 -0
  60. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/process_patch.rb +63 -0
  61. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/stdio_patch.rb +27 -0
  62. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/time_patch.rb +55 -0
  63. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/win32ole_patch.rb +34 -0
  64. data/lib/right_agent/multiplexer.rb +91 -0
  65. data/lib/right_agent/operation_result.rb +270 -0
  66. data/lib/right_agent/packets.rb +637 -0
  67. data/lib/right_agent/payload_formatter.rb +104 -0
  68. data/lib/right_agent/pid_file.rb +159 -0
  69. data/lib/right_agent/platform.rb +319 -0
  70. data/lib/right_agent/platform/darwin.rb +227 -0
  71. data/lib/right_agent/platform/linux.rb +268 -0
  72. data/lib/right_agent/platform/windows.rb +1204 -0
  73. data/lib/right_agent/scripts/agent_controller.rb +522 -0
  74. data/lib/right_agent/scripts/agent_deployer.rb +379 -0
  75. data/lib/right_agent/scripts/common_parser.rb +153 -0
  76. data/lib/right_agent/scripts/log_level_manager.rb +193 -0
  77. data/lib/right_agent/scripts/stats_manager.rb +256 -0
  78. data/lib/right_agent/scripts/usage.rb +58 -0
  79. data/lib/right_agent/secure_identity.rb +92 -0
  80. data/lib/right_agent/security.rb +32 -0
  81. data/lib/right_agent/security/cached_certificate_store_proxy.rb +63 -0
  82. data/lib/right_agent/security/certificate.rb +102 -0
  83. data/lib/right_agent/security/certificate_cache.rb +89 -0
  84. data/lib/right_agent/security/distinguished_name.rb +56 -0
  85. data/lib/right_agent/security/encrypted_document.rb +84 -0
  86. data/lib/right_agent/security/rsa_key_pair.rb +76 -0
  87. data/lib/right_agent/security/signature.rb +86 -0
  88. data/lib/right_agent/security/static_certificate_store.rb +69 -0
  89. data/lib/right_agent/sender.rb +937 -0
  90. data/lib/right_agent/serialize.rb +29 -0
  91. data/lib/right_agent/serialize/message_pack.rb +102 -0
  92. data/lib/right_agent/serialize/secure_serializer.rb +131 -0
  93. data/lib/right_agent/serialize/secure_serializer_initializer.rb +47 -0
  94. data/lib/right_agent/serialize/serializable.rb +135 -0
  95. data/lib/right_agent/serialize/serializer.rb +149 -0
  96. data/lib/right_agent/stats_helper.rb +731 -0
  97. data/lib/right_agent/subprocess.rb +38 -0
  98. data/lib/right_agent/tracer.rb +124 -0
  99. data/right_agent.gemspec +60 -0
  100. data/spec/actor_registry_spec.rb +81 -0
  101. data/spec/actor_spec.rb +99 -0
  102. data/spec/agent_config_spec.rb +226 -0
  103. data/spec/agent_identity_spec.rb +75 -0
  104. data/spec/agent_spec.rb +571 -0
  105. data/spec/broker_client_spec.rb +961 -0
  106. data/spec/command/agent_manager_commands_spec.rb +51 -0
  107. data/spec/command/command_io_spec.rb +93 -0
  108. data/spec/command/command_parser_spec.rb +79 -0
  109. data/spec/command/command_runner_spec.rb +72 -0
  110. data/spec/command/command_serializer_spec.rb +51 -0
  111. data/spec/core_payload_types/dev_repositories_spec.rb +64 -0
  112. data/spec/core_payload_types/executable_bundle_spec.rb +59 -0
  113. data/spec/core_payload_types/login_user_spec.rb +98 -0
  114. data/spec/core_payload_types/right_script_attachment_spec.rb +65 -0
  115. data/spec/core_payload_types/spec_helper.rb +23 -0
  116. data/spec/dispatcher_spec.rb +372 -0
  117. data/spec/enrollment_result_spec.rb +53 -0
  118. data/spec/ha_broker_client_spec.rb +1673 -0
  119. data/spec/idempotent_request_spec.rb +136 -0
  120. data/spec/log_spec.rb +177 -0
  121. data/spec/monkey_patches/amqp_patch_spec.rb +100 -0
  122. data/spec/monkey_patches/eventmachine_spec.rb +62 -0
  123. data/spec/monkey_patches/string_patch_spec.rb +99 -0
  124. data/spec/multiplexer_spec.rb +48 -0
  125. data/spec/operation_result_spec.rb +171 -0
  126. data/spec/packets_spec.rb +418 -0
  127. data/spec/platform/platform_spec.rb +60 -0
  128. data/spec/results_mock.rb +45 -0
  129. data/spec/secure_identity_spec.rb +50 -0
  130. data/spec/security/cached_certificate_store_proxy_spec.rb +56 -0
  131. data/spec/security/certificate_cache_spec.rb +71 -0
  132. data/spec/security/certificate_spec.rb +49 -0
  133. data/spec/security/distinguished_name_spec.rb +46 -0
  134. data/spec/security/encrypted_document_spec.rb +55 -0
  135. data/spec/security/rsa_key_pair_spec.rb +55 -0
  136. data/spec/security/signature_spec.rb +66 -0
  137. data/spec/security/static_certificate_store_spec.rb +52 -0
  138. data/spec/sender_spec.rb +887 -0
  139. data/spec/serialize/message_pack_spec.rb +131 -0
  140. data/spec/serialize/secure_serializer_spec.rb +102 -0
  141. data/spec/serialize/serializable_spec.rb +90 -0
  142. data/spec/serialize/serializer_spec.rb +174 -0
  143. data/spec/spec.opts +2 -0
  144. data/spec/spec_helper.rb +77 -0
  145. data/spec/stats_helper_spec.rb +681 -0
  146. data/spec/tracer_spec.rb +114 -0
  147. metadata +320 -0
@@ -0,0 +1,53 @@
1
+ # Copyright (c) 2009-2011 RightScale, Inc, All Rights Reserved Worldwide.
2
+ #
3
+ # THIS PROGRAM IS CONFIDENTIAL AND PROPRIETARY TO RIGHTSCALE
4
+ # AND CONSTITUTES A VALUABLE TRADE SECRET. Any unauthorized use,
5
+ # reproduction, modification, or disclosure of this program is
6
+ # strictly prohibited. Any use of this program by an authorized
7
+ # licensee is strictly subject to the terms and conditions,
8
+ # including confidentiality obligations, set forth in the applicable
9
+ # License Agreement between RightScale.com, Inc. and
10
+ # the licensee.
11
+
12
+ require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
13
+ require File.expand_path(File.join(File.dirname(__FILE__), '..' , 'lib', 'right_agent', 'enrollment_result'))
14
+
15
+ describe RightScale::EnrollmentResult do
16
+ before(:each) do
17
+ @key = 'topsecret'
18
+ @result = RightScale::EnrollmentResult.new(6, Time.now, 'mapper cert', 'my cert', 'my private key', @key)
19
+ @message = RightScale::EnrollmentResult.dump(@result)
20
+ end
21
+
22
+ it 'should serialize and unserialize correctly' do
23
+ r2 = RightScale::EnrollmentResult.load(@message, @key)
24
+ @result.should == r2
25
+ end
26
+
27
+ context "supporting different versions" do
28
+ RightScale::EnrollmentResult::SUPPORTED_VERSIONS.each do |v|
29
+ it "should support version #{v}" do
30
+ @result = RightScale::EnrollmentResult.new(v, Time.now, 'mapper cert', 'my cert', 'my private key', @key)
31
+ serialized = RightScale::EnrollmentResult.dump(@result)
32
+ @result2 = RightScale::EnrollmentResult.load(serialized, @key)
33
+ @result.should == @result2
34
+ end
35
+ end
36
+ end
37
+
38
+ it 'should fail to decrypt if tampered with' do
39
+ #Simulate some ciphertext tampering.
40
+ @message.gsub! /[0-9]/, '1'
41
+ @message.gsub! /"r_s_version":"[0-9]+"/, '"r_s_version":"6"'
42
+
43
+ lambda do
44
+ RightScale::EnrollmentResult.load(@message, @key)
45
+ end.should raise_error(RightScale::EnrollmentResult::IntegrityFailure)
46
+ end
47
+
48
+ it 'should fail to decrypt if the key is wrong' do
49
+ lambda do
50
+ RightScale::EnrollmentResult.load(@message, @key + "evil")
51
+ end.should raise_error(RightScale::EnrollmentResult::IntegrityFailure)
52
+ end
53
+ end
@@ -0,0 +1,1673 @@
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::HABrokerClient do
26
+
27
+ include FlexMock::ArgumentTypes
28
+
29
+ before(:each) do
30
+ flexmock(RightScale::Log).should_receive(:error).by_default.and_return { |m| raise RightScale::Log.format(*m) }
31
+ flexmock(RightScale::Log).should_receive(:warning).by_default.and_return { |m| raise RightScale::Log.format(*m) }
32
+ flexmock(RightScale::Log).should_receive(:info).by_default
33
+ end
34
+
35
+ describe "Context" do
36
+
37
+ before(:each) do
38
+ @packet1 = flexmock("packet1", :class => RightScale::Request, :name => "request", :type => "type1",
39
+ :from => "from1", :token => "token1", :one_way => false)
40
+ @packet2 = flexmock("packet2", :class => FlexMock, :name => "flexmock")
41
+ @brokers = ["broker"]
42
+ @options = {:option => "option"}
43
+ end
44
+
45
+ it "should initialize context" do
46
+ context = RightScale::HABrokerClient::Context.new(@packet1, @options, @brokers)
47
+ context.name.should == "request"
48
+ context.type.should == "type1"
49
+ context.from.should == "from1"
50
+ context.token.should == "token1"
51
+ context.one_way.should be_false
52
+ context.options.should == @options
53
+ context.brokers.should == @brokers
54
+ context.failed.should == []
55
+ end
56
+
57
+ it "should treat type, from, token, and one_way as optional members of packet but default one_way to true" do
58
+ context = RightScale::HABrokerClient::Context.new(@packet2, @options, @brokers)
59
+ context.name.should == "flexmock"
60
+ context.type.should be_nil
61
+ context.from.should be_nil
62
+ context.token.should be_nil
63
+ context.one_way.should be_true
64
+ context.options.should == @options
65
+ context.brokers.should == @brokers
66
+ context.failed.should == []
67
+ end
68
+
69
+ end
70
+
71
+ describe "Caching" do
72
+
73
+ before(:each) do
74
+ flexmock(Time).should_receive(:now).and_return(Time.at(1000000)).by_default
75
+ @published = RightScale::HABrokerClient::Published.new
76
+ @message1 = MessagePack.dump(:signature => "signature1")
77
+ @key1 = @message1[@message1 =~ /signature/, 1000]
78
+ @message2 = JSON.dump(:signature => "signature2")
79
+ @key2 = @message2[@message2 =~ /signature/, 1000]
80
+ @message3 = MessagePack.dump(:data => "just data")
81
+ @key3 = @message3
82
+ @packet1 = flexmock("packet1", :class => RightScale::Request, :name => "request", :type => "type1",
83
+ :from => "from1", :token => "token1", :one_way => false)
84
+ @packet2 = flexmock("packet2", :class => RightScale::Request, :name => "request", :type => "type2",
85
+ :from => "from2", :token => "token2", :one_way => false)
86
+ @packet3 = flexmock("packet3", :class => RightScale::Push, :name => "push", :type => "type3",
87
+ :from => "from3", :token => "token3", :one_way => true)
88
+ @brokers = ["broker"]
89
+ @options = {:option => "option"}
90
+ @context1 = RightScale::HABrokerClient::Context.new(@packet1, @options, @brokers)
91
+ @context2 = RightScale::HABrokerClient::Context.new(@packet2, @options, @brokers)
92
+ @context3 = RightScale::HABrokerClient::Context.new(@packet3, @options, @brokers)
93
+ end
94
+
95
+ it "should use message signature as cache hash key if it has one" do
96
+ @published.identify(@message1).should == @key1
97
+ @published.identify(@message2).should == @key2
98
+ @published.identify(@message3).should == @key3
99
+ end
100
+
101
+ it "should store message info" do
102
+ @published.store(@message1, @context1)
103
+ @published.instance_variable_get(:@cache)[@key1].should == [1000000, @context1]
104
+ @published.instance_variable_get(:@lru).should == [@key1]
105
+ end
106
+
107
+ it "should update timestamp and lru list when store to existing entry" do
108
+ @published.store(@message1, @context1)
109
+ @published.instance_variable_get(:@cache)[@key1].should == [1000000, @context1]
110
+ @published.instance_variable_get(:@lru).should == [@key1]
111
+ @published.store(@message2, @context2)
112
+ @published.instance_variable_get(:@lru).should == [@key1, @key2]
113
+ flexmock(Time).should_receive(:now).and_return(Time.at(1000010))
114
+ @published.store(@message1, @context1)
115
+ @published.instance_variable_get(:@cache)[@key1].should == [1000010, @context1]
116
+ @published.instance_variable_get(:@lru).should == [@key2, @key1]
117
+ end
118
+
119
+ it "should remove old cache entries when store new one" do
120
+ @published.store(@message1, @context1)
121
+ @published.store(@message2, @context2)
122
+ @published.instance_variable_get(:@cache).keys.should == [@key1, @key2]
123
+ @published.instance_variable_get(:@lru).should == [@key1, @key2]
124
+ flexmock(Time).should_receive(:now).and_return(Time.at(1000031))
125
+ @published.store(@message3, @context3)
126
+ @published.instance_variable_get(:@cache).keys.should == [@key3]
127
+ @published.instance_variable_get(:@lru).should == [@key3]
128
+ end
129
+
130
+ it "should fetch message info and make it the most recently used" do
131
+ @published.store(@message1, @context1)
132
+ @published.store(@message2, @context2)
133
+ @published.instance_variable_get(:@lru).should == [@key1, @key2]
134
+ @published.fetch(@message1).should == @context1
135
+ @published.instance_variable_get(:@lru).should == [@key2, @key1]
136
+ end
137
+
138
+ it "should fetch empty hash if entry not found" do
139
+ @published.fetch(@message1).should be_nil
140
+ @published.store(@message1, @context1)
141
+ @published.fetch(@message1).should_not be_nil
142
+ @published.fetch(@message2).should be_nil
143
+ end
144
+
145
+ end # Published
146
+
147
+ context "when initializing" do
148
+
149
+ before(:each) do
150
+ @serializer = flexmock("Serializer")
151
+ @exceptions = RightScale::StatsHelper::ExceptionStats
152
+ @identity = "rs-broker-localhost-5672"
153
+ @address = {:host => "localhost", :port => 5672, :index => 0}
154
+ @broker = flexmock("broker_client", :identity => @identity, :usable? => true)
155
+ @broker.should_receive(:return_message).by_default
156
+ @broker.should_receive(:update_status).by_default
157
+ flexmock(RightScale::BrokerClient).should_receive(:new).and_return(@broker).by_default
158
+ @island1 = flexmock("island1", :id => 11, :broker_hosts => "second:1,first:0", :broker_ports => "5673")
159
+ @island2 = flexmock("island2", :id => 22, :broker_hosts => "third:0,fourth:1", :broker_ports => nil)
160
+ @islands = {11 => @island1, 22 => @island2}
161
+ end
162
+
163
+ it "should create a broker client for default host and port" do
164
+ flexmock(RightScale::BrokerClient).should_receive(:new).with(@identity, @address, @serializer,
165
+ @exceptions, Hash, nil, nil).and_return(@broker).once
166
+ ha = RightScale::HABrokerClient.new(@serializer)
167
+ ha.brokers.should == [@broker]
168
+ end
169
+
170
+ it "should create broker clients for specified hosts and ports and assign index in order of creation" do
171
+ address1 = {:host => "first", :port => 5672, :index => 0}
172
+ broker1 = flexmock("broker_client1", :identity => "rs-broker-first-5672", :usable? => true, :return_message => true)
173
+ flexmock(RightScale::BrokerClient).should_receive(:new).with("rs-broker-first-5672", address1, @serializer,
174
+ RightScale::StatsHelper::ExceptionStats, Hash, nil, nil).and_return(broker1).once
175
+ address2 = {:host => "second", :port => 5672, :index => 1}
176
+ broker2 = flexmock("broker_client2", :identity => "rs-broker-second-5672", :usable? => true, :return_message => true)
177
+ flexmock(RightScale::BrokerClient).should_receive(:new).with("rs-broker-second-5672", address2, @serializer,
178
+ RightScale::StatsHelper::ExceptionStats, Hash, nil, nil).and_return(broker2).once
179
+ ha = RightScale::HABrokerClient.new(@serializer, :host => "first, second", :port => 5672)
180
+ ha.brokers.should == [broker1, broker2]
181
+ ha.home_island.should be_nil
182
+ end
183
+
184
+ it "should create broker clients for specified islands" do
185
+ address1 = {:host => "first", :port => 5673, :index => 0}
186
+ broker1 = flexmock("broker_client1", :identity => "rs-broker-first-5673", :usable? => true, :return_message => true)
187
+ flexmock(RightScale::BrokerClient).should_receive(:new).with("rs-broker-first-5673", address1, @serializer,
188
+ RightScale::StatsHelper::ExceptionStats, Hash, @island1, nil).and_return(broker1).once
189
+ address2 = {:host => "second", :port => 5673, :index => 1}
190
+ broker2 = flexmock("broker_client2", :identity => "rs-broker-second-5673", :usable? => true, :return_message => true)
191
+ flexmock(RightScale::BrokerClient).should_receive(:new).with("rs-broker-second-5673", address2, @serializer,
192
+ RightScale::StatsHelper::ExceptionStats, Hash, @island1, nil).and_return(broker2).once
193
+ address3 = {:host => "third", :port => 5672, :index => 0}
194
+ broker3 = flexmock("broker_client3", :identity => "rs-broker-third-5672", :usable? => true, :return_message => true)
195
+ flexmock(RightScale::BrokerClient).should_receive(:new).with("rs-broker-third-5672", address3, @serializer,
196
+ RightScale::StatsHelper::ExceptionStats, Hash, @island2, nil).and_return(broker3).once
197
+ address4 = {:host => "fourth", :port => 5672, :index => 1}
198
+ broker4 = flexmock("broker_client4", :identity => "rs-broker-fourth-5672", :usable? => true, :return_message => true)
199
+ flexmock(RightScale::BrokerClient).should_receive(:new).with("rs-broker-fourth-5672", address4, @serializer,
200
+ RightScale::StatsHelper::ExceptionStats, Hash, @island2, nil).and_return(broker4).once
201
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => 22)
202
+ ha.brokers.should == [broker3, broker4, broker2, broker1]
203
+ ha.home_island.should == 22
204
+ end
205
+
206
+ it "should raise an ArgumentError if it cannot find the home island" do
207
+ flexmock(RightScale::BrokerClient).should_receive(:new).never
208
+ lambda { RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => 33) }.
209
+ should raise_error(ArgumentError, /Could not find home island 33/)
210
+ end
211
+
212
+ it "should setup to receive returned messages from each usable broker client" do
213
+ @broker.should_receive(:return_message).twice
214
+ flexmock(RightScale::BrokerClient).should_receive(:new).and_return(@broker).twice
215
+ RightScale::HABrokerClient.new(@serializer, :host => "first, second", :port => 5672)
216
+ end
217
+
218
+ end # when initializing
219
+
220
+ context "when parsing user_data" do
221
+
222
+ it "should extra host list from RS_rn_url and RS_rn_host" do
223
+ RightScale::HABrokerClient.parse_user_data("RS_rn_url=rs@first/right_net&RS_rn_host=:0,second:1").should ==
224
+ ["first:0,second:1", nil]
225
+ end
226
+
227
+ it "should extra port list from RS_rn_port" do
228
+ RightScale::HABrokerClient.parse_user_data("RS_rn_url=rs@host/right_net&RS_rn_host=:1,host:0&RS_rn_port=5673:1,5672:0").should ==
229
+ ["host:1,host:0", "5673:1,5672:0"]
230
+ end
231
+
232
+ it "should raise an exception if there is no user data" do
233
+ lambda { RightScale::HABrokerClient.parse_user_data(nil) }.should raise_error(RightScale::HABrokerClient::NoUserData)
234
+ lambda { RightScale::HABrokerClient.parse_user_data("") }.should raise_error(RightScale::HABrokerClient::NoUserData)
235
+ end
236
+
237
+ it "should raise an exception if there are no broker hosts defined in the data" do
238
+ lambda { RightScale::HABrokerClient.parse_user_data("blah") }.should raise_error(RightScale::HABrokerClient::NoBrokerHosts)
239
+ end
240
+
241
+ it "should translate old host name to standard form" do
242
+ RightScale::HABrokerClient.parse_user_data("RS_rn_url=rs@broker.rightscale.com/right_net").should ==
243
+ ["broker1-1.rightscale.com", nil]
244
+ end
245
+
246
+ end # when parsing user_data
247
+
248
+ context "when addressing" do
249
+
250
+ it "should form list of broker addresses from specified hosts and ports" do
251
+ RightScale::HABrokerClient.addresses("first,second", "5672, 5674").should ==
252
+ [{:host => "first", :port => 5672, :index => 0}, {:host => "second", :port => 5674, :index => 1}]
253
+ end
254
+
255
+ it "should form list of broker addresses from specified hosts and ports and use ids associated with hosts" do
256
+ RightScale::HABrokerClient.addresses("first:1,second:2", "5672, 5674").should ==
257
+ [{:host => "first", :port => 5672, :index => 1}, {:host => "second", :port => 5674, :index => 2}]
258
+ end
259
+
260
+ it "should form list of broker addresses from specified hosts and ports and use ids associated with ports" do
261
+ RightScale::HABrokerClient.addresses("host", "5672:0, 5674:2").should ==
262
+ [{:host => "host", :port => 5672, :index => 0}, {:host => "host", :port => 5674, :index => 2}]
263
+ end
264
+
265
+ it "should use default host and port for broker identity if none provided" do
266
+ RightScale::HABrokerClient.addresses(nil, nil).should == [{:host => "localhost", :port => 5672, :index => 0}]
267
+ end
268
+
269
+ it "should use default port when ports is an empty string" do
270
+ RightScale::HABrokerClient.addresses("first, second", "").should ==
271
+ [{:host => "first", :port => 5672, :index => 0}, {:host => "second", :port => 5672, :index => 1}]
272
+ end
273
+
274
+ it "should use default host when hosts is an empty string" do
275
+ RightScale::HABrokerClient.addresses("", "5672, 5673").should ==
276
+ [{:host => "localhost", :port => 5672, :index => 0}, {:host => "localhost", :port => 5673, :index => 1}]
277
+ end
278
+
279
+ it "should reuse host if there is only one but multiple ports" do
280
+ RightScale::HABrokerClient.addresses("first", "5672, 5674").should ==
281
+ [{:host => "first", :port => 5672, :index => 0}, {:host => "first", :port => 5674, :index => 1}]
282
+ end
283
+
284
+ it "should reuse port if there is only one but multiple hosts" do
285
+ RightScale::HABrokerClient.addresses("first, second", 5672).should ==
286
+ [{:host => "first", :port => 5672, :index => 0}, {:host => "second", :port => 5672, :index => 1}]
287
+ end
288
+
289
+ it "should apply ids associated with host" do
290
+ RightScale::HABrokerClient.addresses("first:0, third:2", 5672).should ==
291
+ [{:host => "first", :port => 5672, :index => 0}, {:host => "third", :port => 5672, :index => 2}]
292
+ end
293
+
294
+ it "should not allow mismatched number of hosts and ports" do
295
+ runner = lambda { RightScale::HABrokerClient.addresses("first, second", "5672, 5673, 5674") }
296
+ runner.should raise_exception(ArgumentError)
297
+ end
298
+
299
+ end # when addressing
300
+
301
+ context "when identifying" do
302
+
303
+ before(:each) do
304
+ @serializer = flexmock("Serializer")
305
+ @exceptions = RightScale::StatsHelper::ExceptionStats
306
+
307
+ @address1 = {:host => "first", :port => 5672, :index => 0}
308
+ @identity1 = "rs-broker-first-5672"
309
+ @broker1 = flexmock("broker_client1", :identity => @identity1, :usable? => true, :return_message => true,
310
+ :alias => "b0", :host => "first", :port => 5672, :index => 0)
311
+ @broker1.should_receive(:island_id).and_return(nil).by_default
312
+ @broker1.should_receive(:in_home_island).and_return(true).by_default
313
+ flexmock(RightScale::BrokerClient).should_receive(:new).with(@identity1, @address1, @serializer,
314
+ @exceptions, Hash, nil, nil).and_return(@broker1).by_default
315
+
316
+ @address2 = {:host => "second", :port => 5672, :index => 1}
317
+ @identity2 = "rs-broker-second-5672"
318
+ @broker2 = flexmock("broker_client2", :identity => @identity2, :usable? => true, :return_message => true,
319
+ :alias => "b1", :host => "second", :port => 5672, :index => 1)
320
+ @broker2.should_receive(:island_id).and_return(nil).by_default
321
+ @broker2.should_receive(:in_home_island).and_return(true).by_default
322
+ flexmock(RightScale::BrokerClient).should_receive(:new).with(@identity2, @address2, @serializer,
323
+ @exceptions, Hash, nil, nil).and_return(@broker2).by_default
324
+
325
+ @address3 = {:host => "third", :port => 5672, :index => 2}
326
+ @identity3 = "rs-broker-third-5672"
327
+ @broker3 = flexmock("broker_client3", :identity => @identity3, :usable? => true, :return_message => true,
328
+ :alias => "b2", :host => "third", :port => 5672, :index => 2)
329
+ @broker3.should_receive(:island_id).and_return(nil).by_default
330
+ @broker3.should_receive(:in_home_island).and_return(true).by_default
331
+ flexmock(RightScale::BrokerClient).should_receive(:new).with(@identity3, @address3, @serializer,
332
+ @exceptions, Hash, nil, nil).and_return(@broker3).by_default
333
+ end
334
+
335
+ it "should use host and port to uniquely identity broker in AgentIdentity format" do
336
+ RightScale::HABrokerClient.identity("localhost", 5672).should == "rs-broker-localhost-5672"
337
+ RightScale::HABrokerClient.identity("10.21.102.23", 1234).should == "rs-broker-10.21.102.23-1234"
338
+ end
339
+
340
+ it "should replace '-' with '~' in host names when forming broker identity" do
341
+ RightScale::HABrokerClient.identity("9-1-1", 5672).should == "rs-broker-9~1~1-5672"
342
+ end
343
+
344
+ it "should use default port when forming broker identity" do
345
+ RightScale::HABrokerClient.identity("10.21.102.23").should == "rs-broker-10.21.102.23-5672"
346
+ end
347
+
348
+ it "should list broker identities" do
349
+ RightScale::HABrokerClient.identities("first,second", "5672, 5674").should ==
350
+ ["rs-broker-first-5672", "rs-broker-second-5674"]
351
+ end
352
+
353
+ it "should convert identities into aliases" do
354
+ ha = RightScale::HABrokerClient.new(@serializer, :host => "first:0, third:2", :port => 5672)
355
+ ha.aliases([@identity3]).should == ["b2"]
356
+ ha.aliases([@identity3, @identity1]).should == ["b2", "b0"]
357
+ end
358
+
359
+ it "should convert identities into nil alias when unknown" do
360
+ ha = RightScale::HABrokerClient.new(@serializer, :host => "first:0, third:2", :port => 5672)
361
+ ha.aliases(["rs-broker-second-5672", nil]).should == [nil, nil]
362
+ end
363
+
364
+ it "should convert identity into alias" do
365
+ ha = RightScale::HABrokerClient.new(@serializer, :host => "first:0, third:2", :port => 5672)
366
+ ha.alias_(@identity3).should == "b2"
367
+ end
368
+
369
+ it "should convert identity into nil alias when unknown" do
370
+ ha = RightScale::HABrokerClient.new(@serializer, :host => "first:0, third:2", :port => 5672)
371
+ ha.alias_("rs-broker-second-5672").should == nil
372
+ end
373
+
374
+ it "should convert identity into parts" do
375
+ ha = RightScale::HABrokerClient.new(@serializer, :host => "first:0, third:2", :port => 5672)
376
+ ha.identity_parts(@identity3).should == ["third", 5672, 2, 1, nil]
377
+ end
378
+
379
+ it "should convert an alias into parts" do
380
+ ha = RightScale::HABrokerClient.new(@serializer, :host => "first:0, third:2", :port => 5672)
381
+ ha.identity_parts("b2").should == ["third", 5672, 2, 1, nil]
382
+ end
383
+
384
+ it "should convert unknown identity into nil parts" do
385
+ ha = RightScale::HABrokerClient.new(@serializer, :host => "first:0, third:2", :port => 5672)
386
+ ha.identity_parts("rs-broker-second-5672").should == [nil, nil, nil, nil, nil]
387
+ end
388
+
389
+ it "should get identity from identity" do
390
+ ha = RightScale::HABrokerClient.new(@serializer, :host => "first:0, third:2", :port => 5672)
391
+ ha.get(@identity1).should == @identity1
392
+ ha.get("rs-broker-second-5672").should be_nil
393
+ ha.get(@identity3).should == @identity3
394
+ end
395
+
396
+ it "should get identity from an alias" do
397
+ ha = RightScale::HABrokerClient.new(@serializer, :host => "first:0, third:2", :port => 5672)
398
+ ha.get("b0").should == @identity1
399
+ ha.get("b1").should be_nil
400
+ ha.get("b2").should == @identity3
401
+ end
402
+
403
+ it "should generate host:index list" do
404
+ ha = RightScale::HABrokerClient.new(@serializer, :host => "second:1, first:0, third:2", :port => 5672)
405
+ ha.hosts.should == "second:1,first:0,third:2"
406
+ end
407
+
408
+ it "should generate port:index list" do
409
+ ha = RightScale::HABrokerClient.new(@serializer, :host => "second:1, third:2, first:0", :port => 5672)
410
+ ha.ports.should == "5672:1,5672:2,5672:0"
411
+ end
412
+
413
+ context "when using islands" do
414
+
415
+ before(:each) do
416
+ @island1 = flexmock("island1", :id => 11, :broker_hosts => "second:1,first:0", :broker_ports => "5672")
417
+ @island2 = flexmock("island2", :id => 22, :broker_hosts => "third:0,fourth:1", :broker_ports => nil)
418
+ @islands = {11 => @island1, 22 => @island2}
419
+
420
+ @broker1.should_receive(:island_id).and_return(11)
421
+ @broker1.should_receive(:in_home_island).and_return(false)
422
+ flexmock(RightScale::BrokerClient).should_receive(:new).with(@identity1, @address1, @serializer,
423
+ @exceptions, Hash, @island1, nil).and_return(@broker1)
424
+
425
+ @broker2.should_receive(:island_id).and_return(11)
426
+ @broker2.should_receive(:in_home_island).and_return(false)
427
+ flexmock(RightScale::BrokerClient).should_receive(:new).with(@identity2, @address2, @serializer,
428
+ @exceptions, Hash, @island1, nil).and_return(@broker2)
429
+
430
+ @address3 = {:host => "third", :port => 5672, :index => 0}
431
+ @identity3 = "rs-broker-third-5672"
432
+ @broker3 = flexmock("broker_client3", :identity => @identity3, :usable? => true, :return_message => true,
433
+ :alias => "b0", :host => "third", :port => 5672, :index => 0)
434
+ @broker3.should_receive(:island_id).and_return(22).by_default
435
+ @broker3.should_receive(:in_home_island).and_return(true)
436
+ flexmock(RightScale::BrokerClient).should_receive(:new).with(@identity3, @address3, @serializer,
437
+ @exceptions, Hash, @island2, nil).and_return(@broker3)
438
+
439
+ @address4 = {:host => "fourth", :port => 5672, :index => 1}
440
+ @identity4 = "rs-broker-fourth-5672"
441
+ @broker4 = flexmock("broker_client4", :identity => @identity4, :usable? => true, :return_message => true,
442
+ :alias => "b1", :host => "fourth", :port => 5672, :index => 1)
443
+ @broker4.should_receive(:island_id).and_return(22)
444
+ @broker4.should_receive(:in_home_island).and_return(true)
445
+ flexmock(RightScale::BrokerClient).should_receive(:new).with(@identity4, @address4, @serializer,
446
+ @exceptions, Hash, @island2, nil).and_return(@broker4)
447
+ end
448
+
449
+ it "should convert identity into parts that includes island_id" do
450
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => 22)
451
+ ha.identity_parts(@identity1).should == ["first", 5672, 0, 1, 11]
452
+ ha.identity_parts(@identity2).should == ["second", 5672, 1, 0, 11]
453
+ ha.identity_parts(@identity3).should == ["third", 5672, 0, 0, 22]
454
+ ha.identity_parts(@identity4).should == ["fourth", 5672, 1, 1, 22]
455
+ end
456
+
457
+ it "should generate host:index list for home island" do
458
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => 22)
459
+ ha.hosts.should == "third:0,fourth:1"
460
+ ha.hosts(22).should == "third:0,fourth:1"
461
+ end
462
+
463
+ it "should generate host:index list for other island" do
464
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => 22)
465
+ ha.hosts(11).should == "second:1,first:0"
466
+ end
467
+
468
+ it "should generate port:index list for home island" do
469
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => 22)
470
+ ha.ports.should == "5672:0,5672:1"
471
+ ha.ports(22).should == "5672:0,5672:1"
472
+ end
473
+
474
+ it "should generate port:index list for other island" do
475
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => 22)
476
+ ha.ports(11).should == "5672:1,5672:0"
477
+ end
478
+
479
+ end # when using islands
480
+
481
+ end # when identifying
482
+
483
+ context "when" do
484
+
485
+ before(:each) do
486
+ @serializer = flexmock("Serializer")
487
+ @exceptions = RightScale::StatsHelper::ExceptionStats
488
+
489
+ @island1 = flexmock("island1", :id => 11, :index => 0, :broker_ports => nil)
490
+ @island1.should_receive(:broker_hosts).and_return("first:0,second:1").by_default
491
+ @island2 = flexmock("island2", :id => 22, :index => 1, :broker_ports => nil)
492
+ @island2.should_receive(:broker_hosts).and_return("third:0,fourth:1").by_default
493
+ @islands = {11 => @island1, 22 => @island2}
494
+ @home = 22
495
+
496
+ # Generate mocking for five BrokerClients in two islands with second being home island
497
+ # The fifth client is not configured for use except when doing island updates
498
+ # key index host alias island_id
499
+ { 1 => [0, "first", "i0b0", 1],
500
+ 2 => [1, "second", "i0b1", 1],
501
+ 3 => [0, "third", "b0" , 2],
502
+ 4 => [1, "fourth", "b1" , 2],
503
+ 5 => [2, "fifth", "b2" , 2] }.each do |k, v|
504
+ i, h, a, d = v
505
+ eval("@identity#{k} = 'rs-broker-#{h}-5672'")
506
+ eval("@address#{k} = {:host => '#{h}', :port => 5672, :index => #{i}}")
507
+ eval("@broker#{k} = flexmock('broker_client#{k}', :identity => @identity#{k}, :alias => '#{a}', " +
508
+ ":host => '#{h}', :port => 5672, :index => #{i}, :island_id => #{d}#{d}, " +
509
+ ":in_home_island => #{d}#{d} == @home)")
510
+ eval("@broker#{k}.should_receive(:status).and_return(:connected).by_default")
511
+ eval("@broker#{k}.should_receive(:usable?).and_return(true).by_default")
512
+ eval("@broker#{k}.should_receive(:connected?).and_return(true).by_default")
513
+ eval("@broker#{k}.should_receive(:subscribe).and_return(true).by_default")
514
+ eval("@broker#{k}.should_receive(:return_message).and_return(true).by_default")
515
+ eval("flexmock(RightScale::BrokerClient).should_receive(:new).with(@identity#{k}, @address#{k}, " +
516
+ "@serializer, @exceptions, Hash, @island#{d}, nil).and_return(@broker#{k}).by_default")
517
+ end
518
+ end
519
+
520
+ context "connecting" do
521
+
522
+ # Generate mocking for three BrokerClients that do not use islands
523
+ before(:each) do
524
+ {0 => "a", 1 => "b", 2 => "c"}.each do |i, h|
525
+ eval("@identity_#{h} = 'rs-broker-#{h}-5672'")
526
+ eval("@address_#{h} = {:host => '#{h}', :port => 5672, :index => #{i}}")
527
+ eval("@broker_#{h} = flexmock('broker_client_#{h}', :identity => @identity_#{h}, :alias => 'b#{i}', " +
528
+ ":host => '#{h}', :port => 5672, :index => #{i}, :island_id => nil, " +
529
+ ":in_home_island => true)")
530
+ eval("@broker_#{h}.should_receive(:usable?).and_return(true).by_default")
531
+ eval("@broker_#{h}.should_receive(:return_message).and_return(true).by_default")
532
+ eval("flexmock(RightScale::BrokerClient).should_receive(:new).with(@identity_#{h}, @address_#{h}, " +
533
+ "@serializer, @exceptions, Hash, nil, any).and_return(@broker_#{h}).by_default")
534
+ end
535
+ end
536
+
537
+ it "should connect and add a new broker client to the end of the list" do
538
+ ha = RightScale::HABrokerClient.new(@serializer, :host => "a", :port => 5672)
539
+ ha.brokers.size.should == 1
540
+ ha.brokers[0].alias == "b0"
541
+ flexmock(RightScale::BrokerClient).should_receive(:new).with(@identity_b, @address_b, @serializer,
542
+ @exceptions, Hash, nil, nil).and_return(@broker_b).once
543
+ res = ha.connect("b", 5672, 1)
544
+ res.should be_true
545
+ ha.brokers.size.should == 2
546
+ ha.brokers[1].alias == "b1"
547
+ end
548
+
549
+ it "should reconnect an existing broker client after closing it if it is not connected" do
550
+ ha = RightScale::HABrokerClient.new(@serializer, :host => "a, b")
551
+ ha.brokers.size.should == 2
552
+ @broker_a.should_receive(:usable?).and_return(false)
553
+ @broker_a.should_receive(:close).and_return(true).once
554
+ flexmock(RightScale::BrokerClient).should_receive(:new).with(@identity_a, @address_a, @serializer,
555
+ @exceptions, Hash, nil, ha.brokers[0]).and_return(@broker_a).once
556
+ res = ha.connect("a", 5672, 0)
557
+ res.should be_true
558
+ ha.brokers.size.should == 2
559
+ ha.brokers[0].alias == "b0"
560
+ ha.brokers[1].alias == "b1"
561
+ end
562
+
563
+ it "should a new broker client and reconnect broker clients when an island is specified" do
564
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => {22 => @island2}, :home_island => @home)
565
+ ha.brokers.size.should == 2
566
+ ha.brokers[0].alias == "b0"
567
+ ha.brokers[1].alias == "b1"
568
+ flexmock(RightScale::BrokerClient).should_receive(:new).with(@identity2, @address2, @serializer,
569
+ @exceptions, Hash, @island1, nil).and_return(@broker2).by_default
570
+ res = ha.connect("second", 5672, 1, nil, @island1)
571
+ res.should be_true
572
+ ha.brokers.size.should == 3
573
+ ha.brokers[0].alias == "b0"
574
+ ha.brokers[1].alias == "b1"
575
+ ha.brokers[2].alias == "i0b1"
576
+ @broker3.should_receive(:usable?).and_return(false)
577
+ @broker3.should_receive(:close).and_return(true).once
578
+ flexmock(RightScale::BrokerClient).should_receive(:new).with(@identity3, @address3, @serializer,
579
+ @exceptions, Hash, @island2, ha.brokers[0]).and_return(@broker3).by_default
580
+ res = ha.connect("third", 5672, 0, nil, @island2)
581
+ res.should be_true
582
+ ha.brokers.size.should == 3
583
+ ha.brokers[0].alias == "b0"
584
+ ha.brokers[1].alias == "b1"
585
+ ha.brokers[2].alias == "i0b1"
586
+ flexmock(RightScale::BrokerClient).should_receive(:new).with(@identity1, @address1, @serializer,
587
+ @exceptions, Hash, @island1, nil).and_return(@broker1).by_default
588
+ res = ha.connect("first", 5672, 0, 0, @island1)
589
+ res.should be_true
590
+ ha.brokers.size.should == 4
591
+ ha.brokers[0].alias == "b0"
592
+ ha.brokers[1].alias == "b1"
593
+ ha.brokers[2].alias == "i0b0"
594
+ ha.brokers[3].alias == "i0b1"
595
+ end
596
+
597
+ it "should not do anything except log a message if asked to reconnect an already connected broker client" do
598
+ flexmock(RightScale::Log).should_receive(:info).with(/Ignored request to reconnect/).once
599
+ ha = RightScale::HABrokerClient.new(@serializer, :host => "a, b")
600
+ ha.brokers.size.should == 2
601
+ @broker_a.should_receive(:status).and_return(:connected).once
602
+ @broker_a.should_receive(:close).and_return(true).never
603
+ flexmock(RightScale::BrokerClient).should_receive(:new).with(@identity_a, @address_a, @serializer,
604
+ @exceptions, Hash, nil, ha.brokers[0]).and_return(@broker_a).never
605
+ res = ha.connect("a", 5672, 0)
606
+ res.should be_false
607
+ ha.brokers.size.should == 2
608
+ ha.brokers[0].alias == "b0"
609
+ ha.brokers[1].alias == "b1"
610
+ end
611
+
612
+ it "should reconnect already connected broker client if force specified" do
613
+ flexmock(RightScale::Log).should_receive(:info).with(/Ignored request to reconnect/).never
614
+ ha = RightScale::HABrokerClient.new(@serializer, :host => "a, b")
615
+ ha.brokers.size.should == 2
616
+ @broker_a.should_receive(:close).and_return(true).once
617
+ flexmock(RightScale::BrokerClient).should_receive(:new).with(@identity_a, @address_a, @serializer,
618
+ @exceptions, Hash, nil, ha.brokers[0]).and_return(@broker_a).once
619
+ res = ha.connect("a", 5672, 0, nil, nil, force = true)
620
+ res.should be_true
621
+ ha.brokers.size.should == 2
622
+ ha.brokers[0].alias == "b0"
623
+ ha.brokers[1].alias == "b1"
624
+ end
625
+
626
+ it "should slot broker client into specified priority position when at end of list" do
627
+ ha = RightScale::HABrokerClient.new(@serializer, :host => "a, b")
628
+ ha.brokers.size.should == 2
629
+ res = ha.connect("c", 5672, 2, 2)
630
+ res.should be_true
631
+ ha.brokers.size.should == 3
632
+ ha.brokers[0].alias == "b0"
633
+ ha.brokers[1].alias == "b1"
634
+ ha.brokers[2].alias == "b2"
635
+ end
636
+
637
+ it "should slot broker client into specified priority position when already is a client in that position" do
638
+ ha = RightScale::HABrokerClient.new(@serializer, :host => "a, b")
639
+ ha.brokers.size.should == 2
640
+ res = ha.connect("c", 5672, 2, 1)
641
+ res.should be_true
642
+ ha.brokers.size.should == 3
643
+ ha.brokers[0].alias == "b0"
644
+ ha.brokers[1].alias == "b2"
645
+ ha.brokers[2].alias == "b1"
646
+ end
647
+
648
+ it "should slot broker client into nex priority position if specified priority would leave a gap" do
649
+ flexmock(RightScale::Log).should_receive(:info).with(/Reduced priority setting for broker/).once
650
+ ha = RightScale::HABrokerClient.new(@serializer, :host => "a")
651
+ ha.brokers.size.should == 1
652
+ res = ha.connect("c", 5672, 2, 2)
653
+ res.should be_true
654
+ ha.brokers.size.should == 2
655
+ ha.brokers[0].alias == "b0"
656
+ ha.brokers[1].alias == "b2"
657
+ end
658
+
659
+ it "should yield to the block provided with the newly connected broker identity" do
660
+ ha = RightScale::HABrokerClient.new(@serializer, :host => "a")
661
+ ha.brokers.size.should == 1
662
+ ha.brokers[0].alias == "b0"
663
+ identity = nil
664
+ res = ha.connect("b", 5672, 1) { |i| identity = i }
665
+ res.should be_true
666
+ identity.should == @identity_b
667
+ ha.brokers.size.should == 2
668
+ ha.brokers[1].alias == "b1"
669
+ end
670
+
671
+ it "should raise an exception if try to change host and port of an existing broker client" do
672
+ ha = RightScale::HABrokerClient.new(@serializer, :host => "a, b")
673
+ lambda { ha.connect("c", 5672, 0) }.should raise_error(Exception, /Not allowed to change host or port/)
674
+ end
675
+
676
+ end # connecting
677
+
678
+ context "updating connection" do
679
+
680
+ it "should connect to any brokers for which not currently connected and return their identity" do
681
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
682
+ ha.brokers.size.should == 4
683
+ @island2.should_receive(:broker_hosts).and_return("third:0,fourth:1,fifth:2")
684
+ ha.connect_update(@islands)
685
+ ha.brokers.size.should == 5
686
+ ha.brokers[0].alias.should == "b0"
687
+ ha.brokers[1].alias.should == "b1"
688
+ ha.brokers[2].alias.should == "b2"
689
+ ha.brokers[3].alias.should == "i0b0"
690
+ ha.brokers[4].alias.should == "i0b1"
691
+ ha.instance_variable_get(:@brokers_hash)[@identity5].should == @broker5
692
+ end
693
+
694
+ it "should do nothing if there is no change" do
695
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
696
+ ha.brokers.size.should == 4
697
+ ha.connect_update(@islands)
698
+ ha.brokers.size.should == 4
699
+ ha.brokers[0].alias.should == "b0"
700
+ ha.brokers[1].alias.should == "b1"
701
+ ha.brokers[2].alias.should == "i0b0"
702
+ ha.brokers[3].alias.should == "i0b1"
703
+ end
704
+
705
+ it "should remove any broker clients for islands in which they are no longer configured" do
706
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
707
+ ha.brokers.size.should == 4
708
+ @broker1.should_receive(:close).and_return(true).once
709
+ @broker3.should_receive(:close).and_return(true).once
710
+ @island1.should_receive(:broker_hosts).and_return("second:1")
711
+ @island2.should_receive(:broker_hosts).and_return("fourth:1,fifth:2")
712
+ ha.connect_update(@islands)
713
+ ha.brokers.size.should == 3
714
+ ha.brokers[0].alias.should == "b2"
715
+ ha.brokers[1].alias.should == "b1"
716
+ ha.brokers[2].alias.should == "i0b1"
717
+ ha.instance_variable_get(:@brokers_hash)[@identity1].should be_nil
718
+ ha.instance_variable_get(:@brokers_hash)[@identity3].should be_nil
719
+ ha.instance_variable_get(:@brokers_hash)[@identity5].should == @broker5
720
+ end
721
+
722
+ end # updating connection
723
+
724
+ context "subscribing" do
725
+
726
+ it "should subscribe on all usable broker clients and return their identities" do
727
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
728
+ @broker1.should_receive(:usable?).and_return(false)
729
+ @broker1.should_receive(:subscribe).never
730
+ @broker2.should_receive(:subscribe).and_return(true).once
731
+ @broker3.should_receive(:subscribe).and_return(true).once
732
+ @broker4.should_receive(:subscribe).and_return(true).once
733
+ result = ha.subscribe({:name => "queue"}, {:type => :direct, :name => "exchange"})
734
+ result.should == [@identity3, @identity4, @identity2]
735
+ end
736
+
737
+ it "should not return the identity if subscribe fails" do
738
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
739
+ @broker1.should_receive(:usable?).and_return(false)
740
+ @broker1.should_receive(:subscribe).never
741
+ @broker2.should_receive(:subscribe).and_return(true).once
742
+ @broker3.should_receive(:subscribe).and_return(false).once
743
+ @broker4.should_receive(:subscribe).and_return(true).once
744
+ result = ha.subscribe({:name => "queue"}, {:type => :direct, :name => "exchange"})
745
+ result.should == [@identity4, @identity2]
746
+ end
747
+
748
+ it "should subscribe only on specified brokers" do
749
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
750
+ @broker1.should_receive(:usable?).and_return(false)
751
+ @broker1.should_receive(:subscribe).never
752
+ @broker2.should_receive(:subscribe).and_return(true).once
753
+ @broker3.should_receive(:subscribe).never
754
+ @broker4.should_receive(:subscribe).never
755
+ result = ha.subscribe({:name => "queue"}, {:type => :direct, :name => "exchange"},
756
+ :brokers => [@identity1, @identity2])
757
+ result.should == [@identity2]
758
+ end
759
+
760
+ end # subscribing
761
+
762
+ context "unsubscribing" do
763
+
764
+ before(:each) do
765
+ @timer = flexmock("timer", :cancel => true).by_default
766
+ flexmock(EM::Timer).should_receive(:new).and_return(@timer).by_default
767
+ @queue_name = "my_queue"
768
+ @queue = flexmock("queue", :name => @queue_name)
769
+ @queues = [@queue]
770
+ @broker1.should_receive(:queues).and_return(@queues).by_default
771
+ @broker1.should_receive(:unsubscribe).and_return(true).and_yield.by_default
772
+ @broker2.should_receive(:queues).and_return(@queues).by_default
773
+ @broker2.should_receive(:unsubscribe).and_return(true).and_yield.by_default
774
+ @broker3.should_receive(:queues).and_return(@queues).by_default
775
+ @broker3.should_receive(:unsubscribe).and_return(true).and_yield.by_default
776
+ @broker4.should_receive(:queues).and_return(@queues).by_default
777
+ @broker4.should_receive(:unsubscribe).and_return(true).and_yield.by_default
778
+ end
779
+
780
+ it "should unsubscribe from named queues on all usable broker clients" do
781
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
782
+ @broker1.should_receive(:usable?).and_return(false)
783
+ @broker1.should_receive(:unsubscribe).never
784
+ @broker2.should_receive(:unsubscribe).and_return(true).once
785
+ @broker3.should_receive(:unsubscribe).and_return(true).once
786
+ @broker4.should_receive(:unsubscribe).and_return(true).once
787
+ ha.unsubscribe([@queue_name]).should be_true
788
+ end
789
+
790
+ it "should yield to supplied block after unsubscribing" do
791
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
792
+ ha.subscribe({:name => @queue_name}, {:type => :direct, :name => "exchange"})
793
+ called = 0
794
+ ha.unsubscribe([@queue_name]) { called += 1 }
795
+ called.should == 1
796
+ end
797
+
798
+ it "should yield to supplied block if timeout before finish unsubscribing" do
799
+ flexmock(EM::Timer).should_receive(:new).with(10, Proc).and_return(@timer).and_yield.once
800
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
801
+ ha.subscribe({:name => @queue_name}, {:type => :direct, :name => "exchange"})
802
+ called = 0
803
+ ha.unsubscribe([@queue_name], 10) { called += 1 }
804
+ called.should == 1
805
+ end
806
+
807
+ it "should cancel timer if finish unsubscribing before timer fires" do
808
+ @timer.should_receive(:cancel).once
809
+ flexmock(EM::Timer).should_receive(:new).with(10, Proc).and_return(@timer).once
810
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
811
+ ha.subscribe({:name => @queue_name}, {:type => :direct, :name => "exchange"})
812
+ called = 0
813
+ ha.unsubscribe([@queue_name], 10) { called += 1 }
814
+ called.should == 1
815
+ end
816
+
817
+ it "should yield to supplied block after unsubscribing even if no queues to unsubscribe" do
818
+ @broker1.should_receive(:queues).and_return([])
819
+ @broker2.should_receive(:queues).and_return([])
820
+ @broker3.should_receive(:queues).and_return([])
821
+ @broker4.should_receive(:queues).and_return([])
822
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
823
+ called = 0
824
+ ha.unsubscribe([@queue_name]) { called += 1 }
825
+ called.should == 1
826
+ end
827
+
828
+ it "should yield to supplied block once after unsubscribing all queues" do
829
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
830
+ ha.subscribe({:name => @queue_name}, {:type => :direct, :name => "exchange"})
831
+ called = 0
832
+ ha.unsubscribe([@queue_name]) { called += 1 }
833
+ called.should == 1
834
+ end
835
+
836
+ end # unsubscribing
837
+
838
+ context "declaring" do
839
+
840
+ it "should declare exchange on all usable broker clients and return their identities" do
841
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
842
+ @broker1.should_receive(:usable?).and_return(false)
843
+ @broker1.should_receive(:declare).never
844
+ @broker2.should_receive(:declare).and_return(true).once
845
+ @broker3.should_receive(:declare).and_return(true).once
846
+ @broker4.should_receive(:declare).and_return(true).once
847
+ result = ha.declare(:exchange, "x", :durable => true)
848
+ result.should == [@identity3, @identity4, @identity2]
849
+ end
850
+
851
+ it "should not return the identity if declare fails" do
852
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
853
+ @broker1.should_receive(:usable?).and_return(false)
854
+ @broker1.should_receive(:declare).never
855
+ @broker2.should_receive(:declare).and_return(true).once
856
+ @broker3.should_receive(:declare).and_return(false).once
857
+ @broker4.should_receive(:declare).and_return(true).once
858
+ result = ha.declare(:exchange, "x", :durable => true)
859
+ result.should == [@identity4, @identity2]
860
+ end
861
+
862
+ it "should declare exchange only on specified brokers" do
863
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
864
+ @broker1.should_receive(:usable?).and_return(false)
865
+ @broker1.should_receive(:declare).never
866
+ @broker2.should_receive(:declare).and_return(true).once
867
+ @broker3.should_receive(:declare).never
868
+ @broker4.should_receive(:declare).never
869
+ result = ha.declare(:exchange, "x", :durable => true, :brokers => [@identity1, @identity2])
870
+ result.should == [@identity2]
871
+ end
872
+
873
+ end # declaring
874
+
875
+ context "publishing" do
876
+
877
+ before(:each) do
878
+ @message = flexmock("message")
879
+ @packet = flexmock("packet", :class => RightScale::Request, :to_s => true, :version => [12, 12]).by_default
880
+ @serializer.should_receive(:dump).with(@packet).and_return(@message).by_default
881
+ @broker1.should_receive(:publish).and_return(true).by_default
882
+ @broker2.should_receive(:publish).and_return(true).by_default
883
+ @broker3.should_receive(:publish).and_return(true).by_default
884
+ @broker4.should_receive(:publish).and_return(true).by_default
885
+ end
886
+
887
+ it "should serialize message, publish it, and return list of broker identifiers" do
888
+ @serializer.should_receive(:dump).with(@packet).and_return(@message).once
889
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
890
+ ha.publish({:type => :direct, :name => "exchange", :options => {:durable => true}},
891
+ @packet, :persistent => true).should == [@identity3]
892
+ end
893
+
894
+ it "should try other broker clients if a publish fails" do
895
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
896
+ @broker3.should_receive(:publish).and_return(false)
897
+ ha.publish({:type => :direct, :name => "exchange"}, @packet).should == [@identity4]
898
+ end
899
+
900
+ it "should only try to use home island brokers by default" do
901
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
902
+ @broker3.should_receive(:publish).and_return(false)
903
+ @broker4.should_receive(:publish).and_return(false)
904
+ lambda { ha.publish({:type => :direct, :name => "exchange"}, @packet) }.
905
+ should raise_error(RightScale::HABrokerClient::NoConnectedBrokers)
906
+ end
907
+
908
+ it "should publish to a randomly selected broker if random requested" do
909
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
910
+ srand(100)
911
+ ha.publish({:type => :direct, :name => "exchange"}, @packet, :order => :random,
912
+ :brokers =>[@identity1, @identity2, @identity3, @identity4]).should == [@identity2]
913
+ end
914
+
915
+ it "should publish to all connected brokers if fanout requested" do
916
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
917
+ ha.publish({:type => :direct, :name => "exchange"}, @packet, :fanout => true,
918
+ :brokers =>[@identity1, @identity2]).should == [@identity1, @identity2]
919
+ end
920
+
921
+ it "should publish only using specified brokers" do
922
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
923
+ ha.publish({:type => :direct, :name => "exchange"}, @packet,
924
+ :brokers =>[@identity1, @identity2]).should == [@identity1]
925
+ end
926
+
927
+ it "should log an error if a selected broker is unknown but still publish with any remaining brokers" do
928
+ flexmock(RightScale::Log).should_receive(:error).with(/Invalid broker identity "rs-broker-fifth-5672"/).once
929
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
930
+ ha.publish({:type => :direct, :name => "exchange"}, @packet,
931
+ :brokers =>["rs-broker-fifth-5672", @identity1]).should == [@identity1]
932
+ end
933
+
934
+ it "should raise an exception if all available brokers fail to publish" do
935
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
936
+ @broker3.should_receive(:publish).and_return(false)
937
+ @broker4.should_receive(:publish).and_return(false)
938
+ lambda { ha.publish({:type => :direct, :name => "exchange"}, @packet) }.
939
+ should raise_error(RightScale::HABrokerClient::NoConnectedBrokers)
940
+ end
941
+
942
+ it "should not serialize the message if it is already serialized" do
943
+ @serializer.should_receive(:dump).with(@packet).and_return(@message).never
944
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
945
+ ha.publish({:type => :direct, :name => "exchange"}, @packet, :no_serialize => true).should == [@identity3]
946
+ end
947
+
948
+ it "should store message info for use by message returns if :mandatory specified" do
949
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
950
+ ha.publish({:type => :direct, :name => "exchange"}, @packet, :mandatory => true).should == [@identity3]
951
+ ha.instance_variable_get(:@published).instance_variable_get(:@cache).size.should == 1
952
+ end
953
+
954
+ it "should not store message info for use by message returns if message already serialized" do
955
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
956
+ ha.publish({:type => :direct, :name => "exchange"}, @packet, :no_serialize => true).should == [@identity3]
957
+ ha.instance_variable_get(:@published).instance_variable_get(:@cache).size.should == 0
958
+ end
959
+
960
+ it "should not store message info for use by message returns if mandatory not specified" do
961
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
962
+ ha.publish({:type => :direct, :name => "exchange"}, @packet).should == [@identity3]
963
+ ha.instance_variable_get(:@published).instance_variable_get(:@cache).size.should == 0
964
+ end
965
+
966
+ end # publishing
967
+
968
+ context "returning" do
969
+
970
+ before(:each) do
971
+ @message = flexmock("message")
972
+ @packet = flexmock("packet", :class => RightScale::Request, :to_s => true, :version => [12, 12]).by_default
973
+ @serializer.should_receive(:dump).with(@packet).and_return(@message).by_default
974
+ @broker1.should_receive(:publish).and_return(true).by_default
975
+ @broker2.should_receive(:publish).and_return(true).by_default
976
+ @broker3.should_receive(:publish).and_return(true).by_default
977
+ @broker4.should_receive(:publish).and_return(true).by_default
978
+ end
979
+
980
+ it "should invoke return block" do
981
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
982
+ @broker1.should_receive(:return_message).and_yield("exchange", "NO_CONSUMERS", @message).once
983
+ called = 0
984
+ ha.return_message do |id, reason, message, to, context|
985
+ called += 1
986
+ id.should == @identity1
987
+ reason.should == "NO_CONSUMERS"
988
+ message.should == @message
989
+ to.should == "exchange"
990
+ end
991
+ called.should == 1
992
+ end
993
+
994
+ it "should record failure in message context if there is message context" do
995
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
996
+ ha.publish({:type => :direct, :name => "exchange", :options => {:durable => true}},
997
+ @packet, :mandatory => true).should == [@identity3]
998
+ @broker3.should_receive(:return_message).and_yield("exchange", "NO_CONSUMERS", @message).once
999
+ ha.return_message do |id, reason, message, to, context|
1000
+ id.should == @identity3
1001
+ reason.should == "NO_CONSUMERS"
1002
+ message.should == @message
1003
+ to.should == "exchange"
1004
+ end
1005
+ ha.instance_variable_get(:@published).fetch(@message).failed.should == [@identity3]
1006
+ end
1007
+
1008
+ context "when non-delivery" do
1009
+
1010
+ it "should store non-delivery block for use by return handler" do
1011
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
1012
+ non_delivery = lambda {}
1013
+ ha.non_delivery(&non_delivery)
1014
+ ha.instance_variable_get(:@non_delivery).should == non_delivery
1015
+ end
1016
+
1017
+ end
1018
+
1019
+ context "when handling return" do
1020
+
1021
+ before(:each) do
1022
+ @options = {}
1023
+ @brokers = [@identity3, @identity4]
1024
+ @context = RightScale::HABrokerClient::Context.new(@packet, @options, @brokers)
1025
+ end
1026
+
1027
+ it "should republish using a broker not yet tried if possible and log that re-routing" do
1028
+ flexmock(RightScale::Log).should_receive(:info).with(/RE-ROUTE/).once
1029
+ flexmock(RightScale::Log).should_receive(:info).with(/RETURN reason/).once
1030
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
1031
+ @context.record_failure(@identity3)
1032
+ @broker4.should_receive(:publish).and_return(true).once
1033
+ ha.__send__(:handle_return, @identity3, "reason", @message, "to", @context)
1034
+ end
1035
+
1036
+ it "should republish to same broker without mandatory if message is persistent and no other brokers available" do
1037
+ flexmock(RightScale::Log).should_receive(:info).with(/RE-ROUTE/).once
1038
+ flexmock(RightScale::Log).should_receive(:info).with(/RETURN reason/).once
1039
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
1040
+ @context.record_failure(@identity3)
1041
+ @context.record_failure(@identity4)
1042
+ @packet.should_receive(:persistent).and_return(true)
1043
+ @broker3.should_receive(:publish).and_return(true).once
1044
+ ha.__send__(:handle_return, @identity4, "NO_CONSUMERS", @message, "to", @context)
1045
+ end
1046
+
1047
+ it "should republish to same broker without mandatory if message is one-way and no other brokers available" do
1048
+ flexmock(RightScale::Log).should_receive(:info).with(/RE-ROUTE/).once
1049
+ flexmock(RightScale::Log).should_receive(:info).with(/RETURN reason/).once
1050
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
1051
+ @context.record_failure(@identity3)
1052
+ @context.record_failure(@identity4)
1053
+ @packet.should_receive(:one_way).and_return(true)
1054
+ @broker3.should_receive(:publish).and_return(true).once
1055
+ ha.__send__(:handle_return, @identity4, "NO_CONSUMERS", @message, "to", @context)
1056
+ end
1057
+
1058
+ it "should update status to :stopping if message returned because access refused" do
1059
+ flexmock(RightScale::Log).should_receive(:info).with(/RE-ROUTE/).once
1060
+ flexmock(RightScale::Log).should_receive(:info).with(/RETURN reason/).once
1061
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
1062
+ @context.record_failure(@identity3)
1063
+ @broker4.should_receive(:publish).and_return(true).once
1064
+ @broker3.should_receive(:update_status).with(:stopping).and_return(true).once
1065
+ ha.__send__(:handle_return, @identity3, "ACCESS_REFUSED", @message, "to", @context)
1066
+ end
1067
+
1068
+ it "should log info and make non-delivery call even if persistent when returned because of no queue" do
1069
+ flexmock(RightScale::Log).should_receive(:info).with(/NO ROUTE/).once
1070
+ flexmock(RightScale::Log).should_receive(:info).with(/RETURN reason/).once
1071
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
1072
+ called = 0
1073
+ ha.non_delivery { |reason, type, token, from, to| called += 1 }
1074
+ @context.record_failure(@identity3)
1075
+ @context.record_failure(@identity4)
1076
+ @packet.should_receive(:persistent).and_return(true)
1077
+ @broker3.should_receive(:publish).and_return(true).never
1078
+ @broker4.should_receive(:publish).and_return(true).never
1079
+ ha.__send__(:handle_return, @identity4, "NO_QUEUE", @message, "to", @context)
1080
+ called.should == 1
1081
+ end
1082
+
1083
+ it "should log info and make non-delivery call if no route can be found" do
1084
+ flexmock(RightScale::Log).should_receive(:info).with(/NO ROUTE/).once
1085
+ flexmock(RightScale::Log).should_receive(:info).with(/RETURN reason/).once
1086
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
1087
+ called = 0
1088
+ ha.non_delivery { |reason, type, token, from, to| called += 1 }
1089
+ @context.record_failure(@identity3)
1090
+ @context.record_failure(@identity4)
1091
+ @broker3.should_receive(:publish).and_return(true).never
1092
+ @broker4.should_receive(:publish).and_return(true).never
1093
+ ha.__send__(:handle_return, @identity4, "any reason", @message, "to", @context)
1094
+ called.should == 1
1095
+ end
1096
+
1097
+ it "should log info if no message context available for re-routing it" do
1098
+ flexmock(RightScale::Log).should_receive(:info).with(/Dropping/).once
1099
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
1100
+ ha.__send__(:handle_return, @identity4, "any reason", @message, "to", nil)
1101
+ end
1102
+
1103
+ end
1104
+
1105
+ end # returning
1106
+
1107
+ context "deleting" do
1108
+
1109
+ it "should delete queue on all usable broker clients and return their identities" do
1110
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
1111
+ @broker1.should_receive(:usable?).and_return(false)
1112
+ @broker1.should_receive(:delete).never
1113
+ @broker2.should_receive(:delete).and_return(true).once
1114
+ @broker3.should_receive(:delete).and_return(true).once
1115
+ @broker4.should_receive(:delete).and_return(true).once
1116
+ ha.delete("queue").should == [@identity3, @identity4, @identity2]
1117
+ end
1118
+
1119
+ it "should not return the identity if delete fails" do
1120
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
1121
+ @broker1.should_receive(:usable?).and_return(false)
1122
+ @broker1.should_receive(:delete).never
1123
+ @broker2.should_receive(:delete).and_return(true).once
1124
+ @broker3.should_receive(:delete).and_return(false).once
1125
+ @broker4.should_receive(:delete).and_return(true).once
1126
+ ha.delete("queue").should == [@identity4, @identity2]
1127
+ end
1128
+
1129
+ end # deleting
1130
+
1131
+ context "removing" do
1132
+
1133
+ it "should remove broker client after disconnecting and pass identity to block" do
1134
+ flexmock(RightScale::Log).should_receive(:info).with(/Removing/).once
1135
+ @broker2.should_receive(:close).with(true, true, false).once
1136
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
1137
+ identity = nil
1138
+ result = ha.remove("second", 5672) { |i| identity = i }
1139
+ result.should == @identity2
1140
+ identity.should == @identity2
1141
+ ha.get(@identity2).should be_nil
1142
+ ha.get(@identity1).should_not be_nil
1143
+ ha.get(@identity3).should_not be_nil
1144
+ ha.get("rs-broker-fourth-5672").should_not be_nil
1145
+ ha.brokers.size.should == 3
1146
+ end
1147
+
1148
+ it "should remove broker when no block supplied but still return a result" do
1149
+ flexmock(RightScale::Log).should_receive(:info).with(/Removing/).once
1150
+ @broker2.should_receive(:close).once
1151
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
1152
+ result = ha.remove("second", 5672)
1153
+ result.should == @identity2
1154
+ ha.get(@identity2).should be_nil
1155
+ ha.get(@identity1).should_not be_nil
1156
+ ha.get(@identity3).should_not be_nil
1157
+ ha.get(@identity4).should_not be_nil
1158
+ ha.brokers.size.should == 3
1159
+ end
1160
+
1161
+ it "should remove last broker if requested" do
1162
+ flexmock(RightScale::Log).should_receive(:info).with(/Removing/).times(4)
1163
+ @broker1.should_receive(:close).once
1164
+ @broker2.should_receive(:close).once
1165
+ @broker3.should_receive(:close).once
1166
+ @broker4.should_receive(:close).once
1167
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
1168
+ result = ha.remove("second", 5672)
1169
+ result.should == @identity2
1170
+ ha.get(@identity2).should be_nil
1171
+ result = ha.remove("third", 5672)
1172
+ result.should == @identity3
1173
+ ha.get(@identity3).should be_nil
1174
+ result = ha.remove("fourth", 5672)
1175
+ result.should == @identity4
1176
+ ha.get(@identity4).should be_nil
1177
+ ha.brokers.size.should == 1
1178
+ identity = nil
1179
+ result = ha.remove("first", 5672) { |i| identity = i }
1180
+ result.should == @identity1
1181
+ identity.should == @identity1
1182
+ ha.get(@identity1).should be_nil
1183
+ ha.brokers.size.should == 0
1184
+ end
1185
+
1186
+ it "should return nil and not execute block if broker is unknown" do
1187
+ flexmock(RightScale::Log).should_receive(:info).with(/Ignored request to remove/).once
1188
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
1189
+ ha.remove("fifth", 5672).should be_nil
1190
+ ha.brokers.size.should == 4
1191
+ end
1192
+
1193
+ it "should close connection and mark as failed when told broker is not usable" do
1194
+ @broker2.should_receive(:close).with(true, false, false).once
1195
+ @broker3.should_receive(:close).with(true, false, false).once
1196
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
1197
+ result = ha.declare_unusable([@identity2, @identity3])
1198
+ ha.brokers.size.should == 4
1199
+ end
1200
+
1201
+ it "should raise an exception if broker that is declared not usable is unknown" do
1202
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
1203
+ lambda { ha.declare_unusable(["rs-broker-fifth-5672"]) }.should raise_error(Exception, /Cannot mark unknown/)
1204
+ ha.brokers.size.should == 4
1205
+ end
1206
+
1207
+ end # removing
1208
+
1209
+ context "monitoring" do
1210
+
1211
+ include RightScale::StatsHelper
1212
+
1213
+ before(:each) do
1214
+ @timer = flexmock("timer")
1215
+ flexmock(EM::Timer).should_receive(:new).and_return(@timer).by_default
1216
+ @timer.should_receive(:cancel).by_default
1217
+ @identity = "rs-broker-localhost-5672"
1218
+ @address = {:host => "localhost", :port => 5672, :index => 0}
1219
+ @broker = flexmock("broker_client", :identity => @identity, :alias => "b0", :host => "localhost",
1220
+ :port => 5672, :index => 0, :island_id => nil, :in_home_island => true)
1221
+ @broker.should_receive(:status).and_return(:connected).by_default
1222
+ @broker.should_receive(:usable?).and_return(true).by_default
1223
+ @broker.should_receive(:connected?).and_return(true).by_default
1224
+ @broker.should_receive(:subscribe).and_return(true).by_default
1225
+ @broker.should_receive(:return_message).and_return(true).by_default
1226
+ flexmock(RightScale::BrokerClient).should_receive(:new).and_return(@broker).by_default
1227
+ @broker1.should_receive(:failed?).and_return(false).by_default
1228
+ @broker2.should_receive(:failed?).and_return(false).by_default
1229
+ @broker3.should_receive(:failed?).and_return(false).by_default
1230
+ @broker4.should_receive(:failed?).and_return(false).by_default
1231
+ end
1232
+
1233
+ it "should give access to or list usable brokers" do
1234
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
1235
+ aliases = []
1236
+ res = ha.__send__(:each_usable) { |b| aliases << b.alias }
1237
+ aliases.should == ["b0", "b1", "i0b0", "i0b1"]
1238
+ res.size.should == 4
1239
+ res[0].alias.should == "b0"
1240
+ res[1].alias.should == "b1"
1241
+ res[2].alias.should == "i0b0"
1242
+ res[3].alias.should == "i0b1"
1243
+
1244
+ @broker1.should_receive(:usable?).and_return(true)
1245
+ @broker2.should_receive(:usable?).and_return(false)
1246
+ @broker3.should_receive(:usable?).and_return(false)
1247
+ @broker4.should_receive(:usable?).and_return(false)
1248
+ aliases = []
1249
+ res = ha.__send__(:each_usable) { |b| aliases << b.alias }
1250
+ aliases.should == ["i0b0"]
1251
+ res.size.should == 1
1252
+ res[0].alias.should == "i0b0"
1253
+ end
1254
+
1255
+ it "should give list of unusable brokers" do
1256
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
1257
+ @broker1.should_receive(:usable?).and_return(true)
1258
+ @broker2.should_receive(:usable?).and_return(false)
1259
+ @broker3.should_receive(:usable?).and_return(false)
1260
+ @broker4.should_receive(:usable?).and_return(true)
1261
+ ha.unusable.should == [@identity3, @identity2]
1262
+ end
1263
+
1264
+ it "should give access to each selected usable broker" do
1265
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
1266
+ @broker2.should_receive(:usable?).and_return(true)
1267
+ @broker3.should_receive(:usable?).and_return(false)
1268
+ aliases = []
1269
+ res = ha.__send__(:each_usable, [@identity2, @identity3]) { |b| aliases << b.alias }
1270
+ aliases.should == ["i0b1"]
1271
+ res.size.should == 1
1272
+ res[0].alias.should == "i0b1"
1273
+ end
1274
+
1275
+ it "should tell whether a broker is connected" do
1276
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
1277
+ @broker2.should_receive(:connected?).and_return(false)
1278
+ @broker3.should_receive(:connected?).and_return(true)
1279
+ ha.connected?(@identity2).should be_false
1280
+ ha.connected?(@identity3).should be_true
1281
+ ha.connected?("rs-broker-fifth-5672").should be_nil
1282
+ end
1283
+
1284
+ it "should give list of connected brokers for home island by default" do
1285
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
1286
+ @broker1.should_receive(:connected?).and_return(true)
1287
+ @broker2.should_receive(:connected?).and_return(false)
1288
+ @broker3.should_receive(:connected?).and_return(true)
1289
+ @broker4.should_receive(:connected?).and_return(false)
1290
+ ha.connected.should == [@identity3]
1291
+ end
1292
+
1293
+ it "should give list of connected brokers for a specific island" do
1294
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
1295
+ @broker1.should_receive(:connected?).and_return(true)
1296
+ @broker2.should_receive(:connected?).and_return(false)
1297
+ @broker3.should_receive(:connected?).and_return(true)
1298
+ @broker4.should_receive(:connected?).and_return(false)
1299
+ ha.connected(11).should == [@identity1]
1300
+ ha.connected(22).should == [@identity3]
1301
+ end
1302
+
1303
+ it "should give list of all brokers" do
1304
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
1305
+ ha.all.should == [@identity3, @identity4, @identity1, @identity2]
1306
+ end
1307
+
1308
+ it "should give list of failed brokers" do
1309
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
1310
+ @broker1.should_receive(:failed?).and_return(true)
1311
+ @broker2.should_receive(:failed?).and_return(false)
1312
+ @broker3.should_receive(:failed?).and_return(true)
1313
+ @broker4.should_receive(:failed?).and_return(false)
1314
+ ha.failed.should == [@identity3, @identity1]
1315
+ end
1316
+
1317
+ it "should give broker client status list" do
1318
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
1319
+ @broker1.should_receive(:summary).and_return("summary1")
1320
+ @broker2.should_receive(:summary).and_return("summary2")
1321
+ @broker3.should_receive(:summary).and_return("summary3")
1322
+ @broker4.should_receive(:summary).and_return("summary4")
1323
+ ha.status.should == ["summary3", "summary4", "summary1", "summary2"]
1324
+ end
1325
+
1326
+ it "should give broker client statistics" do
1327
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
1328
+ @broker1.should_receive(:stats).and_return("stats1")
1329
+ @broker2.should_receive(:stats).and_return("stats2")
1330
+ @broker3.should_receive(:stats).and_return("stats3")
1331
+ @broker4.should_receive(:stats).and_return("stats4")
1332
+ ha.stats.should == {"brokers" => ["stats3", "stats4", "stats1", "stats2"],
1333
+ "exceptions" => nil,
1334
+ "returns" => nil}
1335
+ end
1336
+
1337
+ it "should log broker client status update if there is a change" do
1338
+ flexmock(RightScale::Log).should_receive(:info).with(/Broker b0 is now connected/).once
1339
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
1340
+ ha.__send__(:update_status, @broker3, false)
1341
+ end
1342
+
1343
+ it "should not log broker client status update if there is no change" do
1344
+ flexmock(RightScale::Log).should_receive(:info).with(/Broker b0 is now connected/).never
1345
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
1346
+ ha.__send__(:update_status, @broker3, true)
1347
+ end
1348
+
1349
+ it "should log broker client status update when become disconnected" do
1350
+ flexmock(RightScale::Log).should_receive(:info).with(/Broker b0 is now disconnected/).once
1351
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
1352
+ @broker3.should_receive(:status).and_return(:disconnected)
1353
+ @broker3.should_receive(:connected?).and_return(false)
1354
+ ha.__send__(:update_status, @broker3, true)
1355
+ end
1356
+
1357
+ it "should provide connection status callback when cross 0/1 connection boundary for home island" do
1358
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
1359
+ connected = 0
1360
+ disconnected = 0
1361
+ ha.connection_status do |status|
1362
+ if status == :connected
1363
+ (ha.brokers[0].status == :connected ||
1364
+ ha.brokers[1].status == :connected).should be_true
1365
+ connected += 1
1366
+ elsif status == :disconnected
1367
+ (ha.brokers[0].status == :disconnected &&
1368
+ ha.brokers[1].status == :disconnected).should be_true
1369
+ disconnected += 1
1370
+ end
1371
+ end
1372
+ ha.__send__(:update_status, @broker3, false)
1373
+ connected.should == 0
1374
+ disconnected.should == 0
1375
+ @broker3.should_receive(:status).and_return(:disconnected)
1376
+ @broker3.should_receive(:connected?).and_return(false)
1377
+ ha.__send__(:update_status, @broker3, true)
1378
+ connected.should == 0
1379
+ disconnected.should == 0
1380
+ @broker4.should_receive(:status).and_return(:disconnected)
1381
+ @broker4.should_receive(:connected?).and_return(false)
1382
+ ha.__send__(:update_status, @broker4, true)
1383
+ connected.should == 0
1384
+ disconnected.should == 1
1385
+ # TODO fix this test so that also checks crossing boundary as become connected
1386
+ end
1387
+
1388
+ it "should provide connection status callback when cross n/n-1 connection boundary for home island when all specified" do
1389
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
1390
+ connected = 0
1391
+ disconnected = 0
1392
+ ha.connection_status(:boundary => :all) do |status|
1393
+ if status == :connected
1394
+ (ha.brokers[0].status == :connected &&
1395
+ ha.brokers[1].status == :connected).should be_true
1396
+ connected += 1
1397
+ elsif status == :disconnected
1398
+ (ha.brokers[0].status == :disconnected ||
1399
+ ha.brokers[1].status == :disconnected).should be_true
1400
+ disconnected += 1
1401
+ end
1402
+ end
1403
+ ha.__send__(:update_status, @broker3, false)
1404
+ connected.should == 1
1405
+ disconnected.should == 0
1406
+ @broker3.should_receive(:status).and_return(:disconnected)
1407
+ @broker3.should_receive(:connected?).and_return(false)
1408
+ ha.__send__(:update_status, @broker3, true)
1409
+ connected.should == 1
1410
+ disconnected.should == 1
1411
+ @broker4.should_receive(:status).and_return(:disconnected)
1412
+ @broker4.should_receive(:connected?).and_return(false)
1413
+ ha.__send__(:update_status, @broker4, true)
1414
+ connected.should == 1
1415
+ disconnected.should == 1
1416
+ # TODO fix this test so that also checks crossing boundary as become disconnected
1417
+ end
1418
+
1419
+ it "should provide connection status callback when cross connection boundary for non-home island" do
1420
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
1421
+ @broker1.should_receive(:island_alias).and_return(:i0)
1422
+ @broker2.should_receive(:island_alias).and_return(:i0)
1423
+ connected = 0
1424
+ disconnected = 0
1425
+ ha.connection_status do |status|
1426
+ if status == :connected
1427
+ (ha.brokers[2].status == :connected ||
1428
+ ha.brokers[3].status == :connected).should be_true
1429
+ connected += 1
1430
+ elsif status == :disconnected
1431
+ (ha.brokers[2].status == :disconnected &&
1432
+ ha.brokers[3].status == :disconnected).should be_true
1433
+ disconnected += 1
1434
+ end
1435
+ end
1436
+ ha.__send__(:update_status, @broker1, false)
1437
+ connected.should == 0
1438
+ disconnected.should == 0
1439
+ @broker1.should_receive(:status).and_return(:disconnected)
1440
+ @broker1.should_receive(:connected?).and_return(false)
1441
+ ha.__send__(:update_status, @broker1, true)
1442
+ connected.should == 0
1443
+ disconnected.should == 0
1444
+ @broker2.should_receive(:status).and_return(:disconnected)
1445
+ @broker2.should_receive(:connected?).and_return(false)
1446
+ ha.__send__(:update_status, @broker2, true)
1447
+ connected.should == 0
1448
+ disconnected.should == 1
1449
+ end
1450
+
1451
+ it "should provide connection status callback for specific broker set" do
1452
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
1453
+ @broker1.should_receive(:island_alias).and_return(:i0)
1454
+ @broker2.should_receive(:island_alias).and_return(:i0)
1455
+ connected = 0
1456
+ disconnected = 0
1457
+ ha.connection_status(:brokers => [@identity1, @identity2]) do |status|
1458
+ if status == :connected
1459
+ (ha.brokers[2].status == :connected ||
1460
+ ha.brokers[3].status == :connected).should be_true
1461
+ connected += 1
1462
+ elsif status == :disconnected
1463
+ (ha.brokers[2].status == :disconnected &&
1464
+ ha.brokers[3].status == :disconnected).should be_true
1465
+ disconnected += 1
1466
+ end
1467
+ end
1468
+ ha.__send__(:update_status, @broker1, false)
1469
+ connected.should == 0
1470
+ disconnected.should == 0
1471
+ @broker1.should_receive(:status).and_return(:disconnected)
1472
+ @broker1.should_receive(:connected?).and_return(false)
1473
+ ha.__send__(:update_status, @broker1, true)
1474
+ connected.should == 0
1475
+ disconnected.should == 0
1476
+ @broker2.should_receive(:status).and_return(:disconnected)
1477
+ @broker2.should_receive(:connected?).and_return(false)
1478
+ ha.__send__(:update_status, @broker2, true)
1479
+ connected.should == 0
1480
+ disconnected.should == 1
1481
+ end
1482
+
1483
+ it "should provide connection status callback only once when one-off is requested" do
1484
+ flexmock(RightScale::BrokerClient).should_receive(:new).with(@identity, @address, @serializer,
1485
+ @exceptions, Hash, nil, nil).and_return(@broker).once
1486
+ ha = RightScale::HABrokerClient.new(@serializer)
1487
+ called = 0
1488
+ ha.connection_status(:one_off => 10) { |_| called += 1 }
1489
+ ha.__send__(:update_status, @broker, false)
1490
+ called.should == 1
1491
+ @broker.should_receive(:status).and_return(:disconnected)
1492
+ @broker.should_receive(:connected?).and_return(false)
1493
+ ha.__send__(:update_status, @broker, true)
1494
+ called.should == 1
1495
+ end
1496
+
1497
+ it "should use connection status timer when one-off is requested" do
1498
+ flexmock(EM::Timer).should_receive(:new).and_return(@timer).once
1499
+ @timer.should_receive(:cancel).once
1500
+ flexmock(RightScale::BrokerClient).should_receive(:new).with(@identity, @address, @serializer,
1501
+ @exceptions, Hash, nil, nil).and_return(@broker).once
1502
+ ha = RightScale::HABrokerClient.new(@serializer)
1503
+ called = 0
1504
+ ha.connection_status(:one_off => 10) { |_| called += 1 }
1505
+ ha.__send__(:update_status, @broker, false)
1506
+ called.should == 1
1507
+ end
1508
+
1509
+ it "should give timeout connection status if one-off request times out" do
1510
+ flexmock(EM::Timer).should_receive(:new).and_return(@timer).and_yield.once
1511
+ @timer.should_receive(:cancel).never
1512
+ flexmock(RightScale::BrokerClient).should_receive(:new).with(@identity, @address, @serializer,
1513
+ @exceptions, Hash, nil, nil).and_return(@broker).once
1514
+ ha = RightScale::HABrokerClient.new(@serializer)
1515
+ called = 0
1516
+ ha.connection_status(:one_off => 10) { |status| called += 1; status.should == :timeout }
1517
+ called.should == 1
1518
+ end
1519
+
1520
+ it "should be able to have multiple connection status callbacks" do
1521
+ flexmock(RightScale::BrokerClient).should_receive(:new).with(@identity, @address, @serializer,
1522
+ @exceptions, Hash, nil, nil).and_return(@broker).once
1523
+ ha = RightScale::HABrokerClient.new(@serializer)
1524
+ called1 = 0
1525
+ called2 = 0
1526
+ ha.connection_status(:one_off => 10) { |_| called1 += 1 }
1527
+ ha.connection_status(:boundary => :all) { |_| called2 += 1 }
1528
+ ha.__send__(:update_status, @broker, false)
1529
+ @broker.should_receive(:status).and_return(:disconnected)
1530
+ @broker.should_receive(:connected?).and_return(false)
1531
+ ha.__send__(:update_status, @broker, true)
1532
+ called1.should == 1
1533
+ called2.should == 2
1534
+ end
1535
+
1536
+ it "should provide failed connection status callback when all brokers fail to connect" do
1537
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
1538
+ connected = disconnected = failed = 0
1539
+ ha.connection_status(:boundary => :all) do |status|
1540
+ if status == :connected
1541
+ connected += 1
1542
+ elsif status == :disconnected
1543
+ disconnected += 1
1544
+ elsif status == :failed
1545
+ (ha.brokers[0].failed? &&
1546
+ ha.brokers[1].failed? &&
1547
+ ha.brokers[2].failed? &&
1548
+ ha.brokers[3].failed?).should be_true
1549
+ failed += 1
1550
+ end
1551
+ end
1552
+ @broker1.should_receive(:failed?).and_return(true)
1553
+ @broker1.should_receive(:connected?).and_return(false)
1554
+ ha.__send__(:update_status, @broker1, false)
1555
+ connected.should == 0
1556
+ disconnected.should == 0
1557
+ failed.should == 0
1558
+ @broker2.should_receive(:failed?).and_return(true)
1559
+ @broker2.should_receive(:connected?).and_return(false)
1560
+ ha.__send__(:update_status, @broker2, false)
1561
+ connected.should == 0
1562
+ disconnected.should == 0
1563
+ failed.should == 0
1564
+ @broker3.should_receive(:failed?).and_return(true)
1565
+ @broker3.should_receive(:connected?).and_return(false)
1566
+ ha.__send__(:update_status, @broker3, false)
1567
+ connected.should == 0
1568
+ disconnected.should == 0
1569
+ failed.should == 0
1570
+ @broker4.should_receive(:failed?).and_return(true)
1571
+ @broker4.should_receive(:connected?).and_return(false)
1572
+ ha.__send__(:update_status, @broker4, false)
1573
+ connected.should == 0
1574
+ disconnected.should == 0
1575
+ failed.should == 1
1576
+ end
1577
+
1578
+ it "should provide failed connection status callback when brokers selected and all brokers fail to connect" do
1579
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
1580
+ connected = disconnected = failed = 0
1581
+ ha.connection_status(:boundary => :all, :brokers => [@broker3.identity, @broker4.identity]) do |status|
1582
+ if status == :connected
1583
+ connected += 1
1584
+ elsif status == :disconnected
1585
+ disconnected += 1
1586
+ elsif status == :failed
1587
+ (ha.brokers[0].failed? &&
1588
+ ha.brokers[1].failed?).should be_true
1589
+ failed += 1
1590
+ end
1591
+ end
1592
+ @broker1.should_receive(:failed?).and_return(true)
1593
+ @broker2.should_receive(:failed?).and_return(true)
1594
+ @broker3.should_receive(:failed?).and_return(true)
1595
+ @broker3.should_receive(:connected?).and_return(false)
1596
+ ha.__send__(:update_status, @broker3, false)
1597
+ connected.should == 0
1598
+ disconnected.should == 0
1599
+ failed.should == 0
1600
+ @broker4.should_receive(:failed?).and_return(true)
1601
+ @broker4.should_receive(:connected?).and_return(false)
1602
+ ha.__send__(:update_status, @broker4, false)
1603
+ connected.should == 0
1604
+ disconnected.should == 0
1605
+ failed.should == 1
1606
+ end
1607
+
1608
+ end # monitoring
1609
+
1610
+ context "closing" do
1611
+
1612
+ it "should close all broker connections and execute block after all connections are closed" do
1613
+ @broker1.should_receive(:close).with(false, Proc).and_return(true).and_yield.once
1614
+ @broker2.should_receive(:close).with(false, Proc).and_return(true).and_yield.once
1615
+ @broker3.should_receive(:close).with(false, Proc).and_return(true).and_yield.once
1616
+ @broker4.should_receive(:close).with(false, Proc).and_return(true).and_yield.once
1617
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
1618
+ called = 0
1619
+ ha.close { called += 1 }
1620
+ called.should == 1
1621
+ end
1622
+
1623
+ it "should close broker connections when no block supplied" do
1624
+ @broker1.should_receive(:close).with(false, Proc).and_return(true).and_yield.once
1625
+ @broker2.should_receive(:close).with(false, Proc).and_return(true).and_yield.once
1626
+ @broker3.should_receive(:close).with(false, Proc).and_return(true).and_yield.once
1627
+ @broker4.should_receive(:close).with(false, Proc).and_return(true).and_yield.once
1628
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
1629
+ ha.close
1630
+ end
1631
+
1632
+ it "should close all broker connections even if encounter an exception" do
1633
+ flexmock(RightScale::Log).should_receive(:error).with(/Failed to close/, Exception, :trace).once
1634
+ @broker1.should_receive(:close).and_return(true).and_yield.once
1635
+ @broker2.should_receive(:close).and_raise(Exception).once
1636
+ @broker3.should_receive(:close).and_return(true).and_yield.once
1637
+ @broker4.should_receive(:close).and_return(true).and_yield.once
1638
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
1639
+ called = 0
1640
+ ha.close { called += 1 }
1641
+ called.should == 1
1642
+ end
1643
+
1644
+ it "should close an individual broker connection" do
1645
+ @broker1.should_receive(:close).with(true).and_return(true).once
1646
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
1647
+ ha.close_one(@identity1)
1648
+ end
1649
+
1650
+ it "should not propagate connection status change if requested not to" do
1651
+ @broker1.should_receive(:close).with(false).and_return(true).once
1652
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
1653
+ ha.close_one(@identity1, propagate = false)
1654
+ end
1655
+
1656
+ it "should close an individual broker connection and execute block if given" do
1657
+ @broker1.should_receive(:close).with(true, Proc).and_return(true).and_yield.once
1658
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
1659
+ called = 0
1660
+ ha.close_one(@identity1) { called += 1 }
1661
+ called.should == 1
1662
+ end
1663
+
1664
+ it "should raise exception if unknown broker" do
1665
+ ha = RightScale::HABrokerClient.new(@serializer, :islands => @islands, :home_island => @home)
1666
+ lambda { ha.close_one("rs-broker-fifth-5672") }.should raise_error(Exception, /Cannot close unknown broker/)
1667
+ end
1668
+
1669
+ end # closing
1670
+
1671
+ end # when
1672
+
1673
+ end # RightScale::HABrokerClient