mcollective-client 2.5.3 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. data/lib/mcollective.rb +1 -1
  2. data/lib/mcollective/application.rb +21 -6
  3. data/lib/mcollective/client.rb +7 -0
  4. data/lib/mcollective/config.rb +13 -1
  5. data/lib/mcollective/connector/base.rb +2 -0
  6. data/lib/mcollective/facts/base.rb +18 -5
  7. data/lib/mcollective/log.rb +7 -0
  8. data/lib/mcollective/logger/base.rb +12 -8
  9. data/lib/mcollective/logger/file_logger.rb +7 -0
  10. data/lib/mcollective/message.rb +1 -1
  11. data/lib/mcollective/optionparser.rb +4 -0
  12. data/lib/mcollective/registration/base.rb +24 -10
  13. data/lib/mcollective/rpc/agent.rb +7 -1
  14. data/lib/mcollective/rpc/client.rb +89 -35
  15. data/lib/mcollective/rpc/helpers.rb +8 -3
  16. data/lib/mcollective/rpc/result.rb +4 -0
  17. data/lib/mcollective/rpc/stats.rb +6 -2
  18. data/lib/mcollective/shell.rb +2 -0
  19. data/lib/mcollective/ssl.rb +5 -0
  20. data/lib/mcollective/util.rb +29 -1
  21. data/lib/mcollective/validator.rb +9 -4
  22. data/spec/spec_helper.rb +6 -0
  23. data/spec/unit/config_spec.rb +10 -0
  24. data/spec/unit/connector/base_spec.rb +28 -0
  25. data/spec/unit/facts/base_spec.rb +35 -0
  26. data/spec/unit/log_spec.rb +9 -0
  27. data/spec/unit/logger/base_spec.rb +12 -2
  28. data/spec/unit/logger/file_logger_spec.rb +82 -0
  29. data/spec/unit/plugins/mcollective/application/plugin_spec.rb +1 -0
  30. data/spec/unit/plugins/mcollective/connector/activemq_spec.rb +44 -17
  31. data/spec/unit/plugins/mcollective/connector/rabbitmq_spec.rb +20 -19
  32. data/spec/unit/plugins/mcollective/data/fact_data_spec.rb +92 -0
  33. data/spec/unit/registration/base_spec.rb +46 -0
  34. data/spec/unit/rpc/agent_spec.rb +37 -0
  35. data/spec/unit/rpc/client_spec.rb +68 -15
  36. data/spec/unit/rpc/result_spec.rb +21 -0
  37. data/spec/unit/runner_spec.rb +97 -19
  38. data/spec/unit/shell_spec.rb +5 -0
  39. data/spec/unit/ssl_spec.rb +5 -0
  40. data/spec/unit/util_spec.rb +163 -1
  41. metadata +215 -209
@@ -47,9 +47,9 @@ module MCollective
47
47
 
48
48
  let(:subscription) do
49
49
  sub = mock
50
- sub.stubs("<<").returns(true)
51
- sub.stubs("include?").returns(false)
52
- sub.stubs("delete").returns(false)
50
+ sub.stubs(:<<).returns(true)
51
+ sub.stubs(:include?).returns(false)
52
+ sub.stubs(:delete).returns(false)
53
53
  sub
54
54
  end
55
55
 
@@ -432,8 +432,8 @@ module MCollective
432
432
  msg.stubs(:ttl).returns(60)
433
433
  msg.expects(:discovered_hosts).returns(["one", "two"])
434
434
 
435
- connection.expects(:publish).with('/exchange/mcollective_directed/one', 'msg', {'reply-to' => '/temp-queue/mcollective_reply_agent', 'expiration' => '70000'})
436
- connection.expects(:publish).with('/exchange/mcollective_directed/two', 'msg', {'reply-to' => '/temp-queue/mcollective_reply_agent', 'expiration' => '70000'})
435
+ connection.expects(:publish).with('/exchange/mcollective_directed/one', 'msg', {'reply-to' => '/topic/mcollective', 'expiration' => '70000'})
436
+ connection.expects(:publish).with('/exchange/mcollective_directed/two', 'msg', {'reply-to' => '/topic/mcollective', 'expiration' => '70000'})
437
437
 
438
438
  connector.publish(msg)
439
439
  end
@@ -447,12 +447,12 @@ module MCollective
447
447
  end
448
448
 
449
449
  it "should use the make_target correctly" do
450
- connector.expects("make_target").with("test", :broadcast, "mcollective").returns({:name => "test", :headers => {}})
450
+ connector.expects(:make_target).with("test", :broadcast, "mcollective").returns({:name => "test", :headers => {}})
451
451
  connector.subscribe("test", :broadcast, "mcollective")
452
452
  end
453
453
 
454
454
  it "should check for existing subscriptions" do
455
- connector.expects("make_target").with("test", :broadcast, "mcollective").returns({:name => "test", :headers => {}, :id => "rspec"})
455
+ connector.expects(:make_target).with("test", :broadcast, "mcollective").returns({:name => "test", :headers => {}, :id => "rspec"})
456
456
  subscription.expects("include?").with("rspec").returns(false)
457
457
  connection.expects(:subscribe).never
458
458
 
@@ -460,14 +460,14 @@ module MCollective
460
460
  end
461
461
 
462
462
  it "should subscribe to the middleware" do
463
- connector.expects("make_target").with("test", :broadcast, "mcollective").returns({:name => "test", :headers => {}, :id => "rspec"})
463
+ connector.expects(:make_target).with("test", :broadcast, "mcollective").returns({:name => "test", :headers => {}, :id => "rspec"})
464
464
  connection.expects(:subscribe).with("test", {}, "rspec")
465
465
  connector.subscribe("test", :broadcast, "mcollective")
466
466
  end
467
467
 
468
468
  it "should add to the list of subscriptions" do
469
- connector.expects("make_target").with("test", :broadcast, "mcollective").returns({:name => "test", :headers => {}, :id => "rspec"})
470
- subscription.expects("<<").with("rspec")
469
+ connector.expects(:make_target).with("test", :broadcast, "mcollective").returns({:name => "test", :headers => {}, :id => "rspec"})
470
+ subscription.expects(:<<).with("rspec")
471
471
  connector.subscribe("test", :broadcast, "mcollective")
472
472
  end
473
473
 
@@ -478,7 +478,7 @@ module MCollective
478
478
 
479
479
  it "should subscribe to :reply messages when use_reply_exchange is set" do
480
480
  Rabbitmq.any_instance.stubs(:get_bool_option).with("rabbitmq.use_reply_exchange", false).returns(true)
481
- connector.expects("make_target").with("test", :reply, "mcollective").returns({:name => "test", :headers => {}, :id => "rspec"})
481
+ connector.expects(:make_target).with("test", :reply, "mcollective").returns({:name => "test", :headers => {}, :id => "rspec"})
482
482
  connection.expects(:subscribe).with("test", {}, "rspec").once
483
483
 
484
484
  connector.subscribe("test", :reply, "mcollective")
@@ -487,19 +487,19 @@ module MCollective
487
487
 
488
488
  describe "#unsubscribe" do
489
489
  it "should use make_target correctly" do
490
- connector.expects("make_target").with("test", :broadcast, "mcollective").returns({:name => "test", :headers => {}})
490
+ connector.expects(:make_target).with("test", :broadcast, "mcollective").returns({:name => "test", :headers => {}})
491
491
  connector.unsubscribe("test", :broadcast, "mcollective")
492
492
  end
493
493
 
494
494
  it "should unsubscribe from the target" do
495
- connector.expects("make_target").with("test", :broadcast, "mcollective").returns({:name => "test", :headers => {}, :id => "rspec"})
495
+ connector.expects(:make_target).with("test", :broadcast, "mcollective").returns({:name => "test", :headers => {}, :id => "rspec"})
496
496
  connection.expects(:unsubscribe).with("test", {}, "rspec").once
497
497
 
498
498
  connector.unsubscribe("test", :broadcast, "mcollective")
499
499
  end
500
500
 
501
501
  it "should delete the source from subscriptions" do
502
- connector.expects("make_target").with("test", :broadcast, "mcollective").returns({:name => "test", :headers => {}, :id => "rspec"})
502
+ connector.expects(:make_target).with("test", :broadcast, "mcollective").returns({:name => "test", :headers => {}, :id => "rspec"})
503
503
  subscription.expects(:delete).with("rspec").once
504
504
 
505
505
  connector.unsubscribe("test", :broadcast, "mcollective")
@@ -512,7 +512,7 @@ module MCollective
512
512
 
513
513
  it "should unsubscribe from :reply messages when use_reply_exchange is set" do
514
514
  Rabbitmq.any_instance.stubs(:get_bool_option).with("rabbitmq.use_reply_exchange", false).returns(true)
515
- connector.expects("make_target").with("test", :reply, "mcollective").returns({:name => "test", :headers => {}, :id => "rspec"})
515
+ connector.expects(:make_target).with("test", :reply, "mcollective").returns({:name => "test", :headers => {}, :id => "rspec"})
516
516
  connection.expects(:unsubscribe).with("test", {}, "rspec").once
517
517
 
518
518
  connector.unsubscribe("test", :reply, "mcollective")
@@ -618,23 +618,24 @@ module MCollective
618
618
  end
619
619
 
620
620
  it "should create correct targets" do
621
+ Client.stubs(:request_sequence).returns(42)
621
622
  connector.make_target("test", :reply, "mcollective").should eq({
622
- :name => "/exchange/mcollective_reply/rspec_#{$$}",
623
+ :name => "/exchange/mcollective_reply/rspec_#{$$}_42",
623
624
  :headers => {},
624
625
  :id => "mcollective_test_replies",
625
626
  })
626
627
  connector.make_target("test", :broadcast, "mcollective").should eq({
627
628
  :name => "/exchange/mcollective_broadcast/test",
628
- :headers => { "reply-to" => "/exchange/mcollective_reply/rspec_#{$$}" },
629
+ :headers => { "reply-to" => "/exchange/mcollective_reply/rspec_#{$$}_42" },
629
630
  :id => "mcollective_broadcast_test"
630
631
  })
631
632
  connector.make_target("test", :request, "mcollective").should eq({
632
633
  :name => "/exchange/mcollective_broadcast/test",
633
- :headers => { "reply-to" => "/exchange/mcollective_reply/rspec_#{$$}" },
634
+ :headers => { "reply-to" => "/exchange/mcollective_reply/rspec_#{$$}_42" },
634
635
  :id => "mcollective_broadcast_test",
635
636
  })
636
637
  connector.make_target("test", :direct_request, "mcollective", nil, "rspec").should eq({
637
- :headers => { "reply-to" => "/exchange/mcollective_reply/rspec_#{$$}" },
638
+ :headers => { "reply-to" => "/exchange/mcollective_reply/rspec_#{$$}_42" },
638
639
  :name => "/exchange/mcollective_directed/rspec",
639
640
  :id => nil
640
641
  })
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env rspec
2
+
3
+ require 'spec_helper'
4
+
5
+ require File.dirname(__FILE__) + "/../../../../../plugins/mcollective/data/fact_data.rb"
6
+
7
+ module MCollective
8
+ module Data
9
+ describe Fact_data do
10
+ describe "#query_data" do
11
+ before :each do
12
+ @ddl = mock('DDL')
13
+ @ddl.stubs(:dataquery_interface).returns({:output => {}})
14
+ @ddl.stubs(:meta).returns({:timeout => 1})
15
+ DDL.stubs(:new).returns(@ddl)
16
+ @plugin = Fact_data.new
17
+
18
+ facts_plugin = mock('fact_plugin')
19
+ PluginManager.stubs(:[]).with('facts_plugin').returns(facts_plugin)
20
+
21
+ facts_plugin.expects(:get_facts).returns({
22
+ "foo" => "foo-value",
23
+ "one" => {
24
+ "one" => "one-one",
25
+ "two" => {
26
+ "one" => "one-two-one",
27
+ "two" => "one-two-two",
28
+ },
29
+ },
30
+ "some_array" => [
31
+ "a",
32
+ "b",
33
+ ],
34
+ })
35
+ end
36
+
37
+ it 'should return an unfound fact as false' do
38
+ @plugin.query_data("bar")
39
+
40
+ @plugin.result[:exists].should == false
41
+ @plugin.result[:value].should == false
42
+ @plugin.result[:value_encoding].should == false
43
+ end
44
+
45
+ it "should be able to find a value at top level" do
46
+ @plugin.query_data("foo")
47
+
48
+ @plugin.result[:exists].should == true
49
+ @plugin.result[:value].should == "foo-value"
50
+ @plugin.result[:value_encoding].should == 'text/plain'
51
+ end
52
+
53
+ it 'should be able to walk down to a hash element' do
54
+ @plugin.query_data("one.one")
55
+
56
+ @plugin.result[:exists].should == true
57
+ @plugin.result[:value].should == "one-one"
58
+ @plugin.result[:value_encoding].should == 'text/plain'
59
+ end
60
+
61
+ it 'should be able to walk down to a hash' do
62
+ @plugin.query_data("one.two")
63
+
64
+ @plugin.result[:exists].should == true
65
+
66
+ @plugin.result[:value].should == {
67
+ "one" => "one-two-one",
68
+ "two" => "one-two-two",
69
+ }.to_json
70
+ @plugin.result[:value_encoding].should == 'application/json'
71
+
72
+ end
73
+
74
+ it 'should be able to walk down to an array' do
75
+ @plugin.query_data("some_array")
76
+
77
+ @plugin.result[:exists].should == true
78
+ @plugin.result[:value].should == [ "a", "b" ].to_json
79
+ @plugin.result[:value_encoding].should == 'application/json'
80
+ end
81
+
82
+ it 'should be able to walk down to an array element' do
83
+ @plugin.query_data("some_array.0")
84
+
85
+ @plugin.result[:exists].should == true
86
+ @plugin.result[:value].should == "a"
87
+ @plugin.result[:value_encoding].should == 'text/plain'
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
@@ -5,6 +5,9 @@ require 'spec_helper'
5
5
  module MCollective
6
6
  module Registration
7
7
  describe Base do
8
+
9
+ let(:connection) { mock }
10
+
8
11
  before do
9
12
  @config = mock
10
13
  @config.stubs(:identity).returns("rspec")
@@ -18,7 +21,20 @@ module MCollective
18
21
  it "should provide access the main configuration class" do
19
22
  @reg.config.should == @config
20
23
  end
24
+ end
25
+
26
+ describe "#run" do
27
+ it "should not start the publish_thread if the registration interval is 0" do
28
+ @reg.stubs(:interval).returns(0)
29
+ Thread.expects(:new).never
30
+ @reg.run(connection).should == false
31
+ end
21
32
 
33
+ it "should start the publish_thread" do
34
+ @reg.stubs(:interval).returns(1)
35
+ Thread.expects(:new).returns(true)
36
+ @reg.run(connection).should be_true
37
+ end
22
38
  end
23
39
 
24
40
  describe "#identity" do
@@ -72,6 +88,36 @@ module MCollective
72
88
  @reg.publish("message")
73
89
  end
74
90
  end
91
+
92
+ describe "#body" do
93
+ it "should fail if body hasn't been implemented" do
94
+ expect {
95
+ @reg.body
96
+ }.to raise_error
97
+ end
98
+ end
99
+
100
+ describe "#publish_thread" do
101
+ before(:each) do
102
+ @reg.expects(:loop).returns("looping")
103
+ end
104
+
105
+ it "should splay if splay is set" do
106
+ @reg.stubs(:interval).returns(1)
107
+ @config.stubs(:registration_splay).returns(true)
108
+ Log.expects(:debug)
109
+ @reg.expects(:sleep)
110
+ @reg.send(:publish_thread, connection)
111
+ end
112
+
113
+ it "should not splay if splay isn't set" do
114
+ @reg.stubs(:interval).returns(1)
115
+ @config.stubs(:registration_splay).returns(false)
116
+ Log.expects(:debug).never
117
+ @reg.expects(:sleep).never
118
+ @reg.send(:publish_thread, connection)
119
+ end
120
+ end
75
121
  end
76
122
  end
77
123
  end
@@ -151,6 +151,43 @@ module MCollective
151
151
  end
152
152
  end
153
153
 
154
+ describe "#activate?" do
155
+ class Test < MCollective::RPC::Agent;end
156
+
157
+ let(:config) do
158
+ conf = mock
159
+ conf.stubs(:pluginconf).returns({})
160
+ conf
161
+ end
162
+
163
+ before(:each) do
164
+ Config.stubs(:instance).returns(config)
165
+ Log.stubs(:debug)
166
+ end
167
+
168
+ it "should return true if plugins are globally enabled" do
169
+ config.stubs(:activate_agents).returns(true)
170
+ Test.activate?.should == true
171
+ end
172
+
173
+ it "should return true if plugins are globally disabled but locally enabled" do
174
+ config.stubs(:activate_agents).returns(false)
175
+ config.pluginconf['test.activate_agent'] = true
176
+ Test.activate?.should == true
177
+ end
178
+
179
+ it "should return false if plugins are globally disabled" do
180
+ config.stubs(:activate_agents).returns(false)
181
+ Test.activate?.should == false
182
+ end
183
+
184
+ it "should return false if plugins are globally enabled but locally disabled" do
185
+ config.stubs(:activate_agents).returns(true)
186
+ config.pluginconf['test.activate_agent'] = false
187
+ Test.activate?.should == false
188
+ end
189
+ end
190
+
154
191
  describe "#load_ddl" do
155
192
  it "should load the correct DDL" do
156
193
  ddl = stub
@@ -102,18 +102,6 @@ module MCollective
102
102
  @client.process_results_with_block("rspec", response, blk, nil)
103
103
  end
104
104
 
105
- it "should raise correct exceptions on failure" do
106
- blk = Proc.new {}
107
-
108
- @client.stubs(:rpc_result_from_reply)
109
-
110
- [[2, UnknownRPCAction], [3, MissingRPCData], [4, InvalidRPCData], [5, UnknownRPCError]].each do |err|
111
- response = {:senderid => "rspec", :body => {:statuscode => err[0]}}
112
-
113
- expect { @client.process_results_with_block("rspec", response, blk, nil) }.to raise_error(err[1])
114
- end
115
- end
116
-
117
105
  it "should pass raw results for single arity blocks" do
118
106
  response = {:senderid => "rspec", :body => {:statuscode => 1}}
119
107
  blk = Proc.new {|r| r.should == response}
@@ -560,11 +548,21 @@ module MCollective
560
548
  @client.limit_targets.should == 1
561
549
  end
562
550
 
563
- it "should not invalid limits to be set" do
551
+ it "should not allow invalid limits to be set" do
564
552
  expect { @client.limit_targets = "a" }.to raise_error(/Invalid/)
565
553
  expect { @client.limit_targets = "%1" }.to raise_error(/Invalid/)
566
554
  expect { @client.limit_targets = "1.1" }.to raise_error(/Invalid/)
567
555
  end
556
+
557
+ it "should reset @limit_targets" do
558
+ @client.limit_targets = 10
559
+ @client.limit_targets.should == 10
560
+ @client.limit_targets = nil
561
+ @client.limit_targets.should == nil
562
+ @client.limit_targets = 10
563
+ @client.limit_targets = false
564
+ @client.limit_targets.should == nil
565
+ end
568
566
  end
569
567
 
570
568
  describe "#fire_and_forget_request" do
@@ -686,12 +684,12 @@ module MCollective
686
684
  }.to raise_error("Cannot bypass result processing for batched requests")
687
685
  end
688
686
 
689
- it "should only accept integer batch sizes" do
687
+ it "should only accept valid batch sizes" do
690
688
  client = Client.new("foo", {:options => {:filter => Util.empty_filter, :config => "/nonexisting"}})
691
689
 
692
690
  expect {
693
691
  client.send(:call_agent_batched, "foo", {}, {}, "foo", 1)
694
- }.to raise_error(/invalid value for Integer/)
692
+ }.to raise_error("batch_size must be an integer or match a percentage string (e.g. '24%'")
695
693
  end
696
694
 
697
695
  it "should only accept float sleep times" do
@@ -825,6 +823,12 @@ module MCollective
825
823
  expect { client.batch_size = 5 }.to raise_error("Can only set batch size if direct addressing is supported")
826
824
  end
827
825
 
826
+ it "should accept batch sizes as percentage strings" do
827
+ client = Client.new("foo", {:options => {:filter => Util.empty_filter, :config => "/nonexisting"}})
828
+ client.batch_size = "50%"
829
+ client.batch_size.should == "50%"
830
+ end
831
+
828
832
  it "should support disabling batch mode when supplied a batch size of 0" do
829
833
  Config.instance.stubs(:direct_addressing).returns(true)
830
834
 
@@ -1011,6 +1015,55 @@ module MCollective
1011
1015
  rpcclient.discover
1012
1016
  end
1013
1017
  end
1018
+
1019
+ describe "#determine_batch_mode" do
1020
+ let(:rpcclient) do
1021
+ rpcclient = Client.new("foo",
1022
+ {:options => {:filter => Util.empty_filter,
1023
+ :config => "/nonexisting",
1024
+ :verbose => false,
1025
+ :disctimeout => 2}})
1026
+ end
1027
+
1028
+ it "should return true when batch_mode should be set" do
1029
+ rpcclient.send(:determine_batch_mode, "1").should == true
1030
+ rpcclient.send(:determine_batch_mode, 1).should == true
1031
+ rpcclient.send(:determine_batch_mode, "1%").should == true
1032
+ end
1033
+
1034
+ it "should return false when batch_mode shouldn't be set" do
1035
+ rpcclient.send(:determine_batch_mode, "0").should == false
1036
+ rpcclient.send(:determine_batch_mode, 0).should == false
1037
+ end
1038
+ end
1039
+
1040
+ describe "#validate_batch_size" do
1041
+ let(:rpcclient) do
1042
+ rpcclient = Client.new("foo",
1043
+ {:options => {:filter => Util.empty_filter,
1044
+ :config => "/nonexisting",
1045
+ :verbose => false,
1046
+ :disctimeout => 2}})
1047
+ end
1048
+
1049
+ it "should fail when batch size is an invalid string" do
1050
+ expect {
1051
+ rpcclient.send(:validate_batch_size, "foo")
1052
+ }.to raise_error
1053
+ end
1054
+
1055
+ it "should fail when batch size is 0%" do
1056
+ expect {
1057
+ rpcclient.send(:validate_batch_size, "0%")
1058
+ }.to raise_error
1059
+ end
1060
+
1061
+ it "should fail when batch size is not a valid string or integer" do
1062
+ expect {
1063
+ rpcclient.send(:validate_batch_size, true)
1064
+ }.to raise_error
1065
+ end
1066
+ end
1014
1067
  end
1015
1068
  end
1016
1069
  end