mcollective-client 2.9.1 → 2.10.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ ZWEwMDY2OTlmMTkwOWM4NGRjODVmYzQzMTk1ZGJmN2M4MDA0MTdlZg==
5
+ data.tar.gz: !binary |-
6
+ MjAyNjQ5NDQxZTE1MmM1NzEwODcwMDU1MTQzNGVlNmNhYjdkZDcyMw==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ NjNjZWZiZjIzMTk5ODE1ZTNkZDVmYThhMGNmNzFhNzY4ZGViMGJiNWU0OGU3
10
+ MDcyMTlhNjEyZDI3ZGZiMjE4YzVjNzk2OTVkOGY2ZDdlZjg5MTFjNTcwOWUx
11
+ N2YzZDU4YTg1MThhZWEwZTVhYjQ4NTk1ZDNlZWU2ZTc0ODRhOWQ=
12
+ data.tar.gz: !binary |-
13
+ Mjc1NjBiNjJjNWMyYjljNDE0OWFiZmE3OWYwOGNmODEzZmE2ZmIxNWJhNDdk
14
+ NzA0MmQ5ZmI3Y2JjYmI5ODIwMGE4NzcwMjNmZTdkOWJhYmRkOGJjZWVjN2Vk
15
+ Njg2YzZiNGI2NThjYWQ2MjA4ZTA3NDUyNDA0M2FhOTgxYmI3MGE=
data/lib/mcollective.rb CHANGED
@@ -59,7 +59,7 @@ module MCollective
59
59
 
60
60
  MCollective::Vendor.load_vendored
61
61
 
62
- VERSION="2.9.1"
62
+ VERSION="2.10.0"
63
63
 
64
64
  def self.version
65
65
  VERSION
@@ -6,6 +6,8 @@ class MCollective::Application::Find<MCollective::Application
6
6
 
7
7
  starttime = Time.now
8
8
 
9
+ mc.detect_and_set_stdin_discovery
10
+
9
11
  nodes = mc.discover
10
12
 
11
13
  discoverytime = Time.now - starttime
@@ -96,18 +96,8 @@ class MCollective::Application::Rpc<MCollective::Application
96
96
  puts "Request sent with id: " + mc.send(configuration[:action], configuration[:arguments])
97
97
  else
98
98
  discover_args = {:verbose => true}
99
- # IF the discovery method hasn't been explicitly overridden
100
- # and we're not being run interactively,
101
- # and someone has piped us some data
102
- # Then we assume it's a discovery list - this can be either:
103
- # - list of hosts in plaintext
104
- # - JSON that came from another rpc or printrpc
105
- if mc.default_discovery_method && !STDIN.tty? && !STDIN.eof?
106
- # Then we override discovery to try to grok the data on STDIN
107
- mc.discovery_method = 'stdin'
108
- mc.discovery_options = 'auto'
109
- discover_args = {:verbose => false}
110
- end
99
+
100
+ mc.detect_and_set_stdin_discovery
111
101
 
112
102
  mc.discover discover_args
113
103
 
@@ -159,10 +159,10 @@ module MCollective
159
159
  #
160
160
  # It returns a hash of times and timeouts for discovery and total run is taken from the options
161
161
  # hash which in turn is generally built using MCollective::Optionparser
162
- def req(body, agent=nil, options=false, waitfor=0, &block)
162
+ def req(body, agent=nil, options=false, waitfor=[], &block)
163
163
  if body.is_a?(Message)
164
164
  agent = body.agent
165
- waitfor = body.discovered_hosts.size || 0
165
+ waitfor = body.discovered_hosts || []
166
166
  @options = body.options
167
167
  end
168
168
 
@@ -170,12 +170,11 @@ module MCollective
170
170
  threaded = @options[:threaded]
171
171
  timeout = @discoverer.discovery_timeout(@options[:timeout], @options[:filter])
172
172
  request = createreq(body, agent, @options[:filter])
173
- publish_timeout = @options[:publish_timeout]
173
+ publish_timeout = @options[:publish_timeout] || @config.publish_timeout
174
174
  stat = {:starttime => Time.now.to_f, :discoverytime => 0, :blocktime => 0, :totaltime => 0}
175
175
  STDOUT.sync = true
176
176
  hosts_responded = 0
177
177
 
178
-
179
178
  begin
180
179
  if threaded
181
180
  hosts_responded = threaded_req(request, publish_timeout, timeout, waitfor, &block)
@@ -238,16 +237,41 @@ module MCollective
238
237
  def start_receiver(requestid, waitfor, timeout, &block)
239
238
  Log.debug("Starting response receiver with timeout of #{timeout}")
240
239
  hosts_responded = 0
240
+
241
+ if (waitfor.is_a?(Array))
242
+ unfinished = Hash.new(0)
243
+ waitfor.each {|w| unfinished[w] += 1}
244
+ else
245
+ unfinished = []
246
+ end
247
+
241
248
  begin
242
249
  Timeout.timeout(timeout) do
243
- begin
250
+ loop do
244
251
  resp = receive(requestid)
245
252
  yield resp.payload
246
253
  hosts_responded += 1
247
- end while (waitfor == 0 || hosts_responded < waitfor)
254
+
255
+ if (waitfor.is_a?(Array))
256
+ sender = resp.payload[:senderid]
257
+ if unfinished[sender] <= 1
258
+ unfinished.delete(sender)
259
+ else
260
+ unfinished[sender] -= 1
261
+ end
262
+
263
+ break if !waitfor.empty? && unfinished.empty?
264
+ else
265
+ break unless waitfor == 0 || hosts_responded < waitfor
266
+ end
267
+ end
248
268
  end
249
269
  rescue Timeout::Error => e
250
- if (waitfor > hosts_responded)
270
+ if waitfor.is_a?(Array)
271
+ if !unfinished.empty?
272
+ Log.warn("Could not receive all responses. Did not receive responses from #{unfinished.keys.join(', ')}")
273
+ end
274
+ elsif (waitfor > hosts_responded)
251
275
  Log.warn("Could not receive all responses. Expected : #{waitfor}. Received : #{hosts_responded}")
252
276
  end
253
277
  end
@@ -541,6 +541,7 @@ module MCollective
541
541
  raise("Unknown target type #{type}") unless [:directed, :broadcast, :reply, :request, :direct_request].include?(type)
542
542
  raise("Unknown collective '#{collective}' known collectives are '#{@config.collectives.join ', '}'") unless @config.collectives.include?(collective)
543
543
 
544
+ agents_multiplex = get_bool_option("activemq.agents_multiplex", "false")
544
545
  target = {:name => nil, :headers => {}}
545
546
 
546
547
  case type
@@ -548,10 +549,18 @@ module MCollective
548
549
  target[:name] = ["/queue/" + collective, :reply, "#{Config.instance.identity}_#{$$}", Client.request_sequence].join(".")
549
550
 
550
551
  when :broadcast
551
- target[:name] = ["/topic/" + collective, agent, :agent].join(".")
552
+ if agents_multiplex
553
+ target[:name] = ["/topic/" + collective, :agents].join(".")
554
+ else
555
+ target[:name] = ["/topic/" + collective, agent, :agent].join(".")
556
+ end
552
557
 
553
558
  when :request
554
- target[:name] = ["/topic/" + collective, agent, :agent].join(".")
559
+ if agents_multiplex
560
+ target[:name] = ["/topic/" + collective, :agents].join(".")
561
+ else
562
+ target[:name] = ["/topic/" + collective, agent, :agent].join(".")
563
+ end
555
564
 
556
565
  when :direct_request
557
566
  target[:name] = ["/queue/" + collective, :nodes].join(".")
@@ -387,6 +387,7 @@ module MCollective
387
387
  raise("Unknown target type #{type}") unless [:directed, :broadcast, :reply, :request, :direct_request].include?(type)
388
388
  raise("Unknown collective '#{collective}' known collectives are '#{@config.collectives.join ', '}'") unless @config.collectives.include?(collective)
389
389
 
390
+ agents_multiplex = get_bool_option("rabbitmq.agents_multiplex", "false")
390
391
  target = {:name => "", :headers => {}, :id => nil}
391
392
 
392
393
  if reply_to
@@ -402,13 +403,18 @@ module MCollective
402
403
  target[:id] = "mcollective_%s_replies" % agent
403
404
 
404
405
  when :broadcast, :request # publishing a request to all nodes with an agent
405
- target[:name] = "/exchange/%s_broadcast/%s" % [collective, agent]
406
+ if agents_multiplex
407
+ target[:name] = "/exchange/%s_broadcast" % collective
408
+ target[:id] = "%s_broadcast" % collective
409
+ else
410
+ target[:name] = "/exchange/%s_broadcast/%s" % [collective, agent]
411
+ target[:id] = "%s_broadcast_%s" % [collective, agent]
412
+ end
406
413
  if reply_to
407
414
  target[:headers]["reply-to"] = reply_to
408
415
  else
409
416
  target[:headers]["reply-to"] = reply_path
410
417
  end
411
- target[:id] = "%s_broadcast_%s" % [collective, agent]
412
418
 
413
419
  when :direct_request # a request to a specific node
414
420
  raise "Directed requests need to have a node identity" unless node
@@ -18,7 +18,7 @@ module MCollective
18
18
  file = STDIN.read
19
19
 
20
20
  if file =~ /^\s*$/
21
- raise("data piped on STDIN contained only whitespace - could not discover hosts from it.")
21
+ raise("data piped on STDIN contained only whitespace - could not discover hosts from it.")
22
22
  end
23
23
 
24
24
  if type == 'auto'
@@ -29,8 +29,10 @@ module MCollective
29
29
  end
30
30
  end
31
31
 
32
+ Log.debug("Parsing STDIN input as type %s" % type)
33
+
32
34
  if type == 'json'
33
- hosts = MCollective::RPC::Helpers.extract_hosts_from_json(file)
35
+ hosts = RPC::Helpers.extract_hosts_from_json(file)
34
36
  elsif type == 'text'
35
37
  hosts = file.split("\n")
36
38
  else
@@ -119,6 +119,12 @@ module MCollective
119
119
  @stdout = STDOUT
120
120
  @stdout.sync = true
121
121
  end
122
+
123
+ if initial_options[:stdin]
124
+ @stdin = initial_options[:stdin]
125
+ else
126
+ @stdin = STDIN
127
+ end
122
128
  end
123
129
 
124
130
  # Disconnects cleanly from the middleware
@@ -459,6 +465,24 @@ module MCollective
459
465
  agent_filter @agent
460
466
  end
461
467
 
468
+ # Detects data on STDIN and sets the STDIN discovery method
469
+ #
470
+ # IF the discovery method hasn't been explicitly overridden
471
+ # and we're not being run interactively,
472
+ # and someone has piped us some data
473
+ #
474
+ # Then we assume it's a discovery list - this can be either:
475
+ # - list of hosts in plaintext
476
+ # - JSON that came from another rpc or printrpc
477
+ #
478
+ # Then we override discovery to try to grok the data on STDIN
479
+ def detect_and_set_stdin_discovery
480
+ if self.default_discovery_method && !@stdin.tty? && !@stdin.eof?
481
+ self.discovery_method = 'stdin'
482
+ self.discovery_options = 'auto'
483
+ end
484
+ end
485
+
462
486
  # Does discovery based on the filters set, if a discovery was
463
487
  # previously done return that else do a new discovery.
464
488
  #
@@ -845,6 +869,7 @@ module MCollective
845
869
  end
846
870
 
847
871
  @stats.noresponsefrom.concat @client.stats[:noresponsefrom]
872
+ @stats.unexpectedresponsefrom.concat @client.stats[:unexpectedresponsefrom]
848
873
  @stats.responses += @client.stats[:responses]
849
874
  @stats.blocktime += @client.stats[:blocktime] + sleep_time
850
875
  @stats.totaltime += @client.stats[:totaltime]
@@ -2,8 +2,8 @@ module MCollective
2
2
  module RPC
3
3
  # Various utilities for the RPC system
4
4
  class Helpers
5
- # Parse JSON output as produced by printrpc and extract
6
- # the "sender" of each rpc response
5
+ # Parse JSON output as produced by printrpc or puppet query
6
+ # and extract the "sender" / "certname" of each entry
7
7
  #
8
8
  # The simplist valid JSON based data would be:
9
9
  #
@@ -11,6 +11,13 @@ module MCollective
11
11
  # {"sender" => "example.com"},
12
12
  # {"sender" => "another.com"}
13
13
  # ]
14
+ #
15
+ # or
16
+ #
17
+ # [
18
+ # {"certname" => "example.com"},
19
+ # {"certname" => "another.com"}
20
+ # ]
14
21
  def self.extract_hosts_from_json(json)
15
22
  hosts = JSON.parse(json)
16
23
 
@@ -18,9 +25,12 @@ module MCollective
18
25
 
19
26
  hosts.map do |host|
20
27
  raise "JSON host list is not an array of Hashes" unless host.is_a?(Hash)
21
- raise "JSON host list does not have senders in it" unless host.include?("sender")
22
28
 
23
- host["sender"]
29
+ unless host.include?("sender") || host.include?("certname")
30
+ raise "JSON host list does not have senders in it"
31
+ end
32
+
33
+ host["sender"] || host["certname"]
24
34
  end.uniq
25
35
  end
26
36
 
@@ -264,7 +274,7 @@ module MCollective
264
274
  parser.on('--one', '-1', 'Send request to only one discovered nodes') do |v|
265
275
  options[:mcollective_limit_targets] = 1
266
276
  end
267
-
277
+
268
278
  parser.on('--batch SIZE', 'Do requests in batches') do |v|
269
279
  # validate batch string. Is it x% where x > 0 or is it an integer
270
280
  if ((v =~ /^(\d+)%$/ && Integer($1) != 0) || v =~ /^(\d+)$/)
@@ -2,9 +2,9 @@ module MCollective
2
2
  module RPC
3
3
  # Class to wrap all the stats and to keep track of some timings
4
4
  class Stats
5
- attr_accessor :noresponsefrom, :starttime, :discoverytime, :blocktime, :responses, :totaltime
6
- attr_accessor :discovered, :discovered_nodes, :okcount, :failcount, :noresponsefrom, :responsesfrom
7
- attr_accessor :requestid, :aggregate_summary, :ddl, :aggregate_failures
5
+ attr_accessor :noresponsefrom, :unexpectedresponsefrom, :starttime, :discoverytime, :blocktime, :responses
6
+ attr_accessor :totaltime, :discovered, :discovered_nodes, :okcount, :failcount, :noresponsefrom
7
+ attr_accessor :responsesfrom, :requestid, :aggregate_summary, :ddl, :aggregate_failures
8
8
 
9
9
  def initialize
10
10
  reset
@@ -13,6 +13,7 @@ module MCollective
13
13
  # Resets stats, if discovery time is set we keep it as it was
14
14
  def reset
15
15
  @noresponsefrom = []
16
+ @unexpectedresponsefrom = []
16
17
  @responsesfrom = []
17
18
  @responses = 0
18
19
  @starttime = Time.now.to_f
@@ -23,7 +24,6 @@ module MCollective
23
24
  @discovered_nodes = []
24
25
  @okcount = 0
25
26
  @failcount = 0
26
- @noresponsefrom = []
27
27
  @requestid = nil
28
28
  @aggregate_summary = []
29
29
  @aggregate_failures = []
@@ -32,6 +32,7 @@ module MCollective
32
32
  # returns a hash of our stats
33
33
  def to_hash
34
34
  {:noresponsefrom => @noresponsefrom,
35
+ :unexpectedresponsefrom => @unexpectedresponsefrom,
35
36
  :starttime => @starttime,
36
37
  :discoverytime => @discoverytime,
37
38
  :blocktime => @blocktime,
@@ -70,6 +71,7 @@ module MCollective
70
71
  # Re-initializes the object with stats from the basic client
71
72
  def client_stats=(stats)
72
73
  @noresponsefrom = stats[:noresponsefrom]
74
+ @unexpectedresponsefrom = stats[:unexpectedresponsefrom]
73
75
  @responses = stats[:responses]
74
76
  @starttime = stats[:starttime]
75
77
  @blocktime = stats[:blocktime]
@@ -115,13 +117,19 @@ module MCollective
115
117
  def finish_request
116
118
  @totaltime = @blocktime + @discoverytime
117
119
 
118
- # figures out who we had no responses from
120
+ # figure out who responded unexpectedly
121
+ rhosts = @responsesfrom.clone
122
+ @discovered_nodes.each {|d| rhosts.delete(d)}
123
+ @unexpectedresponsefrom = rhosts
124
+
125
+ # figure out who we had no responses from
119
126
  dhosts = @discovered_nodes.clone
120
127
  @responsesfrom.each {|r| dhosts.delete(r)}
121
128
  @noresponsefrom = dhosts
122
129
  rescue
123
130
  @totaltime = 0
124
131
  @noresponsefrom = []
132
+ @unexpectedresponsefrom = []
125
133
  end
126
134
 
127
135
  # Helper to keep track of who we received responses from
@@ -225,8 +233,22 @@ module MCollective
225
233
  end
226
234
  end
227
235
 
228
- if no_response_report != ""
229
- result_text << "" << no_response_report
236
+ no_response_r = no_response_report
237
+ unexpected_response_r = unexpected_response_report
238
+ if no_response_r || unexpected_response_r
239
+ result_text << ""
240
+ end
241
+
242
+ if no_response_r != ""
243
+ result_text << "" << no_response_r
244
+ end
245
+
246
+ if unexpected_response_r != ""
247
+ result_text << "" << unexpected_response_r
248
+ end
249
+
250
+ if no_response_r || unexpected_response_r
251
+ result_text << ""
230
252
  end
231
253
 
232
254
  result_text.join("\n")
@@ -237,7 +259,6 @@ module MCollective
237
259
  result_text = StringIO.new
238
260
 
239
261
  if @noresponsefrom.size > 0
240
- result_text.puts
241
262
  result_text.puts Util.colorize(:red, "No response from:")
242
263
  result_text.puts
243
264
 
@@ -248,8 +269,26 @@ module MCollective
248
269
  @noresponsefrom.sort.in_groups_of(fields_num) do |c|
249
270
  result_text.puts format % c
250
271
  end
272
+ end
251
273
 
274
+ result_text.string
275
+ end
276
+
277
+ # Returns a blob of text indicating what nodes responded but weren't discovered
278
+ def unexpected_response_report
279
+ result_text = StringIO.new
280
+
281
+ if @unexpectedresponsefrom.size > 0
282
+ result_text.puts Util.colorize(:red, "Unexpected response from:")
252
283
  result_text.puts
284
+
285
+ field_size = Util.field_size(@unexpectedresponsefrom, 30)
286
+ fields_num = Util.field_number(field_size)
287
+ format = " " + ( " %-#{field_size}s" * fields_num )
288
+
289
+ @unexpectedresponsefrom.sort.in_groups_of(fields_num) do |c|
290
+ result_text.puts format % c
291
+ end
253
292
  end
254
293
 
255
294
  result_text.string
@@ -205,14 +205,25 @@ module MCollective
205
205
 
206
206
  it "should thread the publisher and receiver if configured" do
207
207
  client.instance_variable_get(:@options)[:threaded] = true
208
- client.expects(:threaded_req).with(request, nil, 0, 1)
208
+ client.expects(:threaded_req).with(request, 2, 0, ['rspec'])
209
209
  message.options[:threaded] = true
210
210
  client.req(message)
211
211
  end
212
212
 
213
213
  it "should not thread the publisher and receiver if configured" do
214
214
  client.instance_variable_set(:@threaded, false)
215
- client.expects(:unthreaded_req).with(request, nil, 0, 1)
215
+ client.expects(:unthreaded_req).with(request, 2, 0, ['rspec'])
216
+ client.req(message)
217
+ end
218
+
219
+ it "uses the publish_timeout from options when passed as an option" do
220
+ client.expects(:unthreaded_req).with(request, 5, 0, ['rspec'])
221
+ client.req(message, nil, message.options.merge(:publish_timeout => 5))
222
+ end
223
+
224
+ it "uses the publish_timeout from config when passed as a config value" do
225
+ client.expects(:unthreaded_req).with(request, 10, 0, ['rspec'])
226
+ client.instance_variable_get(:@config).expects(:publish_timeout).returns(10)
216
227
  client.req(message)
217
228
  end
218
229
  end
@@ -267,50 +278,132 @@ module MCollective
267
278
  end
268
279
 
269
280
  describe "#start_receiver" do
270
- it "should go into a receive loop and receive until it reaches waitfor" do
271
- results = []
272
- Timeout.stubs(:timeout).yields
273
- message = mock
274
- client.stubs(:receive).with("erfs123").returns(message)
275
- message.stubs(:payload).returns("msg1", "msg2", "msg3")
276
- client.start_receiver("erfs123", 3, 5) do |msg|
277
- results << msg
281
+ describe "waitfor is a number" do
282
+ it "should go into a receive loop and receive until it reaches waitfor" do
283
+ results = []
284
+ Timeout.stubs(:timeout).yields
285
+ message = mock
286
+ client.stubs(:receive).with("erfs123").returns(message)
287
+ message.stubs(:payload).returns("msg1", "msg2", "msg3")
288
+ client.start_receiver("erfs123", 3, 5) do |msg|
289
+ results << msg
290
+ end
291
+ results.should == ["msg1", "msg2", "msg3"]
278
292
  end
279
- results.should == ["msg1", "msg2", "msg3"]
280
- end
281
293
 
282
- it "should log a warning if a timeout occurs" do
283
- results = []
284
- Timeout.stubs(:timeout).yields
285
- message = mock
286
- client.stubs(:receive).with("erfs123").returns(message)
287
- message.stubs(:payload).returns("msg1", "msg2", "timeout")
288
- Log.expects(:warn).with("Could not receive all responses. Expected : 3. Received : 2")
289
- responded = client.start_receiver("erfs123", 3, 5) do |msg|
290
- if msg == "timeout"
291
- raise Timeout::Error
294
+ it "should log a warning if a timeout occurs" do
295
+ results = []
296
+ Timeout.stubs(:timeout).yields
297
+ message = mock
298
+ client.stubs(:receive).with("erfs123").returns(message)
299
+ message.stubs(:payload).returns("msg1", "msg2", "timeout")
300
+ Log.expects(:warn).with("Could not receive all responses. Expected : 3. Received : 2")
301
+ responded = client.start_receiver("erfs123", 3, 5) do |msg|
302
+ if msg == "timeout"
303
+ raise Timeout::Error
304
+ end
305
+ results << msg
306
+ end
307
+ results.should == ["msg1", "msg2"]
308
+ responded.should == 2
309
+ end
310
+
311
+ it "should not log a warning if a the response count is larger or equal to the expected number of responses" do
312
+ results = []
313
+ Timeout.stubs(:timeout).yields
314
+ message = mock
315
+ client.stubs(:receive).with("erfs123").returns(message)
316
+ message.stubs(:payload).returns("msg1", "msg2", "timeout")
317
+ Log.expects(:warn).never
318
+ responded = client.start_receiver("erfs123", 2, 5) do |msg|
319
+ if msg == "timeout"
320
+ raise Timeout::Error
321
+ end
322
+ results << msg
292
323
  end
293
- results << msg
324
+ results.should == ["msg1", "msg2"]
325
+ responded.should == 2
294
326
  end
295
- results.should == ["msg1", "msg2"]
296
- responded.should == 2
297
327
  end
298
328
 
299
- it "should not log a warning if a the response count is larger or equal to the expected number of responses" do
300
- results = []
301
- Timeout.stubs(:timeout).yields
302
- message = mock
303
- client.stubs(:receive).with("erfs123").returns(message)
304
- message.stubs(:payload).returns("msg1", "msg2", "timeout")
305
- Log.expects(:warn).never
306
- responded = client.start_receiver("erfs123", 2, 5) do |msg|
307
- if msg == "timeout"
308
- raise Timeout::Error
329
+ describe "waitfor is an array" do
330
+ it "should go into a receive loop and receive until it matches waitfor" do
331
+ senders = ["sender1", "sender2", "sender3", "sender4"]
332
+ expected = senders.map {|s| Message.new({:callerid => "caller", :senderid => s}, nil, :type => :reply)}
333
+ results = []
334
+ Timeout.stubs(:timeout).yields
335
+ client.stubs(:receive).with("erfs123").returns(*expected)
336
+ client.start_receiver("erfs123", senders[0,3], 5) do |msg|
337
+ results << msg
338
+ end
339
+ results.should == expected[0,3].map {|m| m.payload}
340
+ end
341
+
342
+ it "receive until it gets all expected responses" do
343
+ senders = ["sender1", "sender2", "sender3", "sender4"]
344
+ expected = senders.map {|s| Message.new({:callerid => "caller", :senderid => s}, nil, :type => :reply)}
345
+ results = []
346
+ Timeout.stubs(:timeout).yields
347
+ client.stubs(:receive).with("erfs123").returns(*expected)
348
+ client.start_receiver("erfs123", senders[1,3], 5) do |msg|
349
+ results << msg
350
+ end
351
+ results.should == expected.map {|m| m.payload}
352
+ end
353
+
354
+ it "should log a warning if a timeout occurs" do
355
+ senders = ["sender1", "sender2", "sender3"]
356
+ messages = ["msg1", "msg2", "timeout"]
357
+ expected = senders.zip(messages).map {|s, m| Message.new({:callerid => "caller", :senderid => s, :body => m}, nil, :type => :reply)}
358
+ results = []
359
+ Timeout.stubs(:timeout).yields
360
+ client.stubs(:receive).with("erfs123").returns(*expected)
361
+ Log.expects(:warn).with("Could not receive all responses. Did not receive responses from sender3")
362
+ responded = client.start_receiver("erfs123", senders, 5) do |msg|
363
+ if msg[:body] == "timeout"
364
+ raise Timeout::Error
365
+ end
366
+ results << msg
367
+ end
368
+ results.should == expected[0,2].map {|m| m.payload}
369
+ responded.should == 2
370
+ end
371
+
372
+ it "should not log a warning if accepting all responses" do
373
+ senders = ["sender1", "sender2", "sender3"]
374
+ messages = ["msg1", "msg2", "timeout"]
375
+ expected = senders.zip(messages).map {|s, m| Message.new({:callerid => "caller", :senderid => s, :body => m}, nil, :type => :reply)}
376
+ results = []
377
+ Timeout.stubs(:timeout).yields
378
+ client.stubs(:receive).with("erfs123").returns(*expected)
379
+ Log.expects(:warn).never
380
+ responded = client.start_receiver("erfs123", [], 1) do |msg|
381
+ if msg[:body] == "timeout"
382
+ raise Timeout::Error
383
+ end
384
+ results << msg
385
+ end
386
+ results.should == expected[0,2].map {|m| m.payload}
387
+ responded.should == 2
388
+ end
389
+
390
+ it "should not log a warning if the response count is larger or equal to the expected number of responses" do
391
+ senders = ["sender1", "sender2", "sender3"]
392
+ messages = ["msg1", "msg2", "timeout"]
393
+ expected = senders.zip(messages).map {|s, m| Message.new({:callerid => "caller", :senderid => s, :body => m}, nil, :type => :reply)}
394
+ results = []
395
+ Timeout.stubs(:timeout).yields
396
+ client.stubs(:receive).with("erfs123").returns(*expected)
397
+ Log.expects(:warn).never
398
+ responded = client.start_receiver("erfs123", senders[0,2], 5) do |msg|
399
+ if msg[:body] == "timeout"
400
+ raise Timeout::Error
401
+ end
402
+ results << msg
309
403
  end
310
- results << msg
404
+ results.should == expected[0,2].map {|m| m.payload}
405
+ responded.should == 2
311
406
  end
312
- results.should == ["msg1", "msg2"]
313
- responded.should == 2
314
407
  end
315
408
  end
316
409