12 ddl = DDL.new("foo", "agent", false)
13 ddl.action("rspec", :description => "mock agent")
15 ddl.stubs(:meta).returns({:timeout => 2})
16 DDL.stubs(:new).returns(ddl)
18 @discoverer.stubs(:force_direct_mode?).returns(false)
19 @discoverer.stubs(:discovery_method).returns("mc")
20 @discoverer.stubs(:force_discovery_method_by_filter).returns(false)
21 @discoverer.stubs(:discovery_timeout).returns(2)
22 @discoverer.stubs(:ddl).returns(ddl)
24 @coreclient.stubs("options=")
25 @coreclient.stubs(:collective).returns("mcollective")
26 @coreclient.stubs(:timeout_for_compound_filter).returns(0)
27 @coreclient.stubs(:discoverer).returns(@discoverer)
29 Config.instance.stubs(:loadconfig).with("/nonexisting").returns(true)
30 Config.instance.stubs(:direct_addressing).returns(true)
31 Config.instance.stubs(:collectives).returns(["mcollective", "rspec"])
32 MCollective::Client.stubs(:new).returns(@coreclient)
34 @stderr = StringIO.new
35 @stdout = StringIO.new
37 @client = Client.new("foo", {:options => {:filter => Util.empty_filter, :config => "/nonexisting"}})
38 @client.stubs(:ddl).returns(ddl)
41 describe "#initialize" do
42 it "should fail for missing DDLs" do
43 DDL.stubs(:new).raises("DDL failure")
44 expect { Client.new("foo", {:options => {:config => "/nonexisting"}}) }.to raise_error("DDL failure")
47 it "should set a empty filter when none is supplied" do
48 filter = Util.empty_filter
49 Util.expects(:empty_filter).once.returns(filter)
51 Client.new("foo", :options => {:config => "/nonexisting"})
54 it "should default the discovery_timeout to nil" do
55 c = Client.new("rspec", :options => {:config => "/nonexisting"})
56 c.instance_variable_get("@discovery_timeout").should == nil
59 it "should accept a supplied discovery_timeout" do
60 c = Client.new("rspec", :options => {:config => "/nonexisting", :disctimeout => 10})
61 c.instance_variable_get("@discovery_timeout").should == 10
65 describe "#validate_request" do
66 it "should fail when a DDL isn't present" do
67 @client.instance_variable_set("@ddl", nil)
68 expect { @client.validate_request("rspec", {}) }.to raise_error("No DDL found for agent foo cannot validate inputs")
71 it "should validate the input arguments" do
72 @client.ddl.expects(:set_default_input_arguments).with("rspec", {})
73 @client.ddl.expects(:validate_rpc_request).with("rspec", {})
74 @client.validate_request("rspec", {})
78 describe "#process_results_with_block" do
79 it "should inform the stats object correctly for passed requests" do
80 response = {:senderid => "rspec", :body => {:statuscode => 0}}
82 @client.stubs(:rpc_result_from_reply).with("foo", "rspec", response)
83 @client.stats.expects(:ok)
84 @client.stats.expects(:node_responded).with("rspec")
85 @client.stats.expects(:time_block_execution).with(:start)
86 @client.stats.expects(:time_block_execution).with(:end)
87 @client.expects(:aggregate_reply).returns("aggregate stub")
91 @client.process_results_with_block("rspec", response, blk, "").should == "aggregate stub"
94 it "should inform the stats object correctly for failed requests" do
95 @client.stats.expects(:fail)
96 @client.stats.expects(:node_responded).with("rspec")
98 response = {:senderid => "rspec", :body => {:statuscode => 1}}
101 @client.stubs(:rpc_result_from_reply).with("foo", "rspec", response)
102 @client.process_results_with_block("rspec", response, blk, nil)
105 it "should raise correct exceptions on failure" do
108 @client.stubs(:rpc_result_from_reply)
110 [[2, UnknownRPCAction], [3, MissingRPCData], [4, InvalidRPCData], [5, UnknownRPCError]].each do |err|
111 response = {:senderid => "rspec", :body => {:statuscode => err[0]}}
113 expect { @client.process_results_with_block("rspec", response, blk, nil) }.to raise_error(err[1])
117 it "should pass raw results for single arity blocks" do
118 response = {:senderid => "rspec", :body => {:statuscode => 1}}
119 blk = Proc.new {|r| r.should == response}
121 @client.stubs(:rpc_result_from_reply).with("foo", "rspec", response)
122 @client.process_results_with_block("rspec", response, blk, nil)
125 it "should pass raw and rpc style results for 2 arity blocks" do
126 response = {:senderid => "rspec", :body => {:statuscode => 1}}
127 blk = Proc.new do |r, s|
129 s.should.class == RPC::Result
132 @client.process_results_with_block("rspec", response, blk, nil)
136 describe "#process_results_without_block" do
137 it "should inform the stats object correctly for passed requests" do
138 response = {:senderid => "rspec", :body => {:statuscode => 0}}
139 @client.stubs(:rpc_result_from_reply).with("foo", "rspec", response)
140 @client.stats.expects(:ok)
141 @client.stats.expects(:node_responded).with("rspec")
142 @client.process_results_without_block(response, "rspec", nil)
145 it "should inform the stats object correctly for failed requests" do
146 @client.stats.expects(:fail).twice
147 @client.stats.expects(:node_responded).with("rspec").twice
149 response = {:senderid => "rspec", :body => {:statuscode => 1}}
150 @client.stubs(:rpc_result_from_reply).with("foo", "rspec", response)
151 @client.process_results_without_block(response, "rspec", nil)
153 response = {:senderid => "rspec", :body => {:statuscode => 3}}
154 @client.stubs(:rpc_result_from_reply).with("foo", "rspec", response)
155 @client.process_results_without_block(response, "rspec", nil)
158 it "should return the result and the aggregate" do
159 @client.expects(:aggregate_reply).returns("aggregate stub")
161 response = {:senderid => "rspec", :body => {:statuscode => 0}}
162 result = @client.rpc_result_from_reply("foo", "rspec", response)
164 @client.stubs(:rpc_result_from_reply).with("foo", "rspec", response).returns(result)
165 @client.process_results_without_block(response, "rspec", "").should == [result, "aggregate stub"]
169 describe "#load_aggregate_functions" do
170 it "should not load if the ddl is not set" do
171 @client.load_aggregate_functions("rspec", nil).should == nil
174 it "should create the aggregate for the right action" do
175 @client.ddl.expects(:action_interface).with("rspec").returns({:aggregate => []}).twice
176 Aggregate.expects(:new).with(:aggregate => []).returns("rspec aggregate")
177 @client.load_aggregate_functions("rspec", @client.ddl).should == "rspec aggregate"
180 it "should log and return nil on failure" do
181 @client.ddl.expects(:action_interface).raises("rspec")
182 Log.expects(:error).with(regexp_matches(/Failed to load aggregate/))
183 @client.load_aggregate_functions("rspec", @client.ddl)
187 describe "#aggregate_reply" do
188 it "should not call anything if the aggregate isnt set" do
189 @client.aggregate_reply(nil, nil).should == nil
192 it "should call the aggregate functions with the right data" do
193 result = @client.rpc_result_from_reply("rspec", "rspec", {:body => {:data => "rspec"}})
196 aggregate.expects(:call_functions).with(result).returns(aggregate)
198 @client.aggregate_reply(result, aggregate).should == aggregate
201 it "should log and return nil on failure" do
203 aggregate.expects(:call_functions).raises
205 Log.expects(:error).with(regexp_matches(/Failed to calculate aggregate summaries/))
207 @client.aggregate_reply({}, aggregate).should == nil
211 describe "#collective=" do
212 it "should validate the collective" do
213 expect { @client.collective = "fail" }.to raise_error("Unknown collective fail")
214 @client.collective = "rspec"
217 it "should set the collective" do
218 @client.options[:collective].should == "mcollective"
219 @client.collective = "rspec"
220 @client.options[:collective].should == "rspec"
223 it "should reset the client" do
224 @client.expects(:reset)
225 @client.collective = "rspec"
229 describe "#discovery_method=" do
230 it "should set the method" do
231 @client.discovery_method = "rspec"
232 @client.discovery_method.should == "rspec"
235 it "should set initial options if provided" do
236 client = Client.new("rspec", {:options => {:discovery_options => ["rspec"], :filter => Util.empty_filter, :config => "/nonexisting"}})
237 client.discovery_method = "rspec"
238 client.discovery_method.should == "rspec"
239 client.discovery_options.should == ["rspec"]
242 it "should clear the options if none are given initially" do
243 @client.discovery_options = ["rspec"]
244 @client.discovery_method = "rspec"
245 @client.discovery_options.should == []
248 it "should set the client options" do
249 @client.expects(:options).returns("rspec")
250 @client.client.expects(:options=).with("rspec")
251 @client.discovery_method = "rspec"
254 it "should adjust timeout for the new method" do
255 @client.expects(:discovery_timeout).once.returns(1)
256 @client.discovery_method = "rspec"
257 @client.instance_variable_get("@timeout").should == 4
260 it "should preserve any user supplied discovery timeout" do
261 @client.discovery_timeout = 10
262 @client.discovery_method = "rspec"
263 @client.discovery_timeout.should == 10
266 it "should reset the rpc client" do
267 @client.expects(:reset)
268 @client.discovery_method = "rspec"
272 describe "#discovery_options=" do
273 it "should flatten the options array" do
274 @client.discovery_options = "foo"
275 @client.discovery_options.should == ["foo"]
279 describe "#discovery_timeout" do
280 it "should favour the initial options supplied timeout" do
281 client = Client.new("rspec", {:options => {:disctimeout => 3, :filter => Util.empty_filter, :config => "/nonexisting"}})
282 client.discovery_timeout.should == 3
285 it "should return the DDL data if no specific options are supplied" do
286 client = Client.new("rspec", {:options => {:disctimeout => nil, :filter => Util.empty_filter, :config => "/nonexisting"}})
287 client.discovery_timeout.should == 2
291 describe "#discovery_timeout=" do
292 it "should store the discovery timeout" do
293 @client.discovery_timeout = 10
294 @client.discovery_timeout.should == 10
297 it "should update the overall timeout with the new discovery timeout" do
298 @client.instance_variable_get("@timeout").should == 4
300 @client.discovery_timeout = 10
302 @client.instance_variable_get("@timeout").should == 12
306 describe "#limit_method" do
307 it "should force strings to symbols" do
308 @client.limit_method = "first"
309 @client.limit_method.should == :first
312 it "should only allow valid methods" do
313 @client.limit_method = :first
314 @client.limit_method.should == :first
315 @client.limit_method = :random
316 @client.limit_method.should == :random
318 expect { @client.limit_method = :fail }.to raise_error(/Unknown/)
319 expect { @client.limit_method = "fail" }.to raise_error(/Unknown/)
323 describe "#method_missing" do
324 it "should reset the stats" do
325 client = Client.new("foo", {:options => {:filter => Util.empty_filter, :config => "/nonexisting"}})
326 client.stubs(:call_agent)
328 Stats.any_instance.expects(:reset).once
332 it "should validate the request against the ddl" do
333 client = Client.new("foo", {:options => {:filter => Util.empty_filter, :config => "/nonexisting"}})
335 client.stubs(:call_agent)
337 client.expects(:validate_request).with("rspec", {:arg => :val}).raises("validation failed")
339 expect { client.rspec(:arg => :val) }.to raise_error("validation failed")
342 it "should support limited targets" do
343 client = Client.new("foo", {:options => {:filter => Util.empty_filter, :config => "/nonexisting"}})
344 client.limit_targets = 10
346 client.expects(:pick_nodes_from_discovered).with(10).returns(["one", "two"])
347 client.expects(:custom_request).with("rspec", {}, ["one", "two"], {"identity" => /^(one|two)$/}).once
352 describe "batch mode" do
354 Config.instance.stubs(:direct_addressing).returns(true)
355 @client = Client.new("foo", {:options => {:filter => Util.empty_filter, :config => "/nonexisting"}})
358 it "should support global batch_size" do
359 @client.batch_size = 10
360 @client.expects(:call_agent_batched).with("rspec", {}, @client.options, 10, 1)
364 it "should support custom batch_size" do
365 @client.expects(:call_agent_batched).with("rspec", {}, @client.options, 10, 1)
366 @client.rspec :batch_size => 10
369 it "should allow supplied batch_size override global one" do
370 @client.batch_size = 10
371 @client.expects(:call_agent_batched).with("rspec", {}, @client.options, 20, 1)
372 @client.rspec :batch_size => 20
375 it "should support global batch_sleep_time" do
376 @client.batch_size = 10
377 @client.batch_sleep_time = 20
378 @client.expects(:call_agent_batched).with("rspec", {}, @client.options, 10, 20)
382 it "should support custom batch_sleep_time" do
383 @client.batch_size = 10
384 @client.expects(:call_agent_batched).with("rspec", {}, @client.options, 10, 20)
385 @client.rspec :batch_sleep_time => 20
388 it "should allow supplied batch_sleep_time override global one" do
389 @client.batch_size = 10
390 @client.batch_sleep_time = 10
391 @client.expects(:call_agent_batched).with("rspec", {}, @client.options, 10, 20)
392 @client.rspec :batch_sleep_time => 20
396 it "should support normal calls" do
397 client = Client.new("foo", {:options => {:filter => Util.empty_filter, :config => "/nonexisting"}})
399 client.expects(:call_agent).with("rspec", {}, client.options, :auto).once
405 describe "#pick_nodes_from_discovered" do
411 ddl.stubs(:meta).returns({:timeout => 2})
413 discoverer.stubs(:ddl).returns(ddl)
415 client.stubs("options=")
416 client.stubs(:collective).returns("mcollective")
417 client.stubs(:discoverer).returns(discoverer)
419 Config.instance.stubs(:loadconfig).with("/nonexisting").returns(true)
420 MCollective::Client.stubs(:new).returns(client)
421 Config.instance.stubs(:direct_addressing).returns(true)
424 it "should return a percentage of discovered hosts" do
425 client = Client.new("foo", {:options => {:filter => Util.empty_filter, :config => "/nonexisting"}})
426 client.stubs(:discover).returns((1..10).map{|i| i.to_s})
427 client.limit_method = :first
428 client.pick_nodes_from_discovered("20%").should == ["1", "2"]
431 it "should return the same list when a random seed is supplied" do
432 client = Client.new("foo", {:options => {:filter => Util.empty_filter, :config => "/nonexisting", :limit_seed => 5}})
433 client.stubs(:discover).returns((1..10).map{|i| i.to_s})
434 client.limit_method = :random
435 client.pick_nodes_from_discovered("30%").should == ["3", "7", "8"]
436 client.pick_nodes_from_discovered("30%").should == ["3", "7", "8"]
437 client.pick_nodes_from_discovered("3").should == ["3", "7", "8"]
438 client.pick_nodes_from_discovered("3").should == ["3", "7", "8"]
441 it "should correctly pick a numeric amount of discovered nodes" do
442 client = Client.new("foo", {:options => {:filter => Util.empty_filter, :config => "/nonexisting", :limit_seed => 5}})
443 client.stubs(:discover).returns((1..10).map{|i| i.to_s})
444 client.limit_method = :first
445 client.pick_nodes_from_discovered(5).should == (1..5).map{|i| i.to_s}
446 client.pick_nodes_from_discovered(5).should == (1..5).map{|i| i.to_s}
450 describe "#limit_targets=" do
456 ddl.stubs(:meta).returns({:timeout => 2})
458 discoverer.stubs(:force_direct_mode?).returns(false)
459 discoverer.stubs(:ddl).returns(ddl)
460 discoverer.stubs(:discovery_method).returns("mc")
462 client.stubs("options=")
463 client.stubs(:collective).returns("mcollective")
464 client.stubs(:discoverer).returns(discoverer)
466 Config.instance.stubs(:loadconfig).with("/nonexisting").returns(true)
467 MCollective::Client.expects(:new).returns(client)
468 Config.instance.stubs(:direct_addressing).returns(true)
470 @client = Client.new("foo", {:options => {:filter => Util.empty_filter, :config => "/nonexisting"}})
473 it "should support percentages" do
474 @client.limit_targets = "10%"
475 @client.limit_targets.should == "10%"
478 it "should support integers" do
479 @client.limit_targets = 10
480 @client.limit_targets.should == 10
481 @client.limit_targets = "20"
482 @client.limit_targets.should == 20
483 @client.limit_targets = 1.1
484 @client.limit_targets.should == 1
485 @client.limit_targets = 1.7
486 @client.limit_targets.should == 1
489 it "should not invalid limits to be set" do
490 expect { @client.limit_targets = "a" }.to raise_error(/Invalid/)
491 expect { @client.limit_targets = "%1" }.to raise_error(/Invalid/)
492 expect { @client.limit_targets = "1.1" }.to raise_error(/Invalid/)
496 describe "#call_agent_batched" do
502 @ddl.stubs(:meta).returns({:timeout => 2})
504 @discoverer.stubs(:force_direct_mode?).returns(false)
505 @discoverer.stubs(:ddl).returns(@ddl)
506 @discoverer.stubs(:discovery_method).returns("mc")
508 @client.stubs("options=")
509 @client.stubs(:collective).returns("mcollective")
510 @client.stubs(:discoverer).returns(@discoverer)
512 Config.instance.stubs(:loadconfig).with("/nonexisting").returns(true)
513 MCollective::Client.expects(:new).returns(@client)
514 Config.instance.stubs(:direct_addressing).returns(true)
517 it "should require direct addressing" do
518 Config.instance.stubs(:direct_addressing).returns(false)
519 client = Client.new("foo", {:options => {:filter => Util.empty_filter, :config => "/nonexisting"}})
522 client.send(:call_agent_batched, "foo", {}, {}, 1, 1)
523 }.to raise_error("Batched requests requires direct addressing")
526 it "should require that all results be processed" do
527 client = Client.new("foo", {:options => {:filter => Util.empty_filter, :config => "/nonexisting"}})
530 client.send(:call_agent_batched, "foo", {:process_results => false}, {}, 1, 1)
531 }.to raise_error("Cannot bypass result processing for batched requests")
534 it "should only accept integer batch sizes" do
535 client = Client.new("foo", {:options => {:filter => Util.empty_filter, :config => "/nonexisting"}})
538 client.send(:call_agent_batched, "foo", {}, {}, "foo", 1)
539 }.to raise_error(/invalid value for Integer/)
542 it "should only accept float sleep times" do
543 client = Client.new("foo", {:options => {:filter => Util.empty_filter, :config => "/nonexisting"}})
546 client.send(:call_agent_batched, "foo", {}, {}, 1, "foo")
547 }.to raise_error(/invalid value for Float/)
550 it "should batch hosts in the correct size" do
551 client = Client.new("foo", {:options => {:filter => Util.empty_filter, :config => "/nonexisting", :stderr => StringIO.new}})
553 client.expects(:new_request).returns("req")
556 discovered.stubs(:size).returns(1)
557 discovered.expects(:in_groups_of).with(10).raises("spec pass")
559 client.instance_variable_set("@client", @coreclient)
560 @coreclient.stubs(:discover).returns(discovered)
561 @coreclient.stubs(:timeout_for_compound_filter).returns(0)
563 expect { client.send(:call_agent_batched, "foo", {}, {}, 10, 1) }.to raise_error("spec pass")
566 it "should force direct requests" do
567 client = Client.new("foo", {:options => {:filter => Util.empty_filter, :config => "/nonexisting", :stderr => StringIO.new}})
569 Message.expects(:new).with('req', nil, {:type => :direct_request, :agent => 'foo', :filter => nil, :options => {}, :collective => 'mcollective'}).raises("spec pass")
570 client.expects(:new_request).returns("req")
572 client.instance_variable_set("@client", @coreclient)
573 @coreclient.stubs(:discover).returns(["test"])
574 @coreclient.stubs(:timeout_for_compound_filter).returns(0)
576 expect { client.send(:call_agent_batched, "foo", {}, {}, 1, 1) }.to raise_error("spec pass")
579 it "should process blocks correctly" do
580 client = Client.new("foo", {:options => {:filter => Util.empty_filter, :config => "/nonexisting", :stderr => StringIO.new}})
583 msg.expects(:discovered_hosts=).times(10)
584 msg.expects(:create_reqid).returns("823a3419a0975c3facbde121f72ab61f")
585 msg.expects(:requestid=).with("823a3419a0975c3facbde121f72ab61f").times(10)
587 stats = {:noresponsefrom => [], :responses => 0, :blocktime => 0, :totaltime => 0, :discoverytime => 0, :requestid => "823a3419a0975c3facbde121f72ab61f"}
589 Message.expects(:new).with('req', nil, {:type => :direct_request, :agent => 'foo', :filter => nil, :options => {}, :collective => 'mcollective'}).returns(msg).times(10)
590 client.expects(:new_request).returns("req")
591 client.expects(:sleep).with(1.0).times(9)
593 client.instance_variable_set("@client", @coreclient)
594 @coreclient.stubs(:discover).returns([1,2,3,4,5,6,7,8,9,0])
595 @coreclient.expects(:req).with(msg).yields("result").times(10)
596 @coreclient.stubs(:stats).returns stats
597 @coreclient.stubs(:timeout_for_compound_filter).returns(0)
599 client.expects(:process_results_with_block).with("foo", "result", instance_of(Proc), nil).times(10)
601 result = client.send(:call_agent_batched, "foo", {}, {}, 1, 1) { }
602 result[:requestid].should == "823a3419a0975c3facbde121f72ab61f"
603 result.class.should == Stats
606 it "should return an array of results in array mode" do
607 client = Client.new("foo", {:options => {:filter => Util.empty_filter, :config => "/nonexisting", :stderr => StringIO.new}})
608 client.instance_variable_set("@client", @coreclient)
611 msg.expects(:discovered_hosts=).times(10)
612 msg.expects(:create_reqid).returns("823a3419a0975c3facbde121f72ab61f")
613 msg.expects(:requestid=).with("823a3419a0975c3facbde121f72ab61f").times(10)
615 stats = {:noresponsefrom => [], :responses => 0, :blocktime => 0, :totaltime => 0, :discoverytime => 0, :requestid => "823a3419a0975c3facbde121f72ab61f"}
617 Progress.expects(:new).never
619 Message.expects(:new).with('req', nil, {:type => :direct_request, :agent => 'foo', :filter => nil, :options => {}, :collective => 'mcollective'}).returns(msg).times(10)
620 client.expects(:new_request).returns("req")
621 client.expects(:sleep).with(1.0).times(9)
623 @coreclient.stubs(:discover).returns([1,2,3,4,5,6,7,8,9,0])
624 @coreclient.expects(:req).with(msg).yields("result").times(10)
625 @coreclient.stubs(:stats).returns stats
626 @coreclient.stubs(:timeout_for_compound_filter).returns(0)
628 client.expects(:process_results_without_block).with("result", "foo", nil).returns("rspec").times(10)
630 client.send(:call_agent_batched, "foo", {}, {}, 1, 1).should == ["rspec", "rspec", "rspec", "rspec", "rspec", "rspec", "rspec", "rspec", "rspec", "rspec"]
632 client.stats[:requestid].should == "823a3419a0975c3facbde121f72ab61f"
636 describe "#batch_sleep_time=" do
637 it "should correctly set the sleep" do
638 Config.instance.stubs(:direct_addressing).returns(true)
640 client = Client.new("foo", {:options => {:filter => Util.empty_filter, :config => "/nonexisting"}})
641 client.batch_sleep_time = 5
642 client.batch_sleep_time.should == 5
645 it "should only allow batch sleep to be set for direct addressing capable clients" do
646 Config.instance.stubs(:direct_addressing).returns(false)
647 Config.instance.stubs(:loadconfig).with("/nonexisting").returns(true)
648 client = Client.new("foo", {:options => {:filter => Util.empty_filter, :config => "/nonexisting"}})
650 expect { client.batch_sleep_time = 5 }.to raise_error("Can only set batch sleep time if direct addressing is supported")
654 describe "#batch_size=" do
655 it "should correctly set the size" do
656 Config.instance.stubs(:direct_addressing).returns(true)
658 client = Client.new("foo", {:options => {:filter => Util.empty_filter, :config => "/nonexisting"}})
659 client.batch_mode.should == false
660 client.batch_size = 5
661 client.batch_size.should == 5
662 client.batch_mode.should == true
665 it "should only allow batch size to be set for direct addressing capable clients" do
666 Config.instance.stubs(:loadconfig).with("/nonexisting").returns(true)
667 Config.instance.stubs(:direct_addressing).returns(false)
668 client = Client.new("foo", {:options => {:filter => Util.empty_filter, :config => "/nonexisting"}})
670 expect { client.batch_size = 5 }.to raise_error("Can only set batch size if direct addressing is supported")
673 it "should support disabling batch mode when supplied a batch size of 0" do
674 Config.instance.stubs(:direct_addressing).returns(true)
676 client = Client.new("foo", {:options => {:filter => Util.empty_filter, :config => "/nonexisting"}})
677 client.batch_size = 5
678 client.batch_mode.should == true
679 client.batch_size = 0
680 client.batch_mode.should == false
684 describe "#discover" do
685 it "should not accept invalid flags" do
686 Config.instance.stubs(:direct_addressing).returns(true)
687 client = Client.new("foo", {:options => {:filter => Util.empty_filter, :config => "/nonexisting"}})
689 expect { client.discover(:rspec => :rspec) }.to raise_error("Unknown option rspec passed to discover")
692 it "should reset when :json, :hosts or :nodes are provided" do
693 Config.instance.stubs(:direct_addressing).returns(true)
694 client = Client.new("foo", {:options => {:filter => Util.empty_filter, :config => "/nonexisting"}})
695 client.expects(:reset).times(3)
696 client.discover(:hosts => ["one"])
697 client.discover(:nodes => ["one"])
698 client.discover(:json => ["one"])
701 it "should only allow discovery data in direct addressing mode" do
702 Config.instance.stubs(:direct_addressing).returns(false)
703 client = Client.new("foo", {:options => {:filter => Util.empty_filter, :config => "/nonexisting"}})
704 client.expects(:reset).once
707 client.discover(:nodes => ["one"])
708 }.to raise_error("Can only supply discovery data if direct_addressing is enabled")
711 it "should parse :nodes and :hosts and force direct requests" do
712 Config.instance.stubs(:direct_addressing).returns(true)
713 Helpers.expects(:extract_hosts_from_array).with(["one"]).returns(["one"]).twice
715 client = Client.new("foo", {:options => {:filter => Util.empty_filter, :config => "/nonexisting"}})
716 client.discover(:nodes => ["one"]).should == ["one"]
717 client.discover(:hosts => ["one"]).should == ["one"]
718 client.instance_variable_get("@force_direct_request").should == true
719 client.instance_variable_get("@discovered_agents").should == ["one"]
722 it "should parse :json and force direct requests" do
723 Config.instance.stubs(:direct_addressing).returns(true)
724 Helpers.expects(:extract_hosts_from_json).with('["one"]').returns(["one"]).once
726 client = Client.new("foo", {:options => {:filter => Util.empty_filter, :config => "/nonexisting"}})
727 client.discover(:json => '["one"]').should == ["one"]
728 client.instance_variable_get("@force_direct_request").should == true
729 client.instance_variable_get("@discovered_agents").should == ["one"]
732 it "should not set direct mode for non 'mc' discovery methods" do
733 Config.instance.stubs(:direct_addressing).returns(true)
735 client = Client.new("foo", {:options => {:discovery_method => "rspec", :filter => {"identity" => ["foo"], "agent" => []}, :config => "/nonexisting"}})
736 @coreclient.expects(:discover).returns(["foo"])
739 client.instance_variable_get("@discovered_agents").should == ["foo"]
740 client.instance_variable_get("@force_direct_request").should == false
743 it "should force direct mode for non regex identity filters" do
744 Config.instance.stubs(:direct_addressing).returns(true)
746 client = Client.new("foo", {:options => {:discovery_method => "mc", :filter => {"identity" => ["foo"], "agent" => []}, :config => "/nonexisting"}})
748 client.instance_variable_get("@discovered_agents").should == ["foo"]
749 client.instance_variable_get("@force_direct_request").should == true
752 it "should not set direct mode if its disabled" do
753 Config.instance.stubs(:direct_addressing).returns(false)
755 client = Client.new("foo", {:options => {:discovery_method => "mc", :filter => {"identity" => ["foo"], "agent" => []}, :config => "/nonexisting"}})
758 client.instance_variable_get("@force_direct_request").should == false
759 client.instance_variable_get("@discovered_agents").should == ["foo"]
762 it "should not set direct mode for regex identities" do
763 Config.instance.stubs(:direct_addressing).returns(false)
765 rpcclient = Client.new("foo", {:options => {:filter => {"identity" => ["/foo/"], "agent" => []}, :config => "/nonexisting"}})
767 rpcclient.client.expects(:discover).with({'identity' => ['/foo/'], 'agent' => ['foo']}, 2).once.returns(["foo"])
770 rpcclient.instance_variable_get("@force_direct_request").should == false
771 rpcclient.instance_variable_get("@discovered_agents").should == ["foo"]
774 it "should print status to stderr if in verbose mode" do
775 @stderr.expects(:print).with("Discovering hosts using the mc method for 2 second(s) .... ")
776 @stderr.expects(:puts).with(1)
778 rpcclient = Client.new("foo", {:options => {:filter => Util.empty_filter, :config => "/nonexisting", :verbose => true, :disctimeout => 2, :stderr => @stderr, :stdout => @stdout}})
780 rpcclient.client.expects(:discover).with({'identity' => [], 'compound' => [], 'fact' => [], 'agent' => ['foo'], 'cf_class' => []}, 2).returns(["foo"])
785 it "should not print status to stderr if in nonverbose mode" do
786 @stderr.expects(:print).never
787 @stderr.expects(:puts).never
789 rpcclient = Client.new("foo", {:options => {:filter => Util.empty_filter, :config => "/nonexisting", :verbose => false, :disctimeout => 2, :stderr => @stderr, :stdout => @stdout}})
790 rpcclient.client.expects(:discover).with({'identity' => [], 'compound' => [], 'fact' => [], 'agent' => ['foo'], 'cf_class' => []}, 2).returns(["foo"])
795 it "should record the start and end times" do
796 Stats.any_instance.expects(:time_discovery).with(:start)
797 Stats.any_instance.expects(:time_discovery).with(:end)
799 rpcclient = Client.new("foo", {:options => {:filter => Util.empty_filter, :config => "/nonexisting", :verbose => false, :disctimeout => 2}})
800 rpcclient.client.expects(:discover).with({'identity' => [], 'compound' => [], 'fact' => [], 'agent' => ['foo'], 'cf_class' => []}, 2).returns(["foo"])
805 it "should discover using limits in :first rpclimit mode given a number" do
806 Config.instance.stubs(:rpclimitmethod).returns(:first)
807 rpcclient = Client.new("foo", {:options => {:filter => Util.empty_filter, :config => "/nonexisting", :verbose => false, :disctimeout => 2}})
808 rpcclient.client.expects(:discover).with({'identity' => [], 'compound' => [], 'fact' => [], 'agent' => ['foo'], 'cf_class' => []}, 2, 1).returns(["foo"])
810 rpcclient.limit_targets = 1
815 it "should not discover using limits in :first rpclimit mode given a string" do
816 Config.instance.stubs(:rpclimitmethod).returns(:first)
817 rpcclient = Client.new("foo", {:options => {:filter => Util.empty_filter, :config => "/nonexisting", :verbose => false, :disctimeout => 2}})
818 rpcclient.client.expects(:discover).with({'identity' => [], 'compound' => [], 'fact' => [], 'agent' => ['foo'], 'cf_class' => []}, 2).returns(["foo"])
819 rpcclient.limit_targets = "10%"
824 it "should not discover using limits when not in :first mode" do
825 Config.instance.stubs(:rpclimitmethod).returns(:random)
827 rpcclient = Client.new("foo", {:options => {:filter => Util.empty_filter, :config => "/nonexisting", :verbose => false, :disctimeout => 2}})
828 rpcclient.client.expects(:discover).with({'identity' => [], 'compound' => [], 'fact' => [], 'agent' => ['foo'], 'cf_class' => []}, 2).returns(["foo"])
830 rpcclient.limit_targets = 1
834 it "should ensure force_direct mode is false when doing traditional discovery" do
835 rpcclient = Client.new("foo", {:options => {:filter => Util.empty_filter, :config => "/nonexisting", :verbose => false, :disctimeout => 2}})
836 rpcclient.client.expects(:discover).with({'identity' => [], 'compound' => [], 'fact' => [], 'agent' => ['foo'], 'cf_class' => []}, 2).returns(["foo"])
838 rpcclient.instance_variable_set("@force_direct_request", true)
840 rpcclient.instance_variable_get("@force_direct_request").should == false
843 it "should store discovered nodes in stats" do
844 rpcclient = Client.new("foo", {:options => {:filter => Util.empty_filter, :config => "/nonexisting", :verbose => false, :disctimeout => 2}})
845 rpcclient.client.expects(:discover).with({'identity' => [], 'compound' => [], 'fact' => [], 'agent' => ['foo'], 'cf_class' => []}, 2).returns(["foo"])
848 rpcclient.stats.discovered_nodes.should == ["foo"]
851 it "should save discovered nodes in RPC" do
852 rpcclient = Client.new("foo", {:options => {:filter => Util.empty_filter, :config => "/nonexisting", :verbose => false, :disctimeout => 2}})
853 rpcclient.client.expects(:discover).with({'identity' => [], 'compound' => [], 'fact' => [], 'agent' => ['foo'], 'cf_class' => []}, 2).returns(["foo"])
855 RPC.expects(:discovered).with(["foo"]).once