--- /dev/null
+#!/usr/bin/env rspec
+
+require 'spec_helper'
+
+module MCollective
+ describe Agents do
+ before do
+ tmpfile = Tempfile.new("mc_agents_spec")
+ path = tmpfile.path
+ tmpfile.close!
+
+ @tmpdir = FileUtils.mkdir_p(path)
+ @tmpdir = @tmpdir[0] if @tmpdir.is_a?(Array) # ruby 1.9.2
+
+ @agentsdir = File.join([@tmpdir, "mcollective", "agent"])
+ FileUtils.mkdir_p(@agentsdir)
+
+ logger = mock
+ logger.stubs(:log)
+ logger.stubs(:start)
+ Log.configure(logger)
+ end
+
+ after do
+ FileUtils.rm_r(@tmpdir)
+ end
+
+ describe "#initialize" do
+ it "should fail if configuration has not been loaded" do
+ Config.instance.expects(:configured).returns(false)
+
+ expect {
+ Agents.new
+ }.to raise_error("Configuration has not been loaded, can't load agents")
+ end
+
+ it "should load agents" do
+ Config.instance.expects(:configured).returns(true)
+ Agents.any_instance.expects(:loadagents).once
+
+ Agents.new
+ end
+ end
+
+ describe "#clear!" do
+ it "should delete and unsubscribe all loaded agents" do
+ Config.instance.expects(:configured).returns(true).at_least_once
+ Config.instance.expects(:libdir).returns([@tmpdir])
+ PluginManager.expects(:delete).with("foo_agent").once
+ Util.expects(:make_subscriptions).with("foo", :broadcast).returns("foo_target")
+ Util.expects(:unsubscribe).with("foo_target")
+
+ a = Agents.new({"foo" => 1})
+ end
+ end
+
+ describe "#loadagents" do
+ before do
+ Config.instance.stubs(:configured).returns(true)
+ Config.instance.stubs(:libdir).returns([@tmpdir])
+ Agents.any_instance.stubs("clear!").returns(true)
+ end
+
+ it "should delete all existing agents" do
+ Agents.any_instance.expects("clear!").once
+ a = Agents.new
+ end
+
+ it "should attempt to load agents from all libdirs" do
+ Config.instance.expects(:libdir).returns(["/nonexisting", "/nonexisting"])
+ File.expects("directory?").with("/nonexisting/mcollective/agent").twice
+
+ a = Agents.new
+ end
+
+ it "should load found agents" do
+ Agents.any_instance.expects("loadagent").with("test").once
+
+ FileUtils.touch(File.join([@agentsdir, "test.rb"]))
+
+ a = Agents.new
+ end
+
+ it "should load each agent unless already loaded" do
+ Agents.any_instance.expects("loadagent").with("test").never
+
+ FileUtils.touch(File.join([@agentsdir, "test.rb"]))
+
+ PluginManager << {:type => "test_agent", :class => String.new}
+ a = Agents.new
+ end
+ end
+
+ describe "#loadagent" do
+ before do
+ FileUtils.touch(File.join([@agentsdir, "test.rb"]))
+ Config.instance.stubs(:configured).returns(true)
+ Config.instance.stubs(:libdir).returns([@tmpdir])
+ Agents.any_instance.stubs("clear!").returns(true)
+ PluginManager.stubs(:loadclass).returns(true)
+ PluginManager.stubs("[]").with("test_agent").returns(true)
+ Util.stubs(:make_subscriptions).with("test", :broadcast).returns([{:agent => "test", :type => :broadcast, :collective => "test"}])
+ Util.stubs(:subscribe).with([{:agent => "test", :type => :broadcast, :collective => "test"}]).returns(true)
+ Agents.stubs(:findagentfile).returns(File.join([@agentsdir, "test.rb"]))
+ Agents.any_instance.stubs("activate_agent?").returns(true)
+
+ @a = Agents.new
+ end
+
+ it "should return false if the agent file is missing" do
+ Agents.any_instance.expects(:findagentfile).returns(false).once
+ @a.loadagent("test").should == false
+ end
+
+ it "should delete the agent before loading again" do
+ PluginManager.expects(:delete).with("test_agent").twice
+ @a.loadagent("test")
+ end
+
+ it "should load the agent class from disk" do
+ PluginManager.expects(:loadclass).with("MCollective::Agent::Test")
+ @a.loadagent("test")
+ end
+
+ it "should check if the agent should be activated" do
+ Agents.any_instance.expects(:findagentfile).with("test").returns(File.join([@agentsdir, "test.rb"]))
+ Agents.any_instance.expects("activate_agent?").with("test").returns(true)
+ @a.loadagent("test").should == true
+ end
+
+ it "should set discovery and registration to be single instance plugins" do
+ PluginManager.expects("<<").with({:type => "registration_agent", :class => "MCollective::Agent::Registration", :single_instance => true}).once
+ PluginManager.expects("<<").with({:type => "discovery_agent", :class => "MCollective::Agent::Discovery", :single_instance => true}).once
+ Agents.any_instance.expects("activate_agent?").with("registration").returns(true)
+ Agents.any_instance.expects("activate_agent?").with("discovery").returns(true)
+
+ PluginManager.expects(:loadclass).with("MCollective::Agent::Registration").returns(true).once
+ PluginManager.expects(:loadclass).with("MCollective::Agent::Discovery").returns(true).once
+
+ FileUtils.touch(File.join([@agentsdir, "registration.rb"]))
+ FileUtils.touch(File.join([@agentsdir, "discovery.rb"]))
+
+ @a.loadagent("registration")
+ @a.loadagent("discovery")
+ end
+
+ it "should add general plugins as multiple instance plugins" do
+ PluginManager.expects("<<").with({:type => "test_agent", :class => "MCollective::Agent::Test", :single_instance => false}).once
+ @a.loadagent("test")
+ end
+
+ it "should add the agent to the plugin manager and subscribe" do
+ PluginManager.expects("<<").with({:type => "foo_agent", :class => "MCollective::Agent::Foo", :single_instance => false})
+ Util.stubs(:make_subscriptions).with("foo", :broadcast).returns([{:agent => "foo", :type => :broadcast, :collective => "test"}])
+ Util.expects("subscribe").with([{:type => :broadcast, :agent => 'foo', :collective => 'test'}]).returns(true)
+ Agents.any_instance.expects(:findagentfile).with("foo").returns(File.join([@agentsdir, "foo.rb"]))
+ FileUtils.touch(File.join([@agentsdir, "foo.rb"]))
+ Agents.any_instance.expects("activate_agent?").with("foo").returns(true)
+ PluginManager.stubs("[]").with("foo_agent").returns(true)
+
+ @a.loadagent("foo")
+ end
+
+ it "should check if an agent is loadable and remove it from the list if not" do
+ PluginManager.expects("<<").with({:type => "foo_agent", :class => "MCollective::Agent::Foo", :single_instance => false})
+ Agents.any_instance.expects(:findagentfile).with("foo").returns(File.join([@agentsdir, "foo.rb"]))
+ FileUtils.touch(File.join([@agentsdir, "foo.rb"]))
+ Agents.any_instance.expects("activate_agent?").with("foo").returns(true)
+ PluginManager.stubs("[]").with("foo_agent").raises("rspec")
+
+ Log.expects(:error).once.with("Loading agent foo failed: rspec")
+
+ @a.loadagent("foo").should == false
+ Agents.agentlist.include?("foo").should == false
+ end
+
+ it "should add the agent to the agent list" do
+ Agents.agentlist.should == ["test"]
+ end
+
+ it "should return true on success" do
+ @a.loadagent("test").should == true
+ end
+
+ it "should handle load exceptions" do
+ Agents.any_instance.expects(:findagentfile).with("foo").returns(File.join([@agentsdir, "foo.rb"]))
+ Log.expects(:error).with(regexp_matches(/Loading agent foo failed/))
+ @a.loadagent("foo").should == false
+ end
+
+ it "should delete plugins that failed to load" do
+ Agents.any_instance.expects(:findagentfile).with("foo").returns(File.join([@agentsdir, "foo.rb"]))
+ PluginManager.expects(:delete).with("foo_agent").twice
+
+ @a.loadagent("foo").should == false
+ end
+ end
+
+ describe "#class_for_agent" do
+ it "should return the correct class" do
+ Config.instance.stubs(:configured).returns(true)
+ Agents.any_instance.stubs(:loadagents).returns(true)
+ Agents.new.class_for_agent("foo").should == "MCollective::Agent::Foo"
+ end
+ end
+
+ describe "#activate_agent?" do
+ before do
+ Config.instance.stubs(:configured).returns(true)
+ Agents.any_instance.stubs(:loadagents).returns(true)
+ @a = Agents.new
+
+ module MCollective::Agent;end
+ class MCollective::Agent::Test; end
+ end
+
+ it "should check if the correct class has an activation method" do
+ Agent::Test.expects("respond_to?").with("activate?").once
+
+ @a.activate_agent?("test")
+ end
+
+ it "should call the activation method" do
+ Agent::Test.expects("activate?").returns(true).once
+ @a.activate_agent?("test")
+ end
+
+ it "should log a debug message and return true if the class has no activation method" do
+ Agent::Test.expects("respond_to?").with("activate?").returns(false).once
+ Log.expects(:debug).with("MCollective::Agent::Test does not have an activate? method, activating as default")
+
+ @a.activate_agent?("test").should == true
+ end
+
+ it "should handle exceptions in the activation as false" do
+ Agent::Test.expects("activate?").raises(RuntimeError)
+ @a.activate_agent?("test").should == false
+ end
+ end
+
+ describe "#findagentfile" do
+ before do
+ Config.instance.stubs(:configured).returns(true)
+ Config.instance.stubs(:libdir).returns([@tmpdir])
+ Agents.any_instance.stubs(:loadagents).returns(true)
+ @a = Agents.new
+ end
+
+ it "should support multiple libdirs" do
+ Config.instance.expects(:libdir).returns([@tmpdir, @tmpdir]).once
+ File.expects("exist?").returns(false).twice
+ @a.findagentfile("test")
+ end
+
+ it "should look for the correct filename in the libdir" do
+ File.expects("exist?").with(File.join([@tmpdir, "mcollective", "agent", "test.rb"])).returns(false).once
+ @a.findagentfile("test")
+ end
+
+ it "should return the full path if the agent is found" do
+ agentfile = File.join([@tmpdir, "mcollective", "agent", "test.rb"])
+ File.expects("exist?").with(agentfile).returns(true).once
+ @a.findagentfile("test").should == agentfile
+ end
+
+ it "should return false if no agent is found" do
+ @a.findagentfile("foo").should == false
+ end
+ end
+
+ describe "#include?" do
+ it "should correctly report the plugin state" do
+ Config.instance.stubs(:configured).returns(true)
+ Config.instance.stubs(:libdir).returns([@tmpdir])
+ Agents.any_instance.stubs(:loadagents).returns(true)
+ PluginManager.expects("include?").with("test_agent").returns(true)
+
+ @a = Agents.new
+
+ @a.include?("test").should == true
+ end
+ end
+
+ describe "#agentlist" do
+ it "should return the correct agent list" do
+ Config.instance.stubs(:configured).returns(true)
+ Config.instance.stubs(:libdir).returns([@tmpdir])
+ Agents.any_instance.stubs(:loadagents).returns(true)
+
+ @a = Agents.new("test" => true)
+ Agents.agentlist.should == ["test"]
+ end
+ end
+ end
+end