right_agent 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
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