4e3a4097cd6afd5f7ac1994deb4e797f5bd29a89
[packages/precise/mcollective.git] / spec / unit / discovery_spec.rb
1 #!/usr/bin/env rspec
2
3 require 'spec_helper'
4
5 module MCollective
6   describe Discovery do
7     before do
8       Config.instance.stubs(:default_discovery_method).returns("mc")
9       @client = mock
10
11       Discovery.any_instance.stubs(:find_known_methods).returns(["mc"])
12       @discovery = Discovery.new(@client)
13     end
14
15     describe "#timeout_for_compound_filter" do
16       it "should return the correct time" do
17         ddl = mock
18         ddl.stubs(:meta).returns({:timeout => 1})
19
20         filter = [Matcher.create_compound_callstack("test().size=1 and rspec().size=1")]
21
22         DDL.expects(:new).with("test_data", :data).returns(ddl)
23         DDL.expects(:new).with("rspec_data", :data).returns(ddl)
24
25         @discovery.timeout_for_compound_filter(filter).should == 2
26       end
27     end
28
29     describe "#discover" do
30       before do
31         ddl = mock
32         ddl.stubs(:meta).returns({:timeout => 2})
33
34         discoverer = mock
35
36         @discovery.stubs(:force_discovery_method_by_filter).returns(false)
37         @discovery.stubs(:ddl).returns(ddl)
38         @discovery.stubs(:check_capabilities)
39         @discovery.stubs(:discovery_class).returns(discoverer)
40       end
41
42       it "should error for non fixnum limits" do
43         expect { @discovery.discover(nil, 0, 1.1) }.to raise_error("Limit has to be an integer")
44       end
45
46       it "should use the DDL timeout if none is specified" do
47         filter = Util.empty_filter
48         @discovery.discovery_class.expects(:discover).with(filter, 2, 0, @client)
49         @discovery.discover(filter, nil, 0)
50       end
51
52       it "should check the discovery method is capable of serving the filter" do
53         @discovery.expects(:check_capabilities).with("filter").raises("capabilities check failed")
54         expect { @discovery.discover("filter", nil, 0) }.to raise_error("capabilities check failed")
55       end
56
57       it "should call the correct discovery plugin" do
58         @discovery.discovery_class.expects(:discover).with("filter", 2, 0, @client)
59         @discovery.discover("filter", nil, 0)
60       end
61
62       it "should handle limits correctly" do
63         @discovery.discovery_class.stubs(:discover).returns([1,2,3,4,5])
64         @discovery.discover(Util.empty_filter, 1, 1).should == [1]
65         @discovery.discover(Util.empty_filter, 1, 0).should == [1,2,3,4,5]
66       end
67     end
68
69     describe "#force_discovery_method_by_filter" do
70       it "should force mc plugin when needed" do
71         options = {:discovery_method => "rspec"}
72
73         Log.expects(:info).with("Switching to mc discovery method because compound filters are used")
74
75         @discovery.expects(:discovery_method).returns("rspec")
76         @client.expects(:options).returns(options)
77         @discovery.force_discovery_method_by_filter({"compound" => ["rspec"]}).should == true
78
79         options[:discovery_method].should == "mc"
80       end
81
82       it "should not force mc plugin when no compound filter is used" do
83         options = {:discovery_method => "rspec"}
84
85         @discovery.expects(:discovery_method).returns("rspec")
86         @discovery.force_discovery_method_by_filter({"compound" => []}).should == false
87
88         options[:discovery_method].should == "rspec"
89       end
90     end
91
92     describe "#check_capabilities" do
93       before do
94         @ddl = mock
95         @discovery.stubs(:ddl).returns(@ddl)
96         @discovery.stubs(:discovery_method).returns("rspec")
97       end
98
99       it "should fail for unsupported capabilities" do
100         @ddl.stubs(:discovery_interface).returns({:capabilities => []})
101
102         filter = Util.empty_filter
103
104         expect { @discovery.check_capabilities(filter.merge({"cf_class" => ["filter"]})) }.to raise_error(/Cannot use class filters/)
105
106         ["fact", "identity", "compound"].each do |type|
107           expect { @discovery.check_capabilities(filter.merge({type => ["filter"]})) }.to raise_error(/Cannot use #{type} filters/)
108         end
109       end
110     end
111
112     describe "#ddl" do
113       before do
114         @ddl = mock
115         @ddl.stubs(:meta).returns({:name => "mc"})
116       end
117
118       it "should create an instance of the right ddl" do
119         @discovery.instance_variable_set("@ddl", nil)
120         @client.stubs(:options).returns({})
121         DDL.expects(:new).with("mc", :discovery).returns(@ddl)
122         @discovery.ddl
123       end
124
125       it "should reload the ddl if the method has changed" do
126         @discovery.instance_variable_set("@ddl", @ddl)
127         @discovery.stubs(:discovery_method).returns("rspec")
128         DDL.expects(:new).with("rspec", :discovery).returns(@ddl)
129         @discovery.ddl
130       end
131     end
132
133     describe "#discovery_class" do
134       it "should try to load the class if not already loaded" do
135         @discovery.expects(:discovery_method).returns("mc")
136         PluginManager.expects(:loadclass).with("MCollective::Discovery::Mc")
137         Discovery.expects(:const_defined?).with("Mc").returns(false)
138         Discovery.expects(:const_get).with("Mc").returns("rspec")
139         @discovery.discovery_class.should == "rspec"
140       end
141
142       it "should not load the class again if its already loaded" do
143         @discovery.expects(:discovery_method).returns("mc")
144         PluginManager.expects(:loadclass).never
145         Discovery.expects(:const_defined?).with("Mc").returns(true)
146         Discovery.expects(:const_get).with("Mc").returns("rspec")
147         @discovery.discovery_class.should == "rspec"
148       end
149     end
150
151     describe "#initialize" do
152       it "should load all the known methods" do
153         @discovery.instance_variable_get("@known_methods").should == ["mc"]
154       end
155     end
156
157     describe "#find_known_methods" do
158       it "should use the PluginManager to find plugins of type 'discovery'" do
159         @discovery.find_known_methods.should == ["mc"]
160       end
161     end
162
163     describe "#has_method?" do
164       it "should correctly report the availability of a discovery method" do
165         @discovery.has_method?("mc").should == true
166         @discovery.has_method?("rspec").should == false
167       end
168     end
169
170     describe "#descovery_method" do
171       it "should default to 'mc'" do
172         @client.expects(:options).returns({})
173         @discovery.discovery_method.should == "mc"
174       end
175
176       it "should give preference to the client options" do
177         @client.expects(:options).returns({:discovery_method => "rspec"}).twice
178         Config.instance.expects(:direct_addressing).returns(true)
179         @discovery.expects(:has_method?).with("rspec").returns(true)
180         @discovery.discovery_method.should == "rspec"
181       end
182
183       it "should validate the discovery method exists" do
184         @client.expects(:options).returns({:discovery_method => "rspec"}).twice
185         expect { @discovery.discovery_method.should == "rspec" }.to raise_error("Unknown discovery method rspec")
186       end
187
188       it "should only allow custom discovery methods if direct_addressing is enabled" do
189         @client.expects(:options).returns({:discovery_method => "rspec"}).twice
190         Config.instance.expects(:direct_addressing).returns(false)
191         @discovery.expects(:has_method?).with("rspec").returns(true)
192         expect { @discovery.discovery_method.should == "rspec" }.to raise_error("Custom discovery methods require direct addressing mode")
193       end
194     end
195   end
196 end