mcollective-client 2.0.0 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of mcollective-client might be problematic. Click here for more details.

Files changed (140) hide show
  1. data/lib/mcollective.rb +32 -23
  2. data/lib/mcollective/agent.rb +5 -0
  3. data/lib/mcollective/agents.rb +5 -16
  4. data/lib/mcollective/aggregate.rb +61 -0
  5. data/lib/mcollective/aggregate/base.rb +40 -0
  6. data/lib/mcollective/aggregate/result.rb +9 -0
  7. data/lib/mcollective/aggregate/result/base.rb +25 -0
  8. data/lib/mcollective/aggregate/result/collection_result.rb +19 -0
  9. data/lib/mcollective/aggregate/result/numeric_result.rb +13 -0
  10. data/lib/mcollective/application.rb +7 -4
  11. data/lib/mcollective/applications.rb +3 -14
  12. data/lib/mcollective/cache.rb +145 -0
  13. data/lib/mcollective/client.rb +10 -87
  14. data/lib/mcollective/config.rb +22 -8
  15. data/lib/mcollective/data.rb +87 -0
  16. data/lib/mcollective/data/base.rb +67 -0
  17. data/lib/mcollective/data/result.rb +40 -0
  18. data/lib/mcollective/ddl.rb +113 -0
  19. data/lib/mcollective/ddl/agentddl.rb +185 -0
  20. data/lib/mcollective/ddl/base.rb +220 -0
  21. data/lib/mcollective/ddl/dataddl.rb +56 -0
  22. data/lib/mcollective/ddl/discoveryddl.rb +52 -0
  23. data/lib/mcollective/ddl/validatorddl.rb +6 -0
  24. data/lib/mcollective/discovery.rb +143 -0
  25. data/lib/mcollective/generators.rb +7 -0
  26. data/lib/mcollective/generators/agent_generator.rb +51 -0
  27. data/lib/mcollective/generators/base.rb +46 -0
  28. data/lib/mcollective/generators/data_generator.rb +51 -0
  29. data/lib/mcollective/generators/templates/action_snippet.erb +13 -0
  30. data/lib/mcollective/generators/templates/data_input_snippet.erb +7 -0
  31. data/lib/mcollective/generators/templates/ddl.erb +8 -0
  32. data/lib/mcollective/generators/templates/plugin.erb +7 -0
  33. data/lib/mcollective/logger/console_logger.rb +15 -15
  34. data/lib/mcollective/matcher.rb +167 -0
  35. data/lib/mcollective/matcher/parser.rb +60 -25
  36. data/lib/mcollective/matcher/scanner.rb +156 -78
  37. data/lib/mcollective/message.rb +47 -6
  38. data/lib/mcollective/monkey_patches.rb +17 -0
  39. data/lib/mcollective/optionparser.rb +18 -1
  40. data/lib/mcollective/pluginmanager.rb +3 -3
  41. data/lib/mcollective/pluginpackager.rb +10 -3
  42. data/lib/mcollective/pluginpackager/agent_definition.rb +28 -20
  43. data/lib/mcollective/pluginpackager/standard_definition.rb +11 -9
  44. data/lib/mcollective/registration/base.rb +3 -1
  45. data/lib/mcollective/rpc.rb +18 -24
  46. data/lib/mcollective/rpc/agent.rb +37 -113
  47. data/lib/mcollective/rpc/client.rb +186 -64
  48. data/lib/mcollective/rpc/helpers.rb +42 -80
  49. data/lib/mcollective/rpc/progress.rb +3 -3
  50. data/lib/mcollective/rpc/reply.rb +37 -13
  51. data/lib/mcollective/rpc/request.rb +17 -6
  52. data/lib/mcollective/rpc/result.rb +9 -5
  53. data/lib/mcollective/rpc/stats.rb +71 -24
  54. data/lib/mcollective/security/base.rb +41 -34
  55. data/lib/mcollective/shell.rb +1 -1
  56. data/lib/mcollective/ssl.rb +34 -0
  57. data/lib/mcollective/util.rb +194 -23
  58. data/lib/mcollective/validator.rb +80 -0
  59. data/spec/fixtures/util/1.in +10 -0
  60. data/spec/fixtures/util/1.out +10 -0
  61. data/spec/fixtures/util/2.in +1 -0
  62. data/spec/fixtures/util/2.out +1 -0
  63. data/spec/fixtures/util/3.in +1 -0
  64. data/spec/fixtures/util/3.out +2 -0
  65. data/spec/fixtures/util/4.in +5 -0
  66. data/spec/fixtures/util/4.out +9 -0
  67. data/spec/spec.opts +1 -1
  68. data/spec/spec_helper.rb +2 -0
  69. data/spec/unit/agents_spec.rb +34 -19
  70. data/spec/unit/aggregate/base_spec.rb +57 -0
  71. data/spec/unit/aggregate/result/base_spec.rb +28 -0
  72. data/spec/unit/aggregate/result/collection_result_spec.rb +18 -0
  73. data/spec/unit/aggregate/result/numeric_result_spec.rb +22 -0
  74. data/spec/unit/aggregate_spec.rb +110 -0
  75. data/spec/unit/application_spec.rb +8 -3
  76. data/spec/unit/applications_spec.rb +2 -2
  77. data/spec/unit/cache_spec.rb +115 -0
  78. data/spec/unit/client_spec.rb +78 -0
  79. data/spec/unit/config_spec.rb +32 -34
  80. data/spec/unit/data/base_spec.rb +90 -0
  81. data/spec/unit/data/result_spec.rb +64 -0
  82. data/spec/unit/data_spec.rb +158 -0
  83. data/spec/unit/ddl/agentddl_spec.rb +217 -0
  84. data/spec/unit/{rpc/ddl_spec.rb → ddl/base_spec.rb} +238 -224
  85. data/spec/unit/ddl/dataddl_spec.rb +65 -0
  86. data/spec/unit/ddl/discoveryddl_spec.rb +58 -0
  87. data/spec/unit/ddl_spec.rb +84 -0
  88. data/spec/unit/discovery_spec.rb +196 -0
  89. data/spec/unit/facts/base_spec.rb +1 -1
  90. data/spec/unit/generators/agent_generator_spec.rb +72 -0
  91. data/spec/unit/generators/base_spec.rb +83 -0
  92. data/spec/unit/generators/data_generator_spec.rb +37 -0
  93. data/spec/unit/generators/snippets/agent_ddl +19 -0
  94. data/spec/unit/generators/snippets/data_ddl +20 -0
  95. data/spec/unit/logger/console_logger_spec.rb +76 -0
  96. data/spec/unit/logger/syslog_logger_spec.rb +2 -2
  97. data/spec/unit/matcher/parser_spec.rb +27 -10
  98. data/spec/unit/matcher/scanner_spec.rb +108 -5
  99. data/spec/unit/matcher_spec.rb +260 -0
  100. data/spec/unit/message_spec.rb +35 -13
  101. data/spec/unit/optionparser_spec.rb +2 -2
  102. data/spec/unit/pluginpackager/agent_definition_spec.rb +59 -42
  103. data/spec/unit/pluginpackager/standard_definition_spec.rb +10 -8
  104. data/spec/unit/pluginpackager_spec.rb +131 -0
  105. data/spec/unit/plugins/mcollective/aggregate/average_spec.rb +45 -0
  106. data/spec/unit/plugins/mcollective/aggregate/sum_spec.rb +31 -0
  107. data/spec/unit/plugins/mcollective/aggregate/summary_spec.rb +45 -0
  108. data/spec/unit/plugins/mcollective/connector/activemq_spec.rb +1 -1
  109. data/spec/unit/plugins/mcollective/connector/rabbitmq_spec.rb +478 -0
  110. data/spec/unit/plugins/mcollective/connector/stomp_spec.rb +2 -0
  111. data/spec/unit/plugins/mcollective/data/agent_data_spec.rb +43 -0
  112. data/spec/unit/plugins/mcollective/data/fstat_data_spec.rb +135 -0
  113. data/spec/unit/plugins/mcollective/discovery/flatfile_spec.rb +48 -0
  114. data/spec/unit/plugins/mcollective/discovery/mc_spec.rb +40 -0
  115. data/spec/unit/plugins/mcollective/packagers/debpackage_packager_spec.rb +41 -15
  116. data/spec/unit/plugins/mcollective/packagers/ospackage_spec.rb +1 -1
  117. data/spec/unit/plugins/mcollective/packagers/rpmpackage_packager_spec.rb +22 -38
  118. data/spec/unit/plugins/mcollective/validator/array_validator_spec.rb +19 -0
  119. data/spec/unit/plugins/mcollective/validator/ipv4address_validator_spec.rb +19 -0
  120. data/spec/unit/plugins/mcollective/validator/ipv6address_validator_spec.rb +19 -0
  121. data/spec/unit/plugins/mcollective/validator/length_validator_spec.rb +19 -0
  122. data/spec/unit/plugins/mcollective/validator/regex_validator_spec.rb +19 -0
  123. data/spec/unit/plugins/mcollective/validator/shellsafe_validator_spec.rb +21 -0
  124. data/spec/unit/plugins/mcollective/validator/typecheck_validator_spec.rb +23 -0
  125. data/spec/unit/registration/base_spec.rb +1 -1
  126. data/spec/unit/rpc/actionrunner_spec.rb +2 -2
  127. data/spec/unit/rpc/agent_spec.rb +41 -65
  128. data/spec/unit/rpc/client_spec.rb +430 -134
  129. data/spec/unit/rpc/reply_spec.rb +31 -1
  130. data/spec/unit/rpc/request_spec.rb +33 -12
  131. data/spec/unit/rpc/result_spec.rb +7 -0
  132. data/spec/unit/rpc/stats_spec.rb +14 -14
  133. data/spec/unit/rpc_spec.rb +16 -0
  134. data/spec/unit/security/base_spec.rb +8 -8
  135. data/spec/unit/ssl_spec.rb +20 -2
  136. data/spec/unit/string_spec.rb +15 -0
  137. data/spec/unit/util_spec.rb +141 -21
  138. data/spec/unit/validator_spec.rb +67 -0
  139. metadata +145 -7
  140. data/lib/mcollective/rpc/ddl.rb +0 -258
@@ -6,7 +6,7 @@ module MCollective
6
6
  module PluginPackager
7
7
  describe StandardDefinition do
8
8
  before :each do
9
- PluginPackager.expects(:get_metadata).once.returns({:name => "foo"})
9
+ PluginPackager.expects(:get_metadata).once.returns({:name => "foo", :version => 1})
10
10
  end
11
11
 
12
12
  describe "#initialize" do
@@ -16,14 +16,15 @@ module MCollective
16
16
  end
17
17
 
18
18
  it "should set dependencies if present" do
19
- plugin = StandardDefinition.new(".", "test plugin", nil, nil, nil, nil, ["foo"], {}, "testplugin")
20
- plugin.dependencies.should == ["foo"]
19
+ plugin = StandardDefinition.new(".", "test plugin", nil, nil, nil, nil, [{:name => "foo", :version => nil}], {}, "testplugin")
20
+ plugin.dependencies.should == [{:name => "foo", :version => nil},
21
+ {:name => "mcollective-common", :version => nil}]
21
22
  end
22
23
 
23
- it "should set mc server, client and common dependencies" do
24
- plugin = StandardDefinition.new(".", "test plugin", nil, nil, nil, nil, [], {:server => "pe-mcollective"}, "testplugin")
25
- plugin.mcserver.should == "pe-mcollective"
26
- plugin.mccommon.should == "mcollective-common"
24
+ it "should set mc name and version dependencies" do
25
+ plugin = StandardDefinition.new(".", "test plugin", nil, nil, nil, nil, [], {:mcname => "pe-mcollective", :mcversion => "1"}, "testplugin")
26
+ plugin.mcname.should == "pe-mcollective"
27
+ plugin.mcversion.should == "1"
27
28
  end
28
29
  end
29
30
 
@@ -61,7 +62,8 @@ module MCollective
61
62
  Dir.expects(:glob).with("./testplugin/*").returns(["file.rb"])
62
63
  plugin = StandardDefinition.new(".", nil, nil, nil, nil, nil, [], {}, "testplugin")
63
64
  plugin.packagedata["testplugin"][:files].should == ["file.rb"]
64
- plugin.packagedata["testplugin"][:dependencies].should == ["mcollective", "mcollective-foo-common"]
65
+ plugin.packagedata["testplugin"][:dependencies].should == [{:name => "mcollective-common", :version => nil},
66
+ {:name => "mcollective-foo-common", :version => 1}]
65
67
  end
66
68
  end
67
69
 
@@ -0,0 +1,131 @@
1
+ #!/usr/bin/enn rspec
2
+
3
+ require 'spec_helper'
4
+
5
+ module MCollective
6
+ describe PluginPackager do
7
+ describe "#load_packagers" do
8
+ it "should load all PluginPackager plugins" do
9
+ PluginManager.expects(:find_and_load).with("pluginpackager")
10
+ PluginPackager.load_packagers
11
+ end
12
+ end
13
+
14
+ describe "#[]" do
15
+ it "should return the correct class" do
16
+ PluginPackager.expects(:const_get).with("Foo").returns(:foo)
17
+ result = PluginPackager["Foo"]
18
+ result.should == :foo
19
+ end
20
+
21
+ it "should do something else" do
22
+ expect{
23
+ PluginPackager["Bar"]
24
+ }.to raise_error(NameError, 'uninitialized constant MCollective::PluginPackager::Bar')
25
+ end
26
+ end
27
+
28
+ describe "#get_metadata" do
29
+ it "should raise an exception if the ddl file can't be loaded" do
30
+ DDL.expects(:new).with("package", :foo, false)
31
+ File.stubs(:join)
32
+ Dir.stubs(:glob).returns('')
33
+ expect{
34
+ PluginPackager.get_metadata("/tmp", "foo")
35
+ }.to raise_error(RuntimeError)
36
+ end
37
+
38
+ it "should load the ddl file and return the metadata" do
39
+ ddl = mock
40
+ DDL.expects(:new).with("package", :foo, false).returns(ddl)
41
+ File.stubs(:join)
42
+ Dir.stubs(:glob).returns(["foo.ddl"])
43
+ File.expects(:read).with("foo.ddl").returns("foo_ddl")
44
+ ddl.expects(:instance_eval).with("foo_ddl")
45
+ ddl.expects(:meta).returns("metadata")
46
+ ddl.expects(:requirements).returns({:mcollective => 1})
47
+
48
+ meta, requirements = PluginPackager.get_metadata("/tmp", "foo")
49
+ meta.should == "metadata"
50
+ requirements.should == 1
51
+ end
52
+ end
53
+
54
+ describe "#check_dir_present" do
55
+ it "should return true if the directory is present and not empty" do
56
+ File.expects(:directory?).with("/tmp").returns(true)
57
+ File.expects(:join).with("/tmp", "*")
58
+ Dir.expects(:glob).returns([1])
59
+ result = PluginPackager.check_dir_present("/tmp")
60
+ result.should == true
61
+ end
62
+
63
+ it "should return false if the directory is not present" do
64
+ File.expects(:directory?).with("/tmp").returns(false)
65
+ result = PluginPackager.check_dir_present("/tmp")
66
+ result.should == false
67
+ end
68
+
69
+ it "should return false if the direcotry is present but empty" do
70
+ File.expects(:directory?).with("/tmp").returns(true)
71
+ File.expects(:join).with("/tmp", "*")
72
+ Dir.expects(:glob).returns([])
73
+ result = PluginPackager.check_dir_present("/tmp")
74
+ result.should == false
75
+ end
76
+ end
77
+
78
+ describe "#do_quietly?" do
79
+ it "should call the block parameter if verbose is true" do
80
+ result = PluginPackager.do_quietly?(true) {:success}
81
+ result.should == :success
82
+ end
83
+
84
+ it "should call the block parameter quietly if verbose is false" do
85
+ std_out = Tempfile.new("mc_pluginpackager_spec")
86
+ File.expects(:new).with("/dev/null", "w").returns(std_out)
87
+ PluginPackager.do_quietly?(false) {puts "success"}
88
+ std_out.rewind
89
+ std_out.read.should == "success\n"
90
+ std_out.close
91
+ std_out.unlink
92
+ end
93
+
94
+ it "should raise an exception and reset stdout if the block raises an execption" do
95
+ expect{
96
+ PluginPackager.do_quietly?(false) {raise Exception, "exception"}
97
+ }.to raise_error(Exception, "exception")
98
+ end
99
+ end
100
+
101
+ describe "#build_tool?" do
102
+ it "should return true if the given build tool is present on the system" do
103
+ File.expects(:join).returns("foo")
104
+ File.expects(:exists?).with("foo").returns(true)
105
+ result = PluginPackager.build_tool?("foo")
106
+ result.should == true
107
+ end
108
+
109
+ it "should return false if the given build tool is not present on the system" do
110
+ File.stubs(:join).returns("foo")
111
+ File.stubs(:exists?).with("foo").returns(false)
112
+ result = PluginPackager.build_tool?("foo")
113
+ result.should == false
114
+ end
115
+ end
116
+
117
+ describe "#safe_system" do
118
+ it "should not raise any exceptions if a command ran" do
119
+ PluginPackager.expects(:system).with("foo").returns(true)
120
+ lambda{PluginPackager.safe_system("foo")}.should_not raise_error
121
+ end
122
+
123
+ it "should raise a RuntimeError if command cannot be run" do
124
+ PluginPackager.expects(:system).with("foo").returns(false)
125
+ expect{
126
+ PluginPackager.safe_system("foo")
127
+ }.to raise_error(RuntimeError, "Failed: foo")
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env rspec
2
+
3
+ require 'spec_helper'
4
+ require File.dirname(__FILE__) + "/../../../../../plugins/mcollective/aggregate/average.rb"
5
+
6
+ module MCollective
7
+ class Aggregate
8
+ describe Average do
9
+ describe "#startup_hook" do
10
+ it "should set the correct result hash" do
11
+ result = Average.new(:test, [], "%d", :test_action)
12
+ result.result.should == {:value => 0, :type => :numeric, :output => :test}
13
+ result.aggregate_format.should == "%d"
14
+ end
15
+
16
+ it "should set a defauly aggregate_format if one isn't defined" do
17
+ result = Average.new(:test, [], nil, :test_action)
18
+ result.aggregate_format.should == "Average of test: %f"
19
+ end
20
+ end
21
+
22
+ describe "#process_result" do
23
+ it "should add the reply value to the result hash" do
24
+ average = Average.new([:test], [], "%d", :test_action)
25
+ average.process_result(1, {:test => 1})
26
+ average.result[:value].should == 1
27
+ end
28
+ end
29
+
30
+ describe "#summarize" do
31
+ it "should calculate the average and return a result class" do
32
+ result_obj = mock
33
+ result_obj.stubs(:new).returns(:success)
34
+
35
+ average = Average.new([:test], [], "%d", :test_action)
36
+ average.process_result(10, {:test => 10})
37
+ average.process_result(20, {:test => 20})
38
+ average.stubs(:result_class).returns(result_obj)
39
+ average.summarize.should == :success
40
+ average.result[:value].should == 15
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env rspec
2
+
3
+ require 'spec_helper'
4
+ require File.dirname(__FILE__) + "/../../../../../plugins/mcollective/aggregate/sum.rb"
5
+
6
+ module MCollective
7
+ class Aggregate
8
+ describe Sum do
9
+ describe "#startup_hook" do
10
+ it "should set the correct result hash" do
11
+ result = Sum.new(:test, [], "%d", :test_action)
12
+ result.result.should == {:value => 0, :type => :numeric, :output => :test}
13
+ result.aggregate_format.should == "%d"
14
+ end
15
+
16
+ it "should set a defauly aggregate_format if one isn't defined" do
17
+ result = Sum.new(:test, [], nil, :test_action)
18
+ result.aggregate_format.should == "Sum of test: %f"
19
+ end
20
+ end
21
+
22
+ describe "#process_result" do
23
+ it "should add the reply value to the result hash" do
24
+ average = Sum.new([:test], [], "%d", :test_action)
25
+ average.process_result(1, {:test => 1})
26
+ average.result[:value].should == 1
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env rspec
2
+
3
+ require 'spec_helper'
4
+ require File.dirname(__FILE__) + "/../../../../../plugins/mcollective/aggregate/summary.rb"
5
+
6
+ module MCollective
7
+ class Aggregate
8
+ describe Summary do
9
+ describe "#startup_hook" do
10
+ it "should set the correct result hash" do
11
+ result = Summary.new(:test, [], "%d", :test_action)
12
+ result.result.should == {:value => {}, :type => :collection, :output => :test}
13
+ result.aggregate_format.should == "%d"
14
+ end
15
+
16
+ it "should set a defauly aggregate_format if one isn't defined" do
17
+ result = Summary.new(:test, [], nil, :test_action)
18
+ result.aggregate_format.should == :calculate
19
+ end
20
+ end
21
+
22
+ describe "#process_result" do
23
+ it "should add the value to the result hash" do
24
+ sum = Summary.new(:test, [], "%d", :test_action)
25
+ sum.process_result(:foo, {:test => :foo})
26
+ sum.result[:value].should == {:foo => 1}
27
+ end
28
+
29
+ it "should add the reply values to the result hash if value is an array" do
30
+ sum = Summary.new(:test, [], "%d", :test_action)
31
+ sum.process_result([:foo, :foo, :bar], {:test => [:foo, :foo, :bar]})
32
+ sum.result[:value].should == {:foo => 2, :bar => 1}
33
+ end
34
+ end
35
+
36
+ describe "#summarize" do
37
+ it "should calculate an attractive format" do
38
+ sum = Summary.new(:test, [], nil, :test_action)
39
+ sum.result[:value] = {"shrt" => 1, "long key" => 1}
40
+ sum.summarize.aggregate_format.should == "%8s = %s"
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -438,7 +438,7 @@ module MCollective
438
438
  @c.make_target("test", :broadcast, "mcollective").should == {:name => "/topic/mcollective.test.agent", :headers => {}, :id => "/topic/mcollective.test.agent"}
439
439
  @c.make_target("test", :request, "mcollective").should == {:name => "/topic/mcollective.test.agent", :headers => {}, :id => "/topic/mcollective.test.agent"}
440
440
  @c.make_target("test", :direct_request, "mcollective").should == {:headers=>{}, :name=>"/queue/mcollective.nodes", :id => "/queue/mcollective.nodes"}
441
- @c.make_target("test", :directed, "mcollective").should == {:name => "/queue/mcollective.nodes", :headers=>{"selector"=>"mc_identity = 'rspec'"}, :id => "directed_to_identity"}
441
+ @c.make_target("test", :directed, "mcollective").should == {:name => "/queue/mcollective.nodes", :headers=>{"selector"=>"mc_identity = 'rspec'"}, :id => "mcollective_directed_to_identity"}
442
442
  end
443
443
 
444
444
  it "should raise an error for unknown collectives" do
@@ -0,0 +1,478 @@
1
+ #!/usr/bin/env rspec
2
+
3
+ require 'spec_helper'
4
+
5
+ MCollective::PluginManager.clear
6
+
7
+ require File.dirname(__FILE__) + '/../../../../../plugins/mcollective/connector/rabbitmq.rb'
8
+
9
+ # create the stomp error class here as it does not always exist
10
+ # all versions of the stomp gem and we do not want to tie tests
11
+ # to the stomp gem
12
+ module Stomp
13
+ module Error
14
+ class DuplicateSubscription < RuntimeError; end
15
+ end
16
+ end
17
+
18
+ module MCollective
19
+ module Connector
20
+ describe Rabbitmq do
21
+ before do
22
+ unless ::Stomp::Error.constants.map{|c| c.to_s}.include?("NoCurrentConnection")
23
+ class ::Stomp::Error::NoCurrentConnection < RuntimeError ; end
24
+ end
25
+
26
+ @config = mock
27
+ @config.stubs(:configured).returns(true)
28
+ @config.stubs(:identity).returns("rspec")
29
+ @config.stubs(:collectives).returns(["mcollective"])
30
+
31
+ logger = mock
32
+ logger.stubs(:log)
33
+ logger.stubs(:start)
34
+ Log.configure(logger)
35
+
36
+ Config.stubs(:instance).returns(@config)
37
+
38
+ @msg = mock
39
+ @msg.stubs(:base64_encode!)
40
+ @msg.stubs(:payload).returns("msg")
41
+ @msg.stubs(:agent).returns("agent")
42
+ @msg.stubs(:type).returns(:reply)
43
+ @msg.stubs(:collective).returns("mcollective")
44
+
45
+ @subscription = mock
46
+ @subscription.stubs("<<").returns(true)
47
+ @subscription.stubs("include?").returns(false)
48
+ @subscription.stubs("delete").returns(false)
49
+
50
+ @connection = mock
51
+ @connection.stubs(:subscribe).returns(true)
52
+ @connection.stubs(:unsubscribe).returns(true)
53
+
54
+ @c = Rabbitmq.new
55
+ @c.instance_variable_set("@subscriptions", @subscription)
56
+ @c.instance_variable_set("@connection", @connection)
57
+ end
58
+
59
+ describe "#initialize" do
60
+ it "should set the @config variable" do
61
+ c = Rabbitmq.new
62
+ c.instance_variable_get("@config").should == @config
63
+ end
64
+
65
+ it "should set @subscriptions to an empty list" do
66
+ c = Rabbitmq.new
67
+ c.instance_variable_get("@subscriptions").should == []
68
+ end
69
+ end
70
+
71
+ describe "#connect" do
72
+ it "should not try to reconnect if already connected" do
73
+ Log.expects(:debug).with("Already connection, not re-initializing connection").once
74
+ @c.connect
75
+ end
76
+
77
+ it "should support new style config" do
78
+ pluginconf = {"rabbitmq.pool.size" => "2",
79
+ "rabbitmq.pool.1.host" => "host1",
80
+ "rabbitmq.pool.1.port" => "6163",
81
+ "rabbitmq.pool.1.user" => "user1",
82
+ "rabbitmq.pool.1.password" => "password1",
83
+ "rabbitmq.pool.1.ssl" => "false",
84
+ "rabbitmq.pool.2.host" => "host2",
85
+ "rabbitmq.pool.2.port" => "6164",
86
+ "rabbitmq.pool.2.user" => "user2",
87
+ "rabbitmq.pool.2.password" => "password2",
88
+ "rabbitmq.pool.2.ssl" => "true",
89
+ "rabbitmq.pool.2.ssl.fallback" => "true",
90
+ "rabbitmq.initial_reconnect_delay" => "0.02",
91
+ "rabbitmq.max_reconnect_delay" => "40",
92
+ "rabbitmq.use_exponential_back_off" => "false",
93
+ "rabbitmq.back_off_multiplier" => "3",
94
+ "rabbitmq.max_reconnect_attempts" => "5",
95
+ "rabbitmq.randomize" => "true",
96
+ "rabbitmq.backup" => "true",
97
+ "rabbitmq.timeout" => "1",
98
+ "rabbitmq.vhost" => "mcollective",
99
+ "rabbitmq.connect_timeout" => "5"}
100
+
101
+
102
+ ENV.delete("STOMP_USER")
103
+ ENV.delete("STOMP_PASSWORD")
104
+
105
+ @config.expects(:pluginconf).returns(pluginconf).at_least_once
106
+
107
+ Rabbitmq::EventLogger.expects(:new).returns("logger")
108
+
109
+ connector = mock
110
+ connector.expects(:new).with(:backup => true,
111
+ :back_off_multiplier => 3,
112
+ :max_reconnect_delay => 40.0,
113
+ :timeout => 1,
114
+ :connect_timeout => 5,
115
+ :use_exponential_back_off => false,
116
+ :max_reconnect_attempts => 5,
117
+ :initial_reconnect_delay => 0.02,
118
+ :randomize => true,
119
+ :reliable => true,
120
+ :logger => "logger",
121
+ :connect_headers => {'accept-version' => '1.0', 'host' => 'mcollective'},
122
+ :hosts => [{:passcode => 'password1',
123
+ :host => 'host1',
124
+ :port => 6163,
125
+ :ssl => false,
126
+ :login => 'user1'},
127
+ {:passcode => 'password2',
128
+ :host => 'host2',
129
+ :port => 6164,
130
+ :ssl => true,
131
+ :login => 'user2'}
132
+ ])
133
+
134
+ @c.expects(:ssl_parameters).with(2, true).returns(true)
135
+
136
+ @c.instance_variable_set("@connection", nil)
137
+ @c.connect(connector)
138
+ end
139
+ end
140
+
141
+ describe "#ssl_paramaters" do
142
+ it "should ensure all settings are provided" do
143
+ pluginconf = {"rabbitmq.pool.1.host" => "host1",
144
+ "rabbitmq.pool.1.port" => "6164",
145
+ "rabbitmq.pool.1.user" => "user1",
146
+ "rabbitmq.pool.1.password" => "password1",
147
+ "rabbitmq.pool.1.ssl" => "true",
148
+ "rabbitmq.pool.1.ssl.cert" => "rspec"}
149
+
150
+ @config.expects(:pluginconf).returns(pluginconf).at_least_once
151
+
152
+ expect { @c.ssl_parameters(1, false) }.to raise_error("cert, key and ca has to be supplied for verified SSL mode")
153
+ end
154
+
155
+ it "should verify the ssl files exist" do
156
+ pluginconf = {"rabbitmq.pool.1.host" => "host1",
157
+ "rabbitmq.pool.1.port" => "6164",
158
+ "rabbitmq.pool.1.user" => "user1",
159
+ "rabbitmq.pool.1.password" => "password1",
160
+ "rabbitmq.pool.1.ssl" => "true",
161
+ "rabbitmq.pool.1.ssl.cert" => "rspec.cert",
162
+ "rabbitmq.pool.1.ssl.key" => "rspec.key",
163
+ "rabbitmq.pool.1.ssl.ca" => "rspec1.ca,rspec2.ca"}
164
+
165
+ @config.expects(:pluginconf).returns(pluginconf).at_least_once
166
+
167
+ File.expects(:exist?).with("rspec.cert").twice.returns(true)
168
+ File.expects(:exist?).with("rspec.key").twice.returns(true)
169
+ File.expects(:exist?).with("rspec1.ca").twice.returns(true)
170
+ File.expects(:exist?).with("rspec2.ca").twice.returns(false)
171
+
172
+ expect { @c.ssl_parameters(1, false) }.to raise_error("Cannot find CA file rspec2.ca")
173
+
174
+ @c.ssl_parameters(1, true).should == true
175
+ end
176
+
177
+ it "should support fallback mode when there are errors" do
178
+ pluginconf = {"rabbitmq.pool.1.host" => "host1",
179
+ "rabbitmq.pool.1.port" => "6164",
180
+ "rabbitmq.pool.1.user" => "user1",
181
+ "rabbitmq.pool.1.password" => "password1",
182
+ "rabbitmq.pool.1.ssl" => "true"}
183
+
184
+ @config.expects(:pluginconf).returns(pluginconf).at_least_once
185
+
186
+ @c.ssl_parameters(1, true).should == true
187
+ end
188
+
189
+ it "should fail if fallback isnt enabled" do
190
+ pluginconf = {"rabbitmq.pool.1.host" => "host1",
191
+ "rabbitmq.pool.1.port" => "6164",
192
+ "rabbitmq.pool.1.user" => "user1",
193
+ "rabbitmq.pool.1.password" => "password1",
194
+ "rabbitmq.pool.1.ssl" => "true"}
195
+
196
+ @config.expects(:pluginconf).returns(pluginconf).at_least_once
197
+
198
+ expect { @c.ssl_parameters(1, false) }.to raise_error
199
+ end
200
+ end
201
+
202
+ describe "#receive" do
203
+ it "should receive from the middleware" do
204
+ payload = mock
205
+ payload.stubs(:body).returns("msg")
206
+ payload.stubs(:headers).returns("headers")
207
+
208
+ @connection.expects(:receive).returns(payload)
209
+
210
+ Message.expects(:new).with("msg", payload, :base64 => true, :headers => "headers").returns("message")
211
+ @c.instance_variable_set("@base64", true)
212
+
213
+ received = @c.receive
214
+ received.should == "message"
215
+ end
216
+
217
+ it "should sleep and retry if recieving while disconnected" do
218
+ payload = mock
219
+ payload.stubs(:body).returns("msg")
220
+ payload.stubs(:headers).returns("headers")
221
+
222
+ Message.stubs(:new).returns("rspec")
223
+ @connection.expects(:receive).raises(::Stomp::Error::NoCurrentConnection).returns(payload).twice
224
+ @c.expects(:sleep).with(1)
225
+
226
+ @c.receive.should == "rspec"
227
+ end
228
+ end
229
+
230
+ describe "#publish" do
231
+ before do
232
+ @connection.stubs(:publish).with("test", "msg", {}).returns(true)
233
+ end
234
+
235
+ it "should base64 encode a message if configured to do so" do
236
+ @c.instance_variable_set("@base64", true)
237
+ @c.expects(:target_for).returns({:name => "test", :headers => {}})
238
+ @connection.expects(:publish).with("test", "msg", {})
239
+ @msg.expects(:base64_encode!)
240
+
241
+ @c.publish(@msg)
242
+ end
243
+
244
+ it "should not base64 encode if not configured to do so" do
245
+ @c.instance_variable_set("@base64", false)
246
+ @c.expects(:target_for).returns({:name => "test", :headers => {}})
247
+ @connection.expects(:publish).with("test", "msg", {})
248
+ @msg.expects(:base64_encode!).never
249
+
250
+ @c.publish(@msg)
251
+ end
252
+
253
+ it "should publish the correct message to the correct target with msgheaders" do
254
+ @connection.expects(:publish).with("test", "msg", {}).once
255
+ @c.expects(:target_for).returns({:name => "test", :headers => {}})
256
+
257
+ @c.publish(@msg)
258
+ end
259
+
260
+ it "should publish direct messages based on discovered_hosts" do
261
+ msg = mock
262
+ msg.stubs(:base64_encode!)
263
+ msg.stubs(:payload).returns("msg")
264
+ msg.stubs(:agent).returns("agent")
265
+ msg.stubs(:collective).returns("mcollective")
266
+ msg.stubs(:type).returns(:direct_request)
267
+ msg.expects(:discovered_hosts).returns(["one", "two"])
268
+
269
+ @connection.expects(:publish).with('/exchange/mcollective_directed/one', 'msg', {'reply-to' => '/temp-queue/mcollective_reply_agent'})
270
+ @connection.expects(:publish).with('/exchange/mcollective_directed/two', 'msg', {'reply-to' => '/temp-queue/mcollective_reply_agent'})
271
+
272
+ @c.publish(msg)
273
+ end
274
+ end
275
+
276
+ describe "#subscribe" do
277
+ it "should handle duplicate subscription errors" do
278
+ @connection.expects(:subscribe).raises(::Stomp::Error::DuplicateSubscription)
279
+ Log.expects(:error).with(regexp_matches(/already had a matching subscription, ignoring/))
280
+ @c.subscribe("test", :broadcast, "mcollective")
281
+ end
282
+
283
+ it "should use the make_target correctly" do
284
+ @c.expects("make_target").with("test", :broadcast, "mcollective").returns({:name => "test", :headers => {}})
285
+ @c.subscribe("test", :broadcast, "mcollective")
286
+ end
287
+
288
+ it "should check for existing subscriptions" do
289
+ @c.expects("make_target").with("test", :broadcast, "mcollective").returns({:name => "test", :headers => {}, :id => "rspec"})
290
+ @subscription.expects("include?").with("rspec").returns(false)
291
+ @connection.expects(:subscribe).never
292
+
293
+ @c.subscribe("test", :broadcast, "mcollective")
294
+ end
295
+
296
+ it "should subscribe to the middleware" do
297
+ @c.expects("make_target").with("test", :broadcast, "mcollective").returns({:name => "test", :headers => {}, :id => "rspec"})
298
+ @connection.expects(:subscribe).with("test", {}, "rspec")
299
+ @c.subscribe("test", :broadcast, "mcollective")
300
+ end
301
+
302
+ it "should add to the list of subscriptions" do
303
+ @c.expects("make_target").with("test", :broadcast, "mcollective").returns({:name => "test", :headers => {}, :id => "rspec"})
304
+ @subscription.expects("<<").with("rspec")
305
+ @c.subscribe("test", :broadcast, "mcollective")
306
+ end
307
+ end
308
+
309
+ describe "#unsubscribe" do
310
+ it "should use make_target correctly" do
311
+ @c.expects("make_target").with("test", :broadcast, "mcollective").returns({:name => "test", :headers => {}})
312
+ @c.unsubscribe("test", :broadcast, "mcollective")
313
+ end
314
+
315
+ it "should unsubscribe from the target" do
316
+ @c.expects("make_target").with("test", :broadcast, "mcollective").returns({:name => "test", :headers => {}, :id => "rspec"})
317
+ @connection.expects(:unsubscribe).with("test", {}, "rspec").once
318
+
319
+ @c.unsubscribe("test", :broadcast, "mcollective")
320
+ end
321
+
322
+ it "should delete the source from subscriptions" do
323
+ @c.expects("make_target").with("test", :broadcast, "mcollective").returns({:name => "test", :headers => {}, :id => "rspec"})
324
+ @subscription.expects(:delete).with("rspec").once
325
+
326
+ @c.unsubscribe("test", :broadcast, "mcollective")
327
+ end
328
+ end
329
+
330
+ describe "#target_for" do
331
+ it "should create reply targets based on reply-to headers in requests" do
332
+ message = mock
333
+ message.expects(:type).returns(:reply)
334
+
335
+ request = mock
336
+ request.expects(:headers).returns({"reply-to" => "foo"})
337
+
338
+ message.expects(:request).returns(request)
339
+
340
+ @c.target_for(message).should == {:name => "foo", :headers => {}, :id => ""}
341
+ end
342
+
343
+ it "should create new request targets" do
344
+ message = mock
345
+ message.expects(:type).returns(:request).times(3)
346
+ message.expects(:agent).returns("rspecagent")
347
+ message.expects(:collective).returns("mcollective")
348
+
349
+ @c.expects(:make_target).with("rspecagent", :request, "mcollective", nil)
350
+ @c.target_for(message)
351
+ end
352
+
353
+ it "should support direct requests" do
354
+ message = mock
355
+ message.expects(:type).returns(:direct_request).times(3)
356
+ message.expects(:agent).returns("rspecagent")
357
+ message.expects(:collective).returns("mcollective")
358
+
359
+ @c.expects(:make_target).with("rspecagent", :direct_request, "mcollective", nil)
360
+ @c.target_for(message)
361
+ end
362
+
363
+ it "should fail for unknown message types" do
364
+ message = mock
365
+ message.stubs(:type).returns(:fail)
366
+
367
+ expect {
368
+ @c.target_for(message)
369
+ }.to raise_error("Don't now how to create a target for message type fail")
370
+ end
371
+ end
372
+
373
+ describe "#disconnect" do
374
+ it "should disconnect from the stomp connection" do
375
+ @connection.expects(:disconnect)
376
+ @c.disconnect
377
+ end
378
+ end
379
+
380
+ describe "#make_target" do
381
+ it "should create correct targets" do
382
+ @c.make_target("test", :reply, "mcollective").should == {:name => "/temp-queue/mcollective_reply_test", :headers => {}, :id => "mcollective_test_replies"}
383
+ @c.make_target("test", :broadcast, "mcollective").should == {:name => "/exchange/mcollective_broadcast/test", :headers => {"reply-to"=>"/temp-queue/mcollective_reply_test"}, :id => "mcollective_broadcast_test"}
384
+ @c.make_target("test", :request, "mcollective").should == {:name => "/exchange/mcollective_broadcast/test", :headers => {"reply-to"=>"/temp-queue/mcollective_reply_test"}, :id => "mcollective_broadcast_test"}
385
+ @c.make_target("test", :direct_request, "mcollective", "rspec").should == {:headers=>{"reply-to"=>"/temp-queue/mcollective_reply_test"}, :name=>"/exchange/mcollective_directed/rspec", :id => nil}
386
+ @c.make_target("test", :directed, "mcollective").should == {:name => "/exchange/mcollective_directed/rspec", :headers=>{}, :id => "rspec_directed_to_identity"}
387
+ end
388
+
389
+ it "should raise an error for unknown collectives" do
390
+ expect {
391
+ @c.make_target("test", :broadcast, "foo")
392
+ }.to raise_error("Unknown collective 'foo' known collectives are 'mcollective'")
393
+ end
394
+
395
+ it "should raise an error for unknown types" do
396
+ expect {
397
+ @c.make_target("test", :test, "mcollective")
398
+ }.to raise_error("Unknown target type test")
399
+ end
400
+ end
401
+
402
+
403
+ describe "#get_env_or_option" do
404
+ it "should return the environment variable if set" do
405
+ ENV["test"] = "rspec_env_test"
406
+
407
+ @c.get_env_or_option("test", nil, nil).should == "rspec_env_test"
408
+
409
+ ENV.delete("test")
410
+ end
411
+
412
+ it "should return the config option if set" do
413
+ @config.expects(:pluginconf).returns({"test" => "rspec_test"}).twice
414
+ @c.get_env_or_option("test", "test", "test").should == "rspec_test"
415
+ end
416
+
417
+ it "should return default if nothing else matched" do
418
+ @config.expects(:pluginconf).returns({}).once
419
+ @c.get_env_or_option("test", "test", "test").should == "test"
420
+ end
421
+
422
+ it "should raise an error if no default is supplied" do
423
+ @config.expects(:pluginconf).returns({}).once
424
+
425
+ expect {
426
+ @c.get_env_or_option("test", "test")
427
+ }.to raise_error("No test environment or plugin.test configuration option given")
428
+ end
429
+ end
430
+
431
+ describe "#get_option" do
432
+ it "should return the config option if set" do
433
+ @config.expects(:pluginconf).returns({"test" => "rspec_test"}).twice
434
+ @c.get_option("test").should == "rspec_test"
435
+ end
436
+
437
+ it "should return default option was not found" do
438
+ @config.expects(:pluginconf).returns({}).once
439
+ @c.get_option("test", "test").should == "test"
440
+ end
441
+
442
+ it "should raise an error if no default is supplied" do
443
+ @config.expects(:pluginconf).returns({}).once
444
+
445
+ expect {
446
+ @c.get_option("test")
447
+ }.to raise_error("No plugin.test configuration option given")
448
+ end
449
+ end
450
+
451
+ describe "#get_bool_option" do
452
+ it "should return the default if option isnt set" do
453
+ @config.expects(:pluginconf).returns({}).once
454
+ @c.get_bool_option("test", "default").should == "default"
455
+ end
456
+
457
+ ["1", "yes", "true"].each do |boolean|
458
+ it "should map options to true correctly" do
459
+ @config.expects(:pluginconf).returns({"test" => boolean}).twice
460
+ @c.get_bool_option("test", "default").should == true
461
+ end
462
+ end
463
+
464
+ ["0", "no", "false"].each do |boolean|
465
+ it "should map options to false correctly" do
466
+ @config.expects(:pluginconf).returns({"test" => boolean}).twice
467
+ @c.get_bool_option("test", "default").should == false
468
+ end
469
+ end
470
+
471
+ it "should return default for non boolean options" do
472
+ @config.expects(:pluginconf).returns({"test" => "foo"}).twice
473
+ @c.get_bool_option("test", "default").should == "default"
474
+ end
475
+ end
476
+ end
477
+ end
478
+ end