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,961 @@
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::BrokerClient 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
+ @serializer = flexmock("serializer")
34
+ @exceptions = flexmock("exception_stats")
35
+ @exceptions.should_receive(:track).never.by_default
36
+ @connection = flexmock("connection")
37
+ @connection.should_receive(:connection_status).by_default
38
+ flexmock(AMQP).should_receive(:connect).and_return(@connection).by_default
39
+ @mq = flexmock("mq")
40
+ @mq.should_receive(:connection).and_return(@connection).by_default
41
+ @identity = "rs-broker-localhost-5672"
42
+ @address = {:host => "localhost", :port => 5672, :index => 0}
43
+ @options = {}
44
+ end
45
+
46
+ context "when initializing connection" do
47
+
48
+ before(:each) do
49
+ @amqp = flexmock(AMQP)
50
+ @amqp.should_receive(:connect).and_return(@connection).by_default
51
+ @mq.should_receive(:prefetch).never.by_default
52
+ flexmock(MQ).should_receive(:new).with(@connection).and_return(@mq).by_default
53
+ @island = flexmock("island", :id => 2, :broker_hosts => "local_host").by_default
54
+ end
55
+
56
+ it "should create a broker with AMQP connection for specified address" do
57
+ @amqp.should_receive(:connect).with(hsh(:user => "user", :pass => "pass", :vhost => "vhost", :host => "localhost",
58
+ :port => 5672, :insist => true, :reconnect_interval => 10)).and_return(@connection).once
59
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, {:user => "user",
60
+ :pass => "pass", :vhost => "vhost", :insist => true,
61
+ :reconnect_interval => 10})
62
+ broker.host.should == "localhost"
63
+ broker.port.should == 5672
64
+ broker.index.should == 0
65
+ broker.queues.should == []
66
+ broker.island_id.should be_nil
67
+ broker.island_alias.should == ""
68
+ broker.in_home_island.should be_true
69
+ broker.summary.should == {:alias => "b0", :identity => @identity, :status => :connecting,
70
+ :disconnects => 0, :failures => 0, :retries => 0}
71
+ broker.usable?.should be_true
72
+ broker.connected?.should be_false
73
+ broker.failed?.should be_false
74
+ end
75
+
76
+ it "should recognize the home island" do
77
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions,
78
+ {:home_island => 2}, @island)
79
+ broker.host.should == "localhost"
80
+ broker.port.should == 5672
81
+ broker.index.should == 0
82
+ broker.queues.should == []
83
+ broker.island_id.should == 2
84
+ broker.island_alias.should == "i2"
85
+ broker.in_home_island.should be_true
86
+ broker.summary.should == {:alias => "b0", :identity => @identity, :status => :connecting,
87
+ :disconnects => 0, :failures => 0, :retries => 0}
88
+ end
89
+
90
+ it "should use island information when not home island" do
91
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions,
92
+ {:home_island => 1}, @island)
93
+ broker.host.should == "localhost"
94
+ broker.port.should == 5672
95
+ broker.index.should == 0
96
+ broker.queues.should == []
97
+ broker.island_id.should == 2
98
+ broker.island_alias.should == "i2"
99
+ broker.in_home_island.should be_false
100
+ broker.summary.should == {:alias => "i2b0", :identity => @identity, :status => :connecting,
101
+ :disconnects => 0, :failures => 0, :retries => 0}
102
+ end
103
+
104
+ it "should update state from existing client for given broker" do
105
+ existing = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
106
+ existing.__send__(:update_status, :disconnected)
107
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options, nil, existing)
108
+ broker.summary.should == {:alias => "b0", :identity => @identity, :status => :connecting,
109
+ :disconnects => 1, :failures => 0, :retries => 0}
110
+ end
111
+
112
+ it "should log an info message when it creates an AMQP connection" do
113
+ flexmock(RightScale::Log).should_receive(:info).with(/Connecting to broker/).once
114
+ RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
115
+ end
116
+
117
+ it "should log an error and set status to :failed if it fails to create an AMQP connection" do
118
+ @exceptions.should_receive(:track).once
119
+ @connection.should_receive(:close).once
120
+ flexmock(RightScale::Log).should_receive(:info).once
121
+ flexmock(RightScale::Log).should_receive(:error).with(/Failed connecting/, Exception, :trace).once
122
+ flexmock(MQ).should_receive(:new).with(@connection).and_raise(Exception)
123
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
124
+ broker.summary.should == {:alias => "b0", :identity => @identity, :status => :failed,
125
+ :disconnects => 0, :failures => 1, :retries => 0}
126
+ end
127
+
128
+ it "should set initialize connection status callback" do
129
+ @connection.should_receive(:connection_status).once
130
+ RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
131
+ end
132
+
133
+ it "should set broker prefetch value if specified" do
134
+ @mq.should_receive(:prefetch).with(1).once
135
+ RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, {:prefetch => 1})
136
+ end
137
+
138
+ end # when initializing connection
139
+
140
+ context "when subscribing" do
141
+
142
+ before(:each) do
143
+ @info = flexmock("info", :ack => true).by_default
144
+ @message = flexmock("message")
145
+ @packet = flexmock("packet", :class => RightScale::Request, :to_s => true, :version => [12, 12]).by_default
146
+ @serializer.should_receive(:load).with(@message).and_return(@packet).by_default
147
+ @direct = flexmock("direct")
148
+ @fanout = flexmock("fanout")
149
+ @bind = flexmock("bind")
150
+ @queue = flexmock("queue")
151
+ @queue.should_receive(:bind).and_return(@bind).by_default
152
+ @mq.should_receive(:queue).and_return(@queue).by_default
153
+ @mq.should_receive(:direct).and_return(@direct).by_default
154
+ @mq.should_receive(:fanout).and_return(@fanout).by_default
155
+ flexmock(MQ).should_receive(:new).with(@connection).and_return(@mq).by_default
156
+ end
157
+
158
+ it "should subscribe queue to exchange" do
159
+ @queue.should_receive(:bind).and_return(@bind).once
160
+ @bind.should_receive(:subscribe).once
161
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
162
+ broker.__send__(:update_status, :ready)
163
+ broker.subscribe({:name => "queue"}, {:type => :direct, :name => "exchange"}) {|_, _|}
164
+ end
165
+
166
+ it "should subscribe queue to second exchange if specified" do
167
+ @queue.should_receive(:bind).and_return(@bind).twice
168
+ @bind.should_receive(:subscribe).once
169
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
170
+ broker.__send__(:update_status, :ready)
171
+ options = {:exchange2 => {:type => :fanout, :name => "exchange2", :options => {:durable => true}}}
172
+ broker.subscribe({:name => "queue"}, {:type => :direct, :name => "exchange"}, options) {|_, _|}
173
+ end
174
+
175
+ it "should subscribe queue to exchange when still connecting" do
176
+ @bind.should_receive(:subscribe).once
177
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
178
+ broker.subscribe({:name => "queue"}, {:type => :direct, :name => "exchange"}) {|_, _|}
179
+ end
180
+
181
+ it "should subscribe queue to empty exchange if no exchange specified" do
182
+ @queue.should_receive(:subscribe).once
183
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
184
+ broker.__send__(:update_status, :ready)
185
+ broker.subscribe({:name => "queue"}) {|b, p| p.should == nil}
186
+ end
187
+
188
+ it "should store queues for future reference" do
189
+ @bind.should_receive(:subscribe).once
190
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
191
+ broker.subscribe({:name => "queue"}, {:type => :direct, :name => "exchange"})
192
+ broker.queues.should == [@queue]
193
+ end
194
+
195
+ it "should return true if subscribed successfully" do
196
+ @bind.should_receive(:subscribe).and_yield(@message).once
197
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
198
+ result = broker.subscribe({:name => "queue"}, {:type => :direct, :name => "exchange"},
199
+ RightScale::Request => true) {|b, p| p.should == @packet}
200
+ result.should be_true
201
+ end
202
+
203
+ it "should return true if already subscribed and not try to resubscribe" do
204
+ @queue.should_receive(:name).and_return("queue").once
205
+ @bind.should_receive(:subscribe).and_yield(@message).once
206
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
207
+ result = broker.subscribe({:name => "queue"}, {:type => :direct, :name => "exchange"},
208
+ RightScale::Request => true) {|b, p| p.should == @packet}
209
+ result.should be_true
210
+ result = broker.subscribe({:name => "queue"}, {:type => :direct, :name => "exchange"}) {|_, _|}
211
+ result.should be_true
212
+ end
213
+
214
+ it "should ack received message if requested" do
215
+ @info.should_receive(:ack).once
216
+ @bind.should_receive(:subscribe).and_yield(@info, @message).once
217
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
218
+ broker.__send__(:update_status, :ready)
219
+ result = broker.subscribe({:name => "queue"}, {:type => :direct, :name => "exchange"},
220
+ :ack => true, RightScale::Request => true) {|b, p| p.should == @packet}
221
+ result.should be_true
222
+ end
223
+
224
+ it "should return false if client not usable" do
225
+ @queue.should_receive(:bind).and_return(@bind).never
226
+ @bind.should_receive(:subscribe).never
227
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
228
+ broker.__send__(:update_status, :disconnected)
229
+ broker.subscribe({:name => "queue"}).should be_false
230
+ end
231
+
232
+ it "should receive message causing it to be unserialized and logged" do
233
+ flexmock(RightScale::Log).should_receive(:info).with(/Connecting/).once
234
+ flexmock(RightScale::Log).should_receive(:info).with(/Subscribing/).once
235
+ flexmock(RightScale::Log).should_receive(:info).with(/RECV/).once
236
+ @serializer.should_receive(:load).with(@message).and_return(@packet).once
237
+ @bind.should_receive(:subscribe).and_yield(@message).once
238
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
239
+ broker.__send__(:update_status, :ready)
240
+ broker.subscribe({:name => "queue"}, {:type => :direct, :name => "exchange"},
241
+ RightScale::Request => nil) {|b, p| p.class.should == RightScale::Request}
242
+ end
243
+
244
+ it "should receive message and log exception if subscribe block fails" do
245
+ flexmock(RightScale::Log).should_receive(:info).with(/Connecting/).once
246
+ flexmock(RightScale::Log).should_receive(:info).with(/Subscribing/).once
247
+ flexmock(RightScale::Log).should_receive(:error).with(/Failed executing block/, Exception, :trace).once
248
+ @exceptions.should_receive(:track).once
249
+ @serializer.should_receive(:load).with(@message).and_return(@packet).once
250
+ @bind.should_receive(:subscribe).and_yield(@message).once
251
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
252
+ broker.__send__(:update_status, :ready)
253
+ result = broker.subscribe({:name => "queue"}, {:type => :direct, :name => "exchange"},
254
+ RightScale::Request => nil) {|b, p| raise Exception}
255
+ result.should be_false
256
+ end
257
+
258
+ it "should ignore 'nil' message when using ack" do
259
+ flexmock(RightScale::Log).should_receive(:level).and_return(:debug)
260
+ flexmock(RightScale::Log).should_receive(:info).with(/Connecting/).once
261
+ flexmock(RightScale::Log).should_receive(:info).with(/Subscribing/).once
262
+ flexmock(RightScale::Log).should_receive(:debug).with(/nil message ignored/).once
263
+ @bind.should_receive(:subscribe).and_yield(@info, "nil").once
264
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
265
+ broker.__send__(:update_status, :ready)
266
+ called = 0
267
+ broker.subscribe({:name => "queue"}, {:type => :direct, :name => "exchange"}, :ack => true) { |b, m| called += 1 }
268
+ called.should == 0
269
+ end
270
+
271
+ it "should ignore 'nil' message when not using ack" do
272
+ flexmock(RightScale::Log).should_receive(:level).and_return(:debug)
273
+ flexmock(RightScale::Log).should_receive(:info).with(/Connecting/).once
274
+ flexmock(RightScale::Log).should_receive(:info).with(/Subscribing/).once
275
+ flexmock(RightScale::Log).should_receive(:debug).with(/nil message ignored/).once
276
+ @bind.should_receive(:subscribe).and_yield("nil").once
277
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
278
+ broker.__send__(:update_status, :ready)
279
+ called = 0
280
+ broker.subscribe({:name => "queue"}, {:type => :direct, :name => "exchange"}) { |b, m| called += 1 }
281
+ called.should == 0
282
+ end
283
+
284
+ it "should not unserialize the message if requested" do
285
+ flexmock(RightScale::Log).should_receive(:info).with(/Connecting/).once
286
+ flexmock(RightScale::Log).should_receive(:info).with(/Subscribing/).once
287
+ flexmock(RightScale::Log).should_receive(:info).with(/^RECV/).never
288
+ @bind.should_receive(:subscribe).and_yield(@message).once
289
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
290
+ broker.__send__(:update_status, :ready)
291
+ broker.subscribe({:name => "queue"}, {:type => :direct, :name => "exchange"}, :no_unserialize => true) do |b, m|
292
+ b.should == "rs-broker-localhost-5672"
293
+ m.should == @message
294
+ end
295
+ end
296
+
297
+ it "should log an error if a subscribe fails" do
298
+ flexmock(RightScale::Log).should_receive(:info).with(/Connecting/).once
299
+ flexmock(RightScale::Log).should_receive(:info).with(/RECV/).never
300
+ flexmock(RightScale::Log).should_receive(:error).with(/Failed subscribing/, Exception, :trace).once
301
+ @exceptions.should_receive(:track).once
302
+ @bind.should_receive(:subscribe).and_raise(Exception)
303
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
304
+ broker.__send__(:update_status, :ready)
305
+ result = broker.subscribe({:name => "queue"}, {:type => :direct, :name => "exchange"}) {|b, p|}
306
+ result.should be_false
307
+ end
308
+
309
+ end # when subscribing
310
+
311
+ context "when receiving" do
312
+
313
+ before(:each) do
314
+ @message = flexmock("message")
315
+ @packet = flexmock("packet", :class => RightScale::Request, :to_s => true, :version => [12, 12]).by_default
316
+ @serializer.should_receive(:load).with(@message).and_return(@packet).once.by_default
317
+ end
318
+
319
+ it "should unserialize the message, log it, and return it" do
320
+ flexmock(RightScale::Log).should_receive(:info).with(/Connecting/).once
321
+ flexmock(RightScale::Log).should_receive(:info).with(/^RECV/).once
322
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
323
+ broker.__send__(:receive, "queue", @message, RightScale::Request => nil).should == @packet
324
+ end
325
+
326
+ it "should log a warning if the message is not of the right type and return nil" do
327
+ flexmock(RightScale::Log).should_receive(:warning).with(/Received invalid.*packet type/).once
328
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
329
+ broker.__send__(:receive, "queue", @message).should be_nil
330
+ end
331
+
332
+ it "should show the category in the warning message if specified" do
333
+ flexmock(RightScale::Log).should_receive(:warning).with(/Received invalid xxxx packet type/).once
334
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
335
+ broker.__send__(:receive, "queue", @message, RightScale::Result => nil, :category => "xxxx")
336
+ end
337
+
338
+ it "should display broker alias in the log" do
339
+ flexmock(RightScale::Log).should_receive(:info).with(/Connecting/).once
340
+ flexmock(RightScale::Log).should_receive(:info).with(/^RECV b0 /).once
341
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
342
+ broker.__send__(:receive, "queue", @message, RightScale::Request => nil)
343
+ end
344
+
345
+ it "should filter the packet display for :info level" do
346
+ flexmock(RightScale::Log).should_receive(:info).with(/Connecting/).once
347
+ flexmock(RightScale::Log).should_receive(:info).with(/^RECV.*TO YOU/).once
348
+ flexmock(RightScale::Log).should_receive(:debug).with(/^RECV.*TO YOU/).never
349
+ @packet.should_receive(:to_s).with([:to], :recv_version).and_return("TO YOU").once
350
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
351
+ broker.__send__(:receive, "queue", @message, RightScale::Request => [:to])
352
+ end
353
+
354
+ it "should not filter the packet display for :debug level" do
355
+ flexmock(RightScale::Log).should_receive(:level).and_return(:debug)
356
+ flexmock(RightScale::Log).should_receive(:info).with(/Connecting/).once
357
+ flexmock(RightScale::Log).should_receive(:info).with(/^RECV.*ALL/).never
358
+ flexmock(RightScale::Log).should_receive(:info).with(/^RECV.*ALL/).once
359
+ @packet.should_receive(:to_s).with(nil, :recv_version).and_return("ALL").once
360
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
361
+ broker.__send__(:receive, "queue", @message, RightScale::Request => [:to])
362
+ end
363
+
364
+ it "should display additional data in log" do
365
+ flexmock(RightScale::Log).should_receive(:info).with(/Connecting/).once
366
+ flexmock(RightScale::Log).should_receive(:info).with(/^RECV.*More data/).once
367
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
368
+ broker.__send__(:receive, "queue", @message, RightScale::Request => nil, :log_data => "More data")
369
+ end
370
+
371
+ it "should not log a message if requested not to" do
372
+ flexmock(RightScale::Log).should_receive(:info).with(/Connecting/).once
373
+ flexmock(RightScale::Log).should_receive(:info).with(/^RECV/).never
374
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
375
+ broker.__send__(:receive, "queue", @message, RightScale::Request => nil, :no_log => true)
376
+ end
377
+
378
+ it "should not log a message if requested not to unless debug level" do
379
+ flexmock(RightScale::Log).should_receive(:level).and_return(:debug)
380
+ flexmock(RightScale::Log).should_receive(:info).with(/Connecting/).once
381
+ flexmock(RightScale::Log).should_receive(:info).with(/^RECV/).once
382
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
383
+ broker.__send__(:receive, "queue", @message, RightScale::Request => nil, :no_log => true)
384
+ end
385
+
386
+ it "should log an error if exception prevents normal logging and should then return nil" do
387
+ flexmock(RightScale::Log).should_receive(:error).with(/Failed receiving from queue/, Exception, :trace).once
388
+ @serializer.should_receive(:load).with(@message).and_raise(Exception).once
389
+ @exceptions.should_receive(:track).once
390
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
391
+ broker.__send__(:receive, "queue", @message).should be_nil
392
+ end
393
+
394
+ it "should make callback when there is a receive failure" do
395
+ flexmock(RightScale::Log).should_receive(:error).with(/Failed receiving from queue/, Exception, :trace).once
396
+ @serializer.should_receive(:load).with(@message).and_raise(Exception).once
397
+ @exceptions.should_receive(:track).once
398
+ called = 0
399
+ callback = lambda { |msg, e| called += 1 }
400
+ options = {:exception_on_receive_callback => callback}
401
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, options)
402
+ broker.__send__(:receive, "queue", @message).should be_nil
403
+ called.should == 1
404
+ end
405
+
406
+ it "should display RE-RECV if the message being received is a retry" do
407
+ flexmock(RightScale::Log).should_receive(:info).with(/Connecting/).once
408
+ flexmock(RightScale::Log).should_receive(:info).with(/^RE-RECV/).once
409
+ @packet.should_receive(:tries).and_return(["try1"]).once
410
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
411
+ broker.__send__(:receive, "queue", @message, RightScale::Request => nil).should == @packet
412
+ end
413
+
414
+ end # when receiving
415
+
416
+ context "when unsubscribing" do
417
+
418
+ before(:each) do
419
+ @direct = flexmock("direct")
420
+ @bind = flexmock("bind", :subscribe => true)
421
+ @queue = flexmock("queue", :bind => @bind, :name => "queue1")
422
+ @mq.should_receive(:queue).and_return(@queue).by_default
423
+ @mq.should_receive(:direct).and_return(@direct).by_default
424
+ flexmock(MQ).should_receive(:new).with(@connection).and_return(@mq).by_default
425
+ end
426
+
427
+ it "should unsubscribe a queue by name" do
428
+ @queue.should_receive(:unsubscribe).once
429
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
430
+ broker.subscribe({:name => "queue1"}, {:type => :direct, :name => "exchange"})
431
+ broker.unsubscribe(["queue1"])
432
+ end
433
+
434
+ it "should ignore unsubscribe if queue unknown" do
435
+ @queue.should_receive(:unsubscribe).never
436
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
437
+ broker.subscribe({:name => "queue1"}, {:type => :direct, :name => "exchange"})
438
+ broker.unsubscribe(["queue2"])
439
+ end
440
+
441
+ it "should activate block after unsubscribing if provided" do
442
+ @queue.should_receive(:unsubscribe).and_yield.once
443
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
444
+ broker.subscribe({:name => "queue1"}, {:type => :direct, :name => "exchange"})
445
+ called = 0
446
+ broker.unsubscribe(["queue1"]) { called += 1 }
447
+ called.should == 1
448
+ end
449
+
450
+ it "should ignore the request if client not usable" do
451
+ @queue.should_receive(:unsubscribe).and_yield.never
452
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
453
+ broker.subscribe({:name => "queue1"}, {:type => :direct, :name => "exchange"})
454
+ broker.__send__(:update_status, :disconnected)
455
+ broker.unsubscribe(["queue1"])
456
+ end
457
+
458
+ it "should log an error if unsubscribe raises an exception and activate block if provided" do
459
+ flexmock(RightScale::Log).should_receive(:error).with(/Failed unsubscribing/, Exception, :trace).once
460
+ @queue.should_receive(:unsubscribe).and_raise(Exception).once
461
+ @exceptions.should_receive(:track).once
462
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
463
+ broker.subscribe({:name => "queue1"}, {:type => :direct, :name => "exchange"})
464
+ called = 0
465
+ broker.unsubscribe(["queue1"]) { called += 1 }
466
+ called.should == 1
467
+ end
468
+
469
+ end # when unsubscribing
470
+
471
+ context "when declaring" do
472
+
473
+ before(:each) do
474
+ flexmock(MQ).should_receive(:new).with(@connection).and_return(@mq).by_default
475
+ @mq.should_receive(:queues).and_return({}).by_default
476
+ @mq.should_receive(:exchanges).and_return({}).by_default
477
+ end
478
+
479
+ it "should declare exchange and return true" do
480
+ @mq.should_receive(:exchange).once
481
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
482
+ broker.declare(:exchange, "x", :durable => true).should be_true
483
+ end
484
+
485
+ it "should delete the exchange or queue from the AMQP cache before declaring" do
486
+ @mq.should_receive(:queue).once
487
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
488
+ flexmock(broker).should_receive(:delete_from_cache).with(:queue, "queue").once
489
+ broker.declare(:queue, "queue", :durable => true).should be_true
490
+ end
491
+
492
+ it "should log declaration" do
493
+ flexmock(RightScale::Log).should_receive(:info).with(/Connecting/).once
494
+ flexmock(RightScale::Log).should_receive(:info).with(/Declaring/).once
495
+ @mq.should_receive(:queue).once
496
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
497
+ broker.declare(:queue, "q").should be_true
498
+ end
499
+
500
+ it "should return false if client not usable" do
501
+ @mq.should_receive(:exchange).never
502
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
503
+ broker.__send__(:update_status, :disconnected)
504
+ broker.declare(:exchange, "x", :durable => true).should be_false
505
+
506
+ end
507
+
508
+ it "should log an error if the declare fails and return false" do
509
+ flexmock(RightScale::Log).should_receive(:info).with(/Connecting/).once
510
+ flexmock(RightScale::Log).should_receive(:info).with(/Declaring/).once
511
+ flexmock(RightScale::Log).should_receive(:error).with(/Failed declaring/, Exception, :trace).once
512
+ @exceptions.should_receive(:track).once
513
+ @mq.should_receive(:queue).and_raise(Exception).once
514
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
515
+ broker.declare(:queue, "q").should be_false
516
+ end
517
+
518
+ end # when declaring
519
+
520
+ context "when publishing" do
521
+
522
+ before(:each) do
523
+ @message = flexmock("message")
524
+ @packet = flexmock("packet", :class => RightScale::Request, :to_s => true, :version => [12, 12]).by_default
525
+ @direct = flexmock("direct")
526
+ flexmock(MQ).should_receive(:new).with(@connection).and_return(@mq).by_default
527
+ end
528
+
529
+ it "should serialize message, publish it, and return true" do
530
+ @mq.should_receive(:direct).with("exchange", :durable => true).and_return(@direct).once
531
+ @direct.should_receive(:publish).with(@message, :persistent => true).once
532
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
533
+ broker.__send__(:update_status, :ready)
534
+ broker.publish({:type => :direct, :name => "exchange", :options => {:durable => true}},
535
+ @packet, @message, :persistent => true).should be_true
536
+ end
537
+
538
+ it "should delete the exchange or queue from the AMQP cache if :declare specified" do
539
+ @mq.should_receive(:direct).with("exchange", {:declare => true}).and_return(@direct)
540
+ @direct.should_receive(:publish).with(@message, {})
541
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
542
+ broker.__send__(:update_status, :ready)
543
+ exchange = {:type => :direct, :name => "exchange", :options => {:declare => true}}
544
+ flexmock(broker).should_receive(:delete_from_cache).with(:direct, "exchange").once
545
+ broker.publish(exchange, @packet, @message).should be_true
546
+ end
547
+
548
+ it "should return false if client not connected" do
549
+ @mq.should_receive(:direct).never
550
+ @direct.should_receive(:publish).with(@message, :persistent => true).never
551
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
552
+ broker.publish({:type => :direct, :name => "exchange", :options => {:durable => true}},
553
+ @packet, @message, :persistent => true).should be_false
554
+ end
555
+
556
+ it "should log an error if the publish fails" do
557
+ flexmock(RightScale::Log).should_receive(:error).with(/Failed publishing/, Exception, :trace).once
558
+ @exceptions.should_receive(:track).once
559
+ @mq.should_receive(:direct).and_raise(Exception)
560
+ @direct.should_receive(:publish).with(@message, {}).never
561
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
562
+ broker.__send__(:update_status, :ready)
563
+ broker.publish({:type => :direct, :name => "exchange"}, @packet, @message).should be_false
564
+ end
565
+
566
+ it "should log that message is being sent with info about which broker used" do
567
+ flexmock(RightScale::Log).should_receive(:info).with(/Connecting/).once
568
+ flexmock(RightScale::Log).should_receive(:info).with(/^SEND b0/).once
569
+ @mq.should_receive(:direct).with("exchange", {}).and_return(@direct).once
570
+ @direct.should_receive(:publish).with(@message, {}).once
571
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
572
+ broker.__send__(:update_status, :ready)
573
+ broker.publish({:type => :direct, :name => "exchange"}, @packet, @message).should be_true
574
+ end
575
+
576
+ it "should log broker choices for :debug level" do
577
+ flexmock(RightScale::Log).should_receive(:level).and_return(:debug)
578
+ flexmock(RightScale::Log).should_receive(:debug).with(/... publish options/).once
579
+ flexmock(RightScale::Log).should_receive(:info).with(/Connecting/).once
580
+ flexmock(RightScale::Log).should_receive(:info).with(/^SEND b0/).once
581
+ @mq.should_receive(:direct).with("exchange", {}).and_return(@direct).once
582
+ @direct.should_receive(:publish).with(@message, {}).once
583
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
584
+ broker.__send__(:update_status, :ready)
585
+ broker.publish({:type => :direct, :name => "exchange"}, @packet, @message).should be_true
586
+ end
587
+
588
+ it "should not log a message if requested not to" do
589
+ flexmock(RightScale::Log).should_receive(:info).with(/Connecting/).once
590
+ flexmock(RightScale::Log).should_receive(:info).with(/^SEND/).never
591
+ @mq.should_receive(:direct).with("exchange", {}).and_return(@direct).once
592
+ @direct.should_receive(:publish).with(@message, :no_log => true).once
593
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
594
+ broker.__send__(:update_status, :ready)
595
+ broker.publish({:type => :direct, :name => "exchange"}, @packet, @message, :no_log => true).should be_true
596
+ end
597
+
598
+ it "should not log a message if requested not to unless debug level" do
599
+ flexmock(RightScale::Log).should_receive(:level).and_return(:debug)
600
+ flexmock(RightScale::Log).should_receive(:info).with(/Connecting/).once
601
+ flexmock(RightScale::Log).should_receive(:info).with(/^SEND/).once
602
+ @mq.should_receive(:direct).with("exchange", {}).and_return(@direct).once
603
+ @direct.should_receive(:publish).with(@message, :no_log => true).once
604
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
605
+ broker.__send__(:update_status, :ready)
606
+ broker.publish({:type => :direct, :name => "exchange"}, @packet, @message, :no_log => true).should be_true
607
+ end
608
+
609
+ it "should display broker alias in the log" do
610
+ flexmock(RightScale::Log).should_receive(:info).with(/Connecting/).once
611
+ flexmock(RightScale::Log).should_receive(:info).with(/^SEND b0 /).once
612
+ @mq.should_receive(:direct).with("exchange", {}).and_return(@direct).once
613
+ @direct.should_receive(:publish).with(@message, {}).once
614
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
615
+ broker.__send__(:update_status, :ready)
616
+ broker.publish({:type => :direct, :name => "exchange"}, @packet, @message).should be_true
617
+ end
618
+
619
+ it "should filter the packet display for :info level" do
620
+ flexmock(RightScale::Log).should_receive(:info).with(/Connecting/).once
621
+ flexmock(RightScale::Log).should_receive(:info).with(/^SEND.*TO YOU/).once
622
+ flexmock(RightScale::Log).should_receive(:info).with(/^SEND.*TO YOU/).never
623
+ @packet.should_receive(:to_s).with([:to], :send_version).and_return("TO YOU").once
624
+ @mq.should_receive(:direct).with("exchange", {}).and_return(@direct).once
625
+ @direct.should_receive(:publish).with(@message, :log_filter => [:to]).once
626
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
627
+ broker.__send__(:update_status, :ready)
628
+ broker.publish({:type => :direct, :name => "exchange"}, @packet, @message, :log_filter => [:to]).should be_true
629
+ end
630
+
631
+ it "should not filter the packet display for :debug level" do
632
+ flexmock(RightScale::Log).should_receive(:level).and_return(:debug)
633
+ flexmock(RightScale::Log).should_receive(:info).with(/Connecting/).once
634
+ flexmock(RightScale::Log).should_receive(:info).with(/^SEND.*ALL/).never
635
+ flexmock(RightScale::Log).should_receive(:info).with(/^SEND.*ALL/).once
636
+ @packet.should_receive(:to_s).with(nil, :send_version).and_return("ALL").once
637
+ @mq.should_receive(:direct).with("exchange", {}).and_return(@direct).once
638
+ @direct.should_receive(:publish).with(@message, :log_filter => [:to]).once
639
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
640
+ broker.__send__(:update_status, :ready)
641
+ broker.publish({:type => :direct, :name => "exchange"}, @packet, @message, :log_filter => [:to]).should be_true
642
+ end
643
+
644
+ it "should display additional data in log" do
645
+ flexmock(RightScale::Log).should_receive(:info).with(/Connecting/).once
646
+ flexmock(RightScale::Log).should_receive(:info).with(/^SEND.*More data/).once
647
+ @mq.should_receive(:direct).with("exchange", {}).and_return(@direct).once
648
+ @direct.should_receive(:publish).with(@message, :log_data => "More data").once
649
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
650
+ broker.__send__(:update_status, :ready)
651
+ broker.publish({:type => :direct, :name => "exchange"}, @packet, @message, :log_data => "More data").should be_true
652
+ end
653
+
654
+ it "should display RE-SEND if the message being sent is a retry" do
655
+ flexmock(RightScale::Log).should_receive(:info).with(/Connecting/).once
656
+ flexmock(RightScale::Log).should_receive(:info).with(/^RE-SEND/).once
657
+ @packet = flexmock("packet", :class => RightScale::Request, :to_s => true, :tries => ["try1"], :version => [12, 12])
658
+ @mq.should_receive(:direct).with("exchange", {}).and_return(@direct).once
659
+ @direct.should_receive(:publish).with(@message, {}).once
660
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
661
+ broker.__send__(:update_status, :ready)
662
+ broker.publish({:type => :direct, :name => "exchange"}, @packet, @message).should be_true
663
+ end
664
+
665
+ end # when publishing
666
+
667
+ context "when returning" do
668
+
669
+ class MQ
670
+ attr_accessor :connection, :on_return_message
671
+
672
+ def initialize(connection)
673
+ @connection = connection
674
+ end
675
+
676
+ def return_message(&blk)
677
+ @on_return_message = blk
678
+ end
679
+ end
680
+
681
+ before(:each) do
682
+ @message = flexmock("message")
683
+ @packet = flexmock("packet", :class => RightScale::Request, :to_s => true, :version => [12, 12]).by_default
684
+ @info = flexmock("info", :reply_text => "NO_CONSUMERS", :exchange => "exchange", :routing_key => "routing_key").by_default
685
+ @serializer.should_receive(:load).with(@message).and_return(@packet).by_default
686
+ end
687
+
688
+ it "should invoke block and log the return" do
689
+ flexmock(RightScale::Log).should_receive(:info).with(/Connecting to broker/).once
690
+ flexmock(RightScale::Log).should_receive(:debug).with(/RETURN b0/).once
691
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
692
+ called = 0
693
+ broker.return_message do |to, reason, message|
694
+ called += 1
695
+ to.should == "exchange"
696
+ reason.should == "NO_CONSUMERS"
697
+ message.should == @message
698
+ end
699
+ broker.instance_variable_get(:@mq).on_return_message.call(@info, @message)
700
+ called.should == 1
701
+ end
702
+
703
+ it "should invoke block with routing key if exchange is empty" do
704
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
705
+ called = 0
706
+ broker.return_message do |to, reason, message|
707
+ called += 1
708
+ to.should == "routing_key"
709
+ reason.should == "NO_CONSUMERS"
710
+ message.should == @message
711
+ end
712
+ @info.should_receive(:exchange).and_return("")
713
+ broker.instance_variable_get(:@mq).on_return_message.call(@info, @message)
714
+ called.should == 1
715
+ end
716
+
717
+ it "should log an error if there is a failure while processing the return" do
718
+ flexmock(RightScale::Log).should_receive(:error).with(/Failed return/, Exception, :trace).once
719
+ @exceptions.should_receive(:track).once
720
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
721
+ called = 0
722
+ broker.return_message do |to, reason, message|
723
+ called += 1
724
+ raise Exception
725
+ end
726
+ broker.instance_variable_get(:@mq).on_return_message.call(@info, @message)
727
+ called.should == 1
728
+ end
729
+
730
+ end # when returning
731
+
732
+ context "when deleting" do
733
+
734
+ before(:each) do
735
+ @direct = flexmock("direct")
736
+ @bind = flexmock("bind", :subscribe => true)
737
+ @queue = flexmock("queue", :bind => @bind, :name => "queue1")
738
+ @mq.should_receive(:queue).and_return(@queue).by_default
739
+ @mq.should_receive(:direct).and_return(@direct).by_default
740
+ flexmock(MQ).should_receive(:new).with(@connection).and_return(@mq).by_default
741
+ end
742
+
743
+ it "should delete the named queue and return true" do
744
+ @queue.should_receive(:delete).once
745
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
746
+ broker.subscribe({:name => "queue1"}, {:type => :direct, :name => "exchange"})
747
+ broker.queues.should == [@queue]
748
+ broker.delete("queue1").should be_true
749
+ broker.queues.should == []
750
+ end
751
+
752
+ it "should return false if the client is not usable" do
753
+ @queue.should_receive(:delete).never
754
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
755
+ broker.subscribe({:name => "queue1"}, {:type => :direct, :name => "exchange"})
756
+ broker.queues.should == [@queue]
757
+ broker.__send__(:update_status, :disconnected)
758
+ broker.delete("queue1").should be_false
759
+ broker.queues.should == [@queue]
760
+ end
761
+
762
+ it "should log an error and return false if the delete fails" do
763
+ flexmock(RightScale::Log).should_receive(:error).with(/Failed deleting queue/, Exception, :trace).once
764
+ @exceptions.should_receive(:track).once
765
+ @queue.should_receive(:delete).and_raise(Exception)
766
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
767
+ broker.subscribe({:name => "queue1"}, {:type => :direct, :name => "exchange"})
768
+ broker.queues.should == [@queue]
769
+ broker.delete("queue1").should be_false
770
+ end
771
+
772
+ end # when deleteing
773
+
774
+ context "when monitoring" do
775
+
776
+ include RightScale::StatsHelper
777
+
778
+ before(:each) do
779
+ flexmock(MQ).should_receive(:new).with(@connection).and_return(@mq).by_default
780
+ end
781
+
782
+ it "should distinguish whether the client is usable based on whether connecting or connected" do
783
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
784
+ broker.usable?.should be_true
785
+ broker.__send__(:update_status, :ready)
786
+ broker.usable?.should be_true
787
+ broker.__send__(:update_status, :disconnected)
788
+ broker.usable?.should be_false
789
+ flexmock(RightScale::Log).should_receive(:error).with(/Failed to connect to broker b0/).once
790
+ broker.__send__(:update_status, :failed)
791
+ broker.usable?.should be_false
792
+ end
793
+
794
+ it "should distinguish whether the client is connected" do
795
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
796
+ broker.connected?.should be_false
797
+ broker.__send__(:update_status, :ready)
798
+ broker.connected?.should be_true
799
+ broker.__send__(:update_status, :disconnected)
800
+ broker.connected?.should be_false
801
+ flexmock(RightScale::Log).should_receive(:error).with(/Failed to connect to broker b0/).once
802
+ broker.__send__(:update_status, :failed)
803
+ broker.connected?.should be_false
804
+ end
805
+
806
+ it "should distinguish whether the client has failed" do
807
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
808
+ broker.failed?.should be_false
809
+ broker.__send__(:update_status, :ready)
810
+ broker.failed?.should be_false
811
+ broker.__send__(:update_status, :disconnected)
812
+ broker.failed?.should be_false
813
+ flexmock(RightScale::Log).should_receive(:error).with(/Failed to connect to broker b0/).once
814
+ broker.__send__(:update_status, :failed)
815
+ broker.failed?.should be_true
816
+ end
817
+
818
+ it "should give broker summary" do
819
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
820
+ broker.summary.should == {:alias => "b0", :identity => @identity, :status => :connecting,
821
+ :disconnects => 0, :failures => 0, :retries => 0}
822
+ broker.__send__(:update_status, :ready)
823
+ broker.summary.should == {:alias => "b0", :identity => @identity, :status => :connected,
824
+ :disconnects => 0, :failures => 0, :retries => 0}
825
+ flexmock(RightScale::Log).should_receive(:error).with(/Failed to connect to broker/).once
826
+ broker.__send__(:update_status, :failed)
827
+ broker.summary.should == {:alias => "b0", :identity => @identity, :status => :failed,
828
+ :disconnects => 0, :failures => 1, :retries => 0}
829
+ end
830
+
831
+ it "should give broker statistics" do
832
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
833
+ broker.stats.should == {"alias" => "b0", "identity" => "rs-broker-localhost-5672",
834
+ "status" => "connecting", "disconnects" => nil, "disconnect last" => nil,
835
+ "failures" => nil, "failure last" => nil, "retries" => nil}
836
+ broker.__send__(:update_status, :ready)
837
+ broker.stats.should == {"alias" => "b0", "identity" => "rs-broker-localhost-5672",
838
+ "status" => "connected", "disconnects" => nil, "disconnect last" => nil,
839
+ "failures" => nil, "failure last" => nil, "retries" => nil}
840
+ flexmock(RightScale::Log).should_receive(:error).with(/Failed to connect to broker/).once
841
+ broker.__send__(:update_status, :failed)
842
+ broker.stats.should == {"alias" => "b0", "identity" => "rs-broker-localhost-5672",
843
+ "status" => "failed", "disconnects" => nil, "disconnect last" => nil,
844
+ "failures" => 1, "failure last" => {"elapsed" => 0}, "retries" => nil}
845
+ end
846
+
847
+ it "should make update status callback when status changes" do
848
+ broker = nil
849
+ called = 0
850
+ connected_before = false
851
+ callback = lambda { |b, c| called += 1; b.should == broker; c.should == connected_before }
852
+ options = {:update_status_callback => callback}
853
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, options)
854
+ broker.__send__(:update_status, :ready)
855
+ broker.last_failed.should be_false
856
+ called.should == 1
857
+ connected_before = true
858
+ broker.__send__(:update_status, :disconnected)
859
+ broker.last_failed.should be_false
860
+ broker.disconnects.total.should == 1
861
+ called.should == 2
862
+ broker.__send__(:update_status, :disconnected)
863
+ broker.disconnects.total.should == 1
864
+ called.should == 2
865
+ flexmock(RightScale::Log).should_receive(:error).with(/Failed to connect to broker b0/).once
866
+ connected_before = false
867
+ broker.__send__(:update_status, :failed)
868
+ broker.last_failed.should be_true
869
+ called.should == 3
870
+ end
871
+
872
+ end # when monitoring
873
+
874
+ context "when closing" do
875
+
876
+ before(:each) do
877
+ flexmock(MQ).should_receive(:new).with(@connection).and_return(@mq).by_default
878
+ end
879
+
880
+ it "should close broker connection and send status update" do
881
+ @connection.should_receive(:close).and_yield.once
882
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
883
+ flexmock(broker).should_receive(:update_status).once
884
+ broker.close
885
+ broker.status.should == :closed
886
+ end
887
+
888
+ it "should not propagate status update if requested not to" do
889
+ @connection.should_receive(:close).and_yield.once
890
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
891
+ flexmock(broker).should_receive(:update_status).never
892
+ broker.close(propagate = false)
893
+ end
894
+
895
+ it "should set status to :failed if not a normal close" do
896
+ @connection.should_receive(:close).and_yield.once
897
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
898
+ broker.close(propagate = false, normal = false)
899
+ broker.status.should == :failed
900
+ end
901
+
902
+ it "should log that closing connection" do
903
+ flexmock(RightScale::Log).should_receive(:info).with(/Connecting/).once
904
+ flexmock(RightScale::Log).should_receive(:info).with(/Closed connection to broker b0/).once
905
+ @connection.should_receive(:close).and_yield.once
906
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
907
+ broker.close
908
+ end
909
+
910
+ it "should not log if requested not to" do
911
+ flexmock(RightScale::Log).should_receive(:info).with(/Connecting/).once
912
+ flexmock(RightScale::Log).should_receive(:info).with(/Closed connection to broker b0/).never
913
+ @connection.should_receive(:close).and_yield.once
914
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
915
+ broker.close(propagate = true, normal = true, log = false)
916
+ end
917
+
918
+ it "should close broker connection and execute block if supplied" do
919
+ @connection.should_receive(:close).and_yield.once
920
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
921
+ called = 0
922
+ broker.close { called += 1; broker.status.should == :closed }
923
+ called.should == 1
924
+ end
925
+
926
+ it "should close broker connection when no block supplied" do
927
+ @connection.should_receive(:close).and_yield.once
928
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
929
+ broker.close
930
+ end
931
+
932
+ it "should not propagate status update if already closed" do
933
+ @connection.should_receive(:close).never
934
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
935
+ broker.__send__(:update_status, :closed)
936
+ flexmock(broker).should_receive(:update_status).never
937
+ broker.close
938
+ end
939
+
940
+ it "should change failed status to closed" do
941
+ flexmock(RightScale::Log).should_receive(:error).with(/Failed to connect to broker/).once
942
+ @connection.should_receive(:close).never
943
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
944
+ broker.__send__(:update_status, :failed)
945
+ flexmock(broker).should_receive(:update_status).never
946
+ broker.close
947
+ broker.status.should == :closed
948
+ end
949
+
950
+ it "should log an error if closing connection fails but still set status to :closed" do
951
+ flexmock(RightScale::Log).should_receive(:error).with(/Failed to close broker b0/, Exception, :trace).once
952
+ @exceptions.should_receive(:track).once
953
+ @connection.should_receive(:close).and_raise(Exception)
954
+ broker = RightScale::BrokerClient.new(@identity, @address, @serializer, @exceptions, @options)
955
+ broker.close
956
+ broker.status.should == :closed
957
+ end
958
+
959
+ end # when closing
960
+
961
+ end # RightScale::BrokerClient