Added mcollective 2.3.1 package
[packages/trusty/mcollective.git] / spec / unit / agents_spec.rb
1 #!/usr/bin/env rspec
2
3 require 'spec_helper'
4
5 module MCollective
6   describe Agents do
7     before do
8       tmpfile = Tempfile.new("mc_agents_spec")
9       path = tmpfile.path
10       tmpfile.close!
11
12       @tmpdir = FileUtils.mkdir_p(path)
13       @tmpdir = @tmpdir[0] if @tmpdir.is_a?(Array) # ruby 1.9.2
14
15       @agentsdir = File.join([@tmpdir, "mcollective", "agent"])
16       FileUtils.mkdir_p(@agentsdir)
17
18       logger = mock
19       logger.stubs(:log)
20       logger.stubs(:start)
21       Log.configure(logger)
22     end
23
24     after do
25       FileUtils.rm_r(@tmpdir)
26     end
27
28     describe "#initialize" do
29       it "should fail if configuration has not been loaded" do
30         Config.instance.expects(:configured).returns(false)
31
32         expect {
33           Agents.new
34         }.to raise_error("Configuration has not been loaded, can't load agents")
35       end
36
37       it "should load agents" do
38         Config.instance.expects(:configured).returns(true)
39         Agents.any_instance.expects(:loadagents).once
40
41         Agents.new
42       end
43     end
44
45     describe "#clear!" do
46       it "should delete and unsubscribe all loaded agents" do
47         Config.instance.expects(:configured).returns(true).at_least_once
48         Config.instance.expects(:libdir).returns([@tmpdir])
49         PluginManager.expects(:delete).with("foo_agent").once
50         Util.expects(:make_subscriptions).with("foo", :broadcast).returns("foo_target")
51         Util.expects(:unsubscribe).with("foo_target")
52
53         a = Agents.new({"foo" => 1})
54       end
55     end
56
57     describe "#loadagents" do
58       before do
59         Config.instance.stubs(:configured).returns(true)
60         Config.instance.stubs(:libdir).returns([@tmpdir])
61         Agents.any_instance.stubs("clear!").returns(true)
62       end
63
64       it "should delete all existing agents" do
65         Agents.any_instance.expects("clear!").once
66         a = Agents.new
67       end
68
69       it "should attempt to load agents from all libdirs" do
70         Config.instance.expects(:libdir).returns(["/nonexisting", "/nonexisting"])
71         File.expects("directory?").with("/nonexisting/mcollective/agent").twice
72
73         a = Agents.new
74       end
75
76       it "should load found agents" do
77         Agents.any_instance.expects("loadagent").with("test").once
78
79         FileUtils.touch(File.join([@agentsdir, "test.rb"]))
80
81         a = Agents.new
82       end
83
84       it "should load each agent unless already loaded" do
85         Agents.any_instance.expects("loadagent").with("test").never
86
87         FileUtils.touch(File.join([@agentsdir, "test.rb"]))
88
89         PluginManager << {:type => "test_agent", :class => String.new}
90         a = Agents.new
91       end
92     end
93
94     describe "#loadagent" do
95       before do
96         FileUtils.touch(File.join([@agentsdir, "test.rb"]))
97         Config.instance.stubs(:configured).returns(true)
98         Config.instance.stubs(:libdir).returns([@tmpdir])
99         Agents.any_instance.stubs("clear!").returns(true)
100         PluginManager.stubs(:loadclass).returns(true)
101         PluginManager.stubs("[]").with("test_agent").returns(true)
102         Util.stubs(:make_subscriptions).with("test", :broadcast).returns([{:agent => "test", :type => :broadcast, :collective => "test"}])
103         Util.stubs(:subscribe).with([{:agent => "test", :type => :broadcast, :collective => "test"}]).returns(true)
104         Agents.stubs(:findagentfile).returns(File.join([@agentsdir, "test.rb"]))
105         Agents.any_instance.stubs("activate_agent?").returns(true)
106
107         @a = Agents.new
108       end
109
110       it "should return false if the agent file is missing" do
111         Agents.any_instance.expects(:findagentfile).returns(false).once
112         @a.loadagent("test").should == false
113       end
114
115       it "should delete the agent before loading again" do
116         PluginManager.expects(:delete).with("test_agent").twice
117         @a.loadagent("test")
118       end
119
120       it "should load the agent class from disk" do
121         PluginManager.expects(:loadclass).with("MCollective::Agent::Test")
122         @a.loadagent("test")
123       end
124
125       it "should check if the agent should be activated" do
126         Agents.any_instance.expects(:findagentfile).with("test").returns(File.join([@agentsdir, "test.rb"]))
127         Agents.any_instance.expects("activate_agent?").with("test").returns(true)
128         @a.loadagent("test").should == true
129       end
130
131       it "should set discovery and registration to be single instance plugins" do
132         PluginManager.expects("<<").with({:type => "registration_agent", :class => "MCollective::Agent::Registration", :single_instance => true}).once
133         PluginManager.expects("<<").with({:type => "discovery_agent", :class => "MCollective::Agent::Discovery", :single_instance => true}).once
134         Agents.any_instance.expects("activate_agent?").with("registration").returns(true)
135         Agents.any_instance.expects("activate_agent?").with("discovery").returns(true)
136
137         PluginManager.expects(:loadclass).with("MCollective::Agent::Registration").returns(true).once
138         PluginManager.expects(:loadclass).with("MCollective::Agent::Discovery").returns(true).once
139
140         FileUtils.touch(File.join([@agentsdir, "registration.rb"]))
141         FileUtils.touch(File.join([@agentsdir, "discovery.rb"]))
142
143         @a.loadagent("registration")
144         @a.loadagent("discovery")
145       end
146
147       it "should add general plugins as multiple instance plugins" do
148         PluginManager.expects("<<").with({:type => "test_agent", :class => "MCollective::Agent::Test", :single_instance => false}).once
149         @a.loadagent("test")
150       end
151
152       it "should add the agent to the plugin manager and subscribe" do
153         PluginManager.expects("<<").with({:type => "foo_agent", :class => "MCollective::Agent::Foo", :single_instance => false})
154         Util.stubs(:make_subscriptions).with("foo", :broadcast).returns([{:agent => "foo", :type => :broadcast, :collective => "test"}])
155         Util.expects("subscribe").with([{:type => :broadcast, :agent => 'foo', :collective => 'test'}]).returns(true)
156         Agents.any_instance.expects(:findagentfile).with("foo").returns(File.join([@agentsdir, "foo.rb"]))
157         FileUtils.touch(File.join([@agentsdir, "foo.rb"]))
158         Agents.any_instance.expects("activate_agent?").with("foo").returns(true)
159         PluginManager.stubs("[]").with("foo_agent").returns(true)
160
161         @a.loadagent("foo")
162       end
163
164       it "should check if an agent is loadable and remove it from the list if not" do
165         PluginManager.expects("<<").with({:type => "foo_agent", :class => "MCollective::Agent::Foo", :single_instance => false})
166         Agents.any_instance.expects(:findagentfile).with("foo").returns(File.join([@agentsdir, "foo.rb"]))
167         FileUtils.touch(File.join([@agentsdir, "foo.rb"]))
168         Agents.any_instance.expects("activate_agent?").with("foo").returns(true)
169         PluginManager.stubs("[]").with("foo_agent").raises("rspec")
170
171         Log.expects(:error).once.with("Loading agent foo failed: rspec")
172
173         @a.loadagent("foo").should == false
174         Agents.agentlist.include?("foo").should == false
175       end
176
177       it "should add the agent to the agent list" do
178         Agents.agentlist.should == ["test"]
179       end
180
181       it "should return true on success" do
182         @a.loadagent("test").should == true
183       end
184
185       it "should handle load exceptions" do
186         Agents.any_instance.expects(:findagentfile).with("foo").returns(File.join([@agentsdir, "foo.rb"]))
187         Log.expects(:error).with(regexp_matches(/Loading agent foo failed/))
188         @a.loadagent("foo").should == false
189       end
190
191       it "should delete plugins that failed to load" do
192         Agents.any_instance.expects(:findagentfile).with("foo").returns(File.join([@agentsdir, "foo.rb"]))
193         PluginManager.expects(:delete).with("foo_agent").twice
194
195         @a.loadagent("foo").should == false
196       end
197     end
198
199     describe "#class_for_agent" do
200       it "should return the correct class" do
201         Config.instance.stubs(:configured).returns(true)
202         Agents.any_instance.stubs(:loadagents).returns(true)
203         Agents.new.class_for_agent("foo").should == "MCollective::Agent::Foo"
204       end
205     end
206
207     describe "#activate_agent?" do
208       before do
209         Config.instance.stubs(:configured).returns(true)
210         Agents.any_instance.stubs(:loadagents).returns(true)
211         @a = Agents.new
212
213         module MCollective::Agent;end
214         class MCollective::Agent::Test; end
215       end
216
217       it "should check if the correct class has an activation method" do
218         Agent::Test.expects("respond_to?").with("activate?").once
219
220         @a.activate_agent?("test")
221       end
222
223       it "should call the activation method" do
224         Agent::Test.expects("activate?").returns(true).once
225         @a.activate_agent?("test")
226       end
227
228       it "should log a debug message and return true if the class has no activation method" do
229         Agent::Test.expects("respond_to?").with("activate?").returns(false).once
230         Log.expects(:debug).with("MCollective::Agent::Test does not have an activate? method, activating as default")
231
232         @a.activate_agent?("test").should == true
233       end
234
235       it "should handle exceptions in the activation as false" do
236         Agent::Test.expects("activate?").raises(RuntimeError)
237         @a.activate_agent?("test").should == false
238       end
239     end
240
241     describe "#findagentfile" do
242       before do
243         Config.instance.stubs(:configured).returns(true)
244         Config.instance.stubs(:libdir).returns([@tmpdir])
245         Agents.any_instance.stubs(:loadagents).returns(true)
246         @a = Agents.new
247       end
248
249       it "should support multiple libdirs" do
250         Config.instance.expects(:libdir).returns([@tmpdir, @tmpdir]).once
251         File.expects("exist?").returns(false).twice
252         @a.findagentfile("test")
253       end
254
255       it "should look for the correct filename in the libdir" do
256         File.expects("exist?").with(File.join([@tmpdir, "mcollective", "agent", "test.rb"])).returns(false).once
257         @a.findagentfile("test")
258       end
259
260       it "should return the full path if the agent is found" do
261         agentfile = File.join([@tmpdir, "mcollective", "agent", "test.rb"])
262         File.expects("exist?").with(agentfile).returns(true).once
263         @a.findagentfile("test").should == agentfile
264       end
265
266       it "should return false if no agent is found" do
267         @a.findagentfile("foo").should == false
268       end
269     end
270
271     describe "#include?" do
272       it "should correctly report the plugin state" do
273         Config.instance.stubs(:configured).returns(true)
274         Config.instance.stubs(:libdir).returns([@tmpdir])
275         Agents.any_instance.stubs(:loadagents).returns(true)
276         PluginManager.expects("include?").with("test_agent").returns(true)
277
278         @a = Agents.new
279
280         @a.include?("test").should == true
281       end
282     end
283
284     describe "#agentlist" do
285       it "should return the correct agent list" do
286         Config.instance.stubs(:configured).returns(true)
287         Config.instance.stubs(:libdir).returns([@tmpdir])
288         Agents.any_instance.stubs(:loadagents).returns(true)
289
290         @a = Agents.new("test" => true)
291         Agents.agentlist.should == ["test"]
292       end
293     end
294   end
295 end