diff options
34 files changed, 776 insertions, 475 deletions
diff --git a/lib/puppet/indirector.rb b/lib/puppet/indirector.rb index b8690d7d5..704039abc 100644 --- a/lib/puppet/indirector.rb +++ b/lib/puppet/indirector.rb @@ -11,8 +11,20 @@ module Puppet::Indirector class Terminus require 'puppet/util/docs' extend Puppet::Util::Docs + + class << self + attr_accessor :name, :indirection + end + def name + self.class.name + end + def indirection + self.class.indirection + end end + require 'puppet/indirector/indirection' + # This handles creating the terminus classes. require 'puppet/util/classgen' extend Puppet::Util::ClassGen @@ -38,13 +50,15 @@ module Puppet::Indirector # on the classes including the module. This allows a given indirection to # be used in multiple classes. def self.register_terminus(indirection, terminus, options = {}, &block) - genclass(terminus, + klass = genclass(terminus, :prefix => indirection.to_s.capitalize, :hash => instance_hash(indirection), :attributes => options, :block => block, :parent => options[:parent] || Terminus ) + klass.indirection = indirection + klass.name = terminus end # Retrieve a terminus class by indirection and name. @@ -61,23 +75,14 @@ module Puppet::Indirector # +:to+: What parameter to use as the name of the indirection terminus. def indirects(indirection, options = {}) if defined?(@indirection) - raise ArgumentError, "Already performing an indirection of %s; cannot redirect %s" % [@indirection[:name], indirection] + raise ArgumentError, "Already performing an indirection of %s; cannot redirect %s" % [@indirection.name, indirection] end - options[:name] = indirection - @indirection = options + @indirection = Indirection.new(indirection, options) - # Validate the parameter. This requires that indirecting - # classes require 'puppet/defaults', because of ordering issues, - # but it makes problems much easier to debug. - if param_name = options[:to] - begin - name = Puppet[param_name] - rescue - raise ArgumentError, "Configuration parameter '%s' for indirection '%s' does not exist'" % [param_name, indirection] - end - end # Set up autoloading of the appropriate termini. Puppet::Indirector.register_indirection indirection + + return @indirection end # Define methods for each of the HTTP methods. These just point to the @@ -98,40 +103,16 @@ module Puppet::Indirector private - - # Create a new terminus instance. - def make_terminus(name) - # Load our terminus class. - unless klass = Puppet::Indirector.terminus(@indirection[:name], name) - raise ArgumentError, "Could not find terminus %s for indirection %s" % [name, indirection] - end - return klass.new - end - # Redirect a given HTTP method. def redirect(method_name, *args) begin - terminus.send(method_name, *args) - rescue NoMethodError - raise ArgumentError, "Indirection category %s does not respond to REST method %s" % [indirection, method_name] - end - end - - # Return the singleton terminus for this indirection. - def terminus(name = nil) - @termini ||= {} - # Get the name of the terminus. - unless name - unless param_name = @indirection[:to] - raise ArgumentError, "You must specify an indirection terminus for indirection %s" % @indirection[:name] + @indirection.terminus.send(method_name, *args) + rescue NoMethodError => detail + if Puppet[:trace] + puts detail.backtrace end - name = Puppet[param_name] - name = name.intern if name.is_a?(String) - end - - unless @termini[name] - @termini[name] = make_terminus(name) + raise ArgumentError, "The %s terminus of the %s indirection failed to respond to %s: %s" % + [@indirection.terminus.name, @indirection.name, method_name, detail] end - @termini[name] end end diff --git a/lib/puppet/indirector/facts/yaml.rb b/lib/puppet/indirector/facts/yaml.rb index 87860012f..f29ea8ebc 100644 --- a/lib/puppet/indirector/facts/yaml.rb +++ b/lib/puppet/indirector/facts/yaml.rb @@ -21,7 +21,7 @@ Puppet::Indirector.register_terminus :facts, :yaml do end # Store the facts to disk. - def put(facts) + def post(facts) File.open(path(facts.name), "w", 0600) do |f| begin f.print YAML::dump(facts.values) diff --git a/lib/puppet/indirector/indirection.rb b/lib/puppet/indirector/indirection.rb new file mode 100644 index 000000000..7a4c4bd55 --- /dev/null +++ b/lib/puppet/indirector/indirection.rb @@ -0,0 +1,74 @@ +# An actual indirection. +class Puppet::Indirector::Indirection + @@indirections = [] + + # Clear all cached termini from all indirections. + def self.clear_cache + @@indirections.each { |ind| ind.clear_cache } + end + + attr_accessor :name, :termini + attr_reader :to + + # Clear our cached list of termini. + # This is only used for testing. + def clear_cache + @termini.clear + end + + # This is only used for testing. + def delete + @@indirections.delete(self) if @@indirections.include?(self) + end + + def initialize(name, options = {}) + @name = name + options.each do |name, value| + begin + send(name.to_s + "=", value) + rescue NoMethodError + raise ArgumentError, "%s is not a valid Indirection parameter" % name + end + end + @termini = {} + @@indirections << self + end + + # Return the singleton terminus for this indirection. + def terminus(name = nil) + # Get the name of the terminus. + unless name + unless param_name = self.to + raise ArgumentError, "You must specify an indirection terminus for indirection %s" % self.name + end + name = Puppet[param_name] + name = name.intern if name.is_a?(String) + end + + unless @termini[name] + @termini[name] = make_terminus(name) + end + @termini[name] + end + + # Validate the parameter. This requires that indirecting + # classes require 'puppet/defaults', because of ordering issues, + # but it makes problems much easier to debug. + def to=(param_name) + unless Puppet.config.valid?(param_name) + raise ArgumentError, "Configuration parameter '%s' for indirection '%s' does not exist'" % [param_name, self.name] + end + @to = param_name + end + + private + + # Create a new terminus instance. + def make_terminus(name) + # Load our terminus class. + unless klass = Puppet::Indirector.terminus(self.name, name) + raise ArgumentError, "Could not find terminus %s for indirection %s" % [name, self.name] + end + return klass.new + end +end diff --git a/lib/puppet/indirector/node/external.rb b/lib/puppet/indirector/node/external.rb index ed2a8893e..13cd265fb 100644 --- a/lib/puppet/indirector/node/external.rb +++ b/lib/puppet/indirector/node/external.rb @@ -1,18 +1,66 @@ +require 'puppet/node/facts' + Puppet::Indirector.register_terminus :node, :external do desc "Call an external program to get node information." include Puppet::Util + + # Proxy the execution, so it's easier to test. + def execute(command) + Puppet::Util.execute(command) + end + # Look for external node definitions. def get(name) - return nil unless Puppet[:external_nodes] != "none" + unless Puppet[:external_nodes] != "none" + raise ArgumentError, "You must set the 'external_nodes' parameter to use the external node source" + end + unless Puppet[:external_nodes][0] == File::SEPARATOR[0] + raise ArgumentError, "You must set the 'external_nodes' parameter to a fully qualified command" + end + + # Run the command. + unless output = query(name) + return nil + end + + # Translate the output to ruby. + result = translate(name, output) + + return create_node(name, result) + end + + private + + # Turn our outputted objects into a Puppet::Node instance. + def create_node(name, result) + node = Puppet::Node.new(name) + set = false + [:parameters, :classes].each do |param| + if value = result[param] + node.send(param.to_s + "=", value) + set = true + end + end + + if set + node.fact_merge + return node + else + return nil + end + end + + # Call the external command and see if it returns our output. + def query(name) # This is a very cheap way to do this, since it will break on # commands that have spaces in the arguments. But it's good # enough for most cases. external_node_command = Puppet[:external_nodes].split external_node_command << name begin - output = Puppet::Util.execute(external_node_command) + output = execute(external_node_command) rescue Puppet::ExecutionFailure => detail if $?.exitstatus == 1 return nil @@ -25,31 +73,17 @@ Puppet::Indirector.register_terminus :node, :external do if output =~ /\A\s*\Z/ # all whitespace Puppet.debug "Empty response for %s from external node source" % name return nil + else + return output end + end + # Translate the yaml string into Ruby objects. + def translate(name, output) begin - result = YAML.load(output).inject({}) { |hash, data| hash[symbolize(data[0])] = data[1]; hash } + YAML.load(output).inject({}) { |hash, data| hash[symbolize(data[0])] = data[1]; hash } rescue => detail raise Puppet::Error, "Could not load external node results for %s: %s" % [name, detail] end - - node = Puppe::Node.new(name) - set = false - [:parameters, :classes].each do |param| - if value = result[param] - node.send(param.to_s + "=", value) - set = true - end - end - - if facts = Puppet::Node.facts(name) - node.fact_merge(facts) - end - - if set - return node - else - return nil - end end end diff --git a/lib/puppet/indirector/node/ldap.rb b/lib/puppet/indirector/node/ldap.rb index 77be04126..fb60cad31 100644 --- a/lib/puppet/indirector/node/ldap.rb +++ b/lib/puppet/indirector/node/ldap.rb @@ -18,10 +18,8 @@ Puppet::Indirector.register_terminus :node, :ldap do end end - node = Puppe::Node.new(name, :classes => classes, :source => "ldap", :parameters => parameters) - if facts = Puppet::Node.facts(name) - node.fact_merge(facts) - end + node = Puppet::Node.new(name, :classes => classes, :source => "ldap", :parameters => parameters) + node.fact_merge return node end diff --git a/lib/puppet/indirector/node/none.rb b/lib/puppet/indirector/node/none.rb index 7143033d9..2b326968e 100644 --- a/lib/puppet/indirector/node/none.rb +++ b/lib/puppet/indirector/node/none.rb @@ -1,3 +1,5 @@ +require 'puppet/node/facts' + Puppet::Indirector.register_terminus :node, :none do desc "Always return an empty node object. This is the node source you should use when you don't have some other, functional source you want to use, @@ -6,9 +8,7 @@ Puppet::Indirector.register_terminus :node, :none do # Just return an empty node. def get(name) node = Puppet::Node.new(name) - if facts = Puppet::Node.facts(name) - node.fact_merge(facts) - end + node.fact_merge node end end diff --git a/lib/puppet/network/handler/configuration.rb b/lib/puppet/network/handler/configuration.rb index 372e80325..2df1b3ab4 100644 --- a/lib/puppet/network/handler/configuration.rb +++ b/lib/puppet/network/handler/configuration.rb @@ -79,7 +79,7 @@ class Puppet::Network::Handler # Add any extra data necessary to the node. def add_node_data(node) # Merge in our server-side facts, so they can be used during compilation. - node.fact_merge(@server_facts) + node.merge(@server_facts) # Add any specified classes to the node's class list. if classes = @options[:Classes] diff --git a/lib/puppet/network/handler/facts.rb b/lib/puppet/network/handler/facts.rb deleted file mode 100755 index 4767e8be4..000000000 --- a/lib/puppet/network/handler/facts.rb +++ /dev/null @@ -1,68 +0,0 @@ -require 'yaml' -require 'puppet/util/fact_store' - -class Puppet::Network::Handler - # Receive logs from remote hosts. - class Facts < Handler - desc "An interface for storing and retrieving client facts. Currently only - used internally by Puppet." - - @interface = XMLRPC::Service::Interface.new("facts") { |iface| - iface.add_method("void set(string, string)") - iface.add_method("string get(string)") - iface.add_method("integer store_date(string)") - } - - def initialize(hash = {}) - super - - backend = Puppet[:factstore] - - unless klass = Puppet::Util::FactStore.store(backend) - raise Puppet::Error, "Could not find fact store %s" % backend - end - - @backend = klass.new - end - - # Get the facts from our back end. - def get(node) - if facts = @backend.get(node) - return strip_internal(facts) - else - return nil - end - end - - # Set the facts in the backend. - def set(node, facts) - @backend.set(node, add_internal(facts)) - nil - end - - # Retrieve a client's storage date. - def store_date(node) - if facts = get(node) - facts[:_puppet_timestamp].to_i - else - nil - end - end - - private - - # Add internal data to the facts for storage. - def add_internal(facts) - facts = facts.dup - facts[:_puppet_timestamp] = Time.now - facts - end - - # Strip out that internal data. - def strip_internal(facts) - facts = facts.dup - facts.find_all { |name, value| name.to_s =~ /^_puppet_/ }.each { |name, value| facts.delete(name) } - facts - end - end -end diff --git a/lib/puppet/network/handler/fileserver.rb b/lib/puppet/network/handler/fileserver.rb index a429412d2..993e9d51a 100755 --- a/lib/puppet/network/handler/fileserver.rb +++ b/lib/puppet/network/handler/fileserver.rb @@ -243,7 +243,7 @@ class Puppet::Network::Handler # the modules. def modules_mount(module_name, client) # Find our environment, if we have one. - if node = node_handler.details(client || Facter.value("hostname")) + if node = Puppet::Node.get(client || Facter.value("hostname")) env = node.environment else env = nil @@ -258,14 +258,6 @@ class Puppet::Network::Handler end end - # Create a node handler instance for looking up our nodes. - def node_handler - unless defined?(@node_handler) - @node_handler = Puppet::Network::Handler.handler(:node).create - end - @node_handler - end - # Read the configuration file. def readconfig(check = true) return if @noreadconfig diff --git a/lib/puppet/network/handler/master.rb b/lib/puppet/network/handler/master.rb index c8db277ba..9550dd550 100644 --- a/lib/puppet/network/handler/master.rb +++ b/lib/puppet/network/handler/master.rb @@ -74,7 +74,7 @@ class Puppet::Network::Handler client, clientip = clientname(client, clientip, facts) # Pass the facts to the fact handler - fact_handler.set(client, facts) + Puppet::Node::Facts.post(Puppet::Node::Facts.new(client, facts)) # And get the configuration from the config handler begin @@ -134,13 +134,6 @@ class Puppet::Network::Handler return facts end - def fact_handler - unless defined? @fact_handler - @fact_handler = Puppet::Network::Handler.handler(:facts).new :local => local? - end - @fact_handler - end - # Translate our configuration appropriately for sending back to a client. def translate(config) if local? diff --git a/lib/puppet/node.rb b/lib/puppet/node.rb index 9c5d2d397..7ad7bc3b3 100644 --- a/lib/puppet/node.rb +++ b/lib/puppet/node.rb @@ -1,8 +1,11 @@ +require 'puppet/indirector' + # A simplistic class for managing the node information itself. class Puppet::Node + require 'puppet/node/facts' + # Set up indirection, so that nodes can be looked for in # the node sources. - require 'puppet/indirector' extend Puppet::Indirector # Use the node source as the indirection terminus. @@ -66,9 +69,15 @@ class Puppet::Node end # Merge the node facts with parameters from the node source. - # This is only called if the node source has 'fact_merge' set to true. - def fact_merge(facts) - facts.each do |name, value| + def fact_merge + if facts = Puppet::Node::Facts.get(name) + merge(facts.values) + end + end + + # Merge any random parameters into our parameter list. + def merge(params) + params.each do |name, value| @parameters[name] = value unless @parameters.include?(name) end end diff --git a/lib/puppet/node/facts.rb b/lib/puppet/node/facts.rb index eddf44def..e5774127b 100755 --- a/lib/puppet/node/facts.rb +++ b/lib/puppet/node/facts.rb @@ -1,9 +1,11 @@ +require 'puppet/node' +require 'puppet/indirector' + # Manage a given node's facts. This either accepts facts and stores them, or # returns facts for a given node. class Puppet::Node::Facts # Set up indirection, so that nodes can be looked for in # the node sources. - require 'puppet/indirector' extend Puppet::Indirector # Use the node source as the indirection terminus. @@ -14,23 +16,21 @@ class Puppet::Node::Facts def initialize(name, values = {}) @name = name @values = values + + add_internal end private - # FIXME These methods are currently unused. - # Add internal data to the facts for storage. - def add_internal(facts) - facts = facts.dup - facts[:_puppet_timestamp] = Time.now - facts + def add_internal + self.values[:_timestamp] = Time.now end # Strip out that internal data. - def strip_internal(facts) - facts = facts.dup - facts.find_all { |name, value| name.to_s =~ /^_puppet_/ }.each { |name, value| facts.delete(name) } - facts + def strip_internal + newvals = values.dup + newvals.find_all { |name, value| name.to_s =~ /^_/ }.each { |name, value| newvals.delete(name) } + newvals end end diff --git a/spec/Rakefile b/spec/Rakefile index 40d107312..bb2a75de5 100644 --- a/spec/Rakefile +++ b/spec/Rakefile @@ -2,9 +2,15 @@ require File.join(File.dirname(__FILE__), "spec_helper.rb") require 'rake' require 'spec/rake/spectask' +basedir = File.dirname(__FILE__) +puppetlibdir = File.join(basedir, "../lib") +puppettestlibdir = File.join(basedir, "../test/lib") +speclibdir = File.join(basedir, "lib") + desc "Run all spec unit tests" Spec::Rake::SpecTask.new('unit') do |t| t.spec_files = FileList['unit/**/*.rb'] + t.libs = [puppetlibdir, puppettestlibdir, speclibdir] end task :default => [:unit] diff --git a/spec/lib/spec/dsl/behaviour.rb b/spec/lib/spec/dsl/behaviour.rb index 5158bb673..93a357f19 100644 --- a/spec/lib/spec/dsl/behaviour.rb +++ b/spec/lib/spec/dsl/behaviour.rb @@ -1,6 +1,10 @@ +require 'puppettest/runnable_test' + module Spec module DSL - class EvalModule < Module; end + class EvalModule < Module; + include PuppetTest::RunnableTest + end class Behaviour extend BehaviourCallbacks diff --git a/spec/lib/spec/runner/behaviour_runner.rb b/spec/lib/spec/runner/behaviour_runner.rb index 1ac891f3c..078490e92 100644 --- a/spec/lib/spec/runner/behaviour_runner.rb +++ b/spec/lib/spec/runner/behaviour_runner.rb @@ -55,6 +55,8 @@ module Spec def run_behaviours @behaviours.each do |behaviour| + # LAK:NOTE: this 'runnable' test is Puppet-specific. + next unless behaviour.runnable? behaviour.run(@options.reporter, @options.dry_run, @options.reverse, @options.timeout) end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index a4171bb07..477842495 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -5,8 +5,8 @@ $:.unshift("#{dir}/lib").unshift("#{dir}/../lib") $:.unshift("#{dir}/../test/lib") require 'mocha' -require 'spec' require 'puppettest' +require 'spec' Spec::Runner.configure do |config| config.mock_with :mocha diff --git a/spec/unit/indirector/facts/yaml.rb b/spec/unit/indirector/facts/yaml.rb index 45c079a69..176a47f04 100755 --- a/spec/unit/indirector/facts/yaml.rb +++ b/spec/unit/indirector/facts/yaml.rb @@ -23,7 +23,7 @@ describe Puppet::Indirector.terminus(:facts, :yaml), " when managing facts" do it "should store facts in YAML in the yamlfactdir" do values = {"one" => "two", "three" => "four"} facts = Puppet::Node::Facts.new("node", values) - @store.put(facts) + @store.post(facts) # Make sure the file exists path = File.join(Puppet[:yamlfactdir], facts.name) + ".yaml" diff --git a/spec/unit/indirector/indirection.rb b/spec/unit/indirector/indirection.rb new file mode 100755 index 000000000..e9b10c8c7 --- /dev/null +++ b/spec/unit/indirector/indirection.rb @@ -0,0 +1,57 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../spec_helper' + +require 'puppet/indirector' + +describe Puppet::Indirector::Indirection, " when initializing" do + it "should set the name" do + @indirection = Puppet::Indirector::Indirection.new(:myind) + @indirection.name.should == :myind + end + + it "should set any passed options" do + @indirection = Puppet::Indirector::Indirection.new(:myind, :to => :node_source) + @indirection.to.should == :node_source + end + + it "should only allow valid configuration parameters to be specified as :to targets" do + proc { Puppet::Indirector::Indirection.new(:myind, :to => :no_such_variable) }.should raise_error(ArgumentError) + end + + after do + if defined? @indirection + @indirection.delete + end + end +end + +describe Puppet::Indirector, " when managing termini" do + before do + @indirection = Puppet::Indirector::Indirection.new(:node, :to => :node_source) + end + + it "should allow the clearance of cached termini" do + terminus1 = mock 'terminus1' + terminus2 = mock 'terminus2' + Puppet::Indirector.terminus(:node, Puppet[:node_source]).stubs(:new).returns(terminus1, terminus2, ArgumentError) + @indirection.terminus.should equal(terminus1) + @indirection.class.clear_cache + @indirection.terminus.should equal(terminus2) + end + + # Make sure it caches the terminus. + it "should return the same terminus each time" do + @indirection = Puppet::Indirector::Indirection.new(:node, :to => :node_source) + @terminus = mock 'new' + Puppet::Indirector.terminus(:node, Puppet[:node_source]).expects(:new).returns(@terminus) + + @indirection.terminus.should equal(@terminus) + @indirection.terminus.should equal(@terminus) + end + + after do + @indirection.delete + Puppet::Indirector::Indirection.clear_cache + end +end diff --git a/spec/unit/indirector/indirector.rb b/spec/unit/indirector/indirector.rb index c4221febb..312c60951 100755 --- a/spec/unit/indirector/indirector.rb +++ b/spec/unit/indirector/indirector.rb @@ -11,15 +11,10 @@ describe Puppet::Indirector, " when managing indirections" do @indirector.send(:extend, Puppet::Indirector) end - # LAK:FIXME This seems like multiple tests, but I don't really know how to test one at a time. - it "should accept specification of an indirection terminus via a configuration parameter" do - @indirector.indirects :test, :to => :node_source - Puppet[:node_source] = "test_source" - klass = mock 'terminus_class' - terminus = mock 'terminus' - klass.expects(:new).returns terminus - Puppet::Indirector.expects(:terminus).with(:test, :test_source).returns(klass) - @indirector.send(:terminus).should equal(terminus) + it "should create an indirection" do + indirection = @indirector.indirects :test, :to => :node_source + indirection.name.should == :test + indirection.to.should == :node_source end it "should not allow more than one indirection in the same object" do @@ -33,18 +28,15 @@ describe Puppet::Indirector, " when managing indirections" do other.send(:extend, Puppet::Indirector) proc { other.indirects :test }.should_not raise_error end -end - -describe Puppet::Indirector, " when managing termini" do - before do - @indirector = Object.new - @indirector.send(:extend, Puppet::Indirector) - end it "should should autoload termini from disk" do Puppet::Indirector.expects(:instance_load).with(:test, "puppet/indirector/test") @indirector.indirects :test end + + after do + Puppet.config.clear + end end describe Puppet::Indirector, " when performing indirections" do @@ -66,14 +58,4 @@ describe Puppet::Indirector, " when performing indirections" do @terminus_class.expects(:new).returns(terminus) @indirector.put("myargument") end - - # Make sure it caches the terminus. - it "should use the same terminus for all indirections" do - terminus = mock 'terminus' - terminus.expects(:put).with("myargument") - terminus.expects(:get).with("other_argument") - @terminus_class.expects(:new).returns(terminus) - @indirector.put("myargument") - @indirector.get("other_argument") - end end diff --git a/spec/unit/indirector/node/external.rb b/spec/unit/indirector/node/external.rb new file mode 100755 index 000000000..30b2f74c2 --- /dev/null +++ b/spec/unit/indirector/node/external.rb @@ -0,0 +1,119 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../../spec_helper' + +require 'yaml' +require 'puppet/indirector' + +describe Puppet::Indirector.terminus(:node, :external), " when searching for nodes" do + require 'puppet/node' + + before do + Puppet.config[:external_nodes] = "/yay/ness" + @searcher = Puppet::Indirector.terminus(:node, :external).new + + # Set the searcher up so that we do not need to actually call the + # external script. + @searcher.meta_def(:execute) do |command| + name = command.last.chomp + result = {} + + if name =~ /a/ + result[:parameters] = {'one' => command.last + '1', 'two' => command.last + '2'} + end + + if name =~ /p/ + result['classes'] = [1,2,3].collect { |n| command.last + n.to_s } + end + + return YAML.dump(result) + end + end + + it "should throw an exception if the node_source is external but no external node command is set" do + Puppet[:external_nodes] = "none" + proc { @searcher.get("foo") }.should raise_error(ArgumentError) + end + + it "should throw an exception if the external node source is not fully qualified" do + Puppet[:external_nodes] = "mycommand" + proc { @searcher.get("foo") }.should raise_error(ArgumentError) + end + + it "should execute the command with the node name as the only argument" do + command = [Puppet[:external_nodes], "yay"] + @searcher.expects(:execute).with(command).returns("") + @searcher.get("yay") + end + + it "should return a node object" do + @searcher.get("apple").should be_instance_of(Puppet::Node) + end + + it "should set the node's name" do + @searcher.get("apple").name.should == "apple" + end + + # If we use a name that has a 'p' but no 'a', then our test generator + # will return classes but no parameters. + it "should be able to configure a node's classes" do + node = @searcher.get("plum") + node.classes.should == %w{plum1 plum2 plum3} + node.parameters.should == {} + end + + # If we use a name that has an 'a' but no 'p', then our test generator + # will return parameters but no classes. + it "should be able to configure a node's parameters" do + node = @searcher.get("guava") + node.classes.should == [] + node.parameters.should == {"one" => "guava1", "two" => "guava2"} + end + + it "should be able to configure a node's classes and parameters" do + node = @searcher.get("apple") + node.classes.should == %w{apple1 apple2 apple3} + node.parameters.should == {"one" => "apple1", "two" => "apple2"} + end + + it "should merge node facts with returned parameters" do + facts = Puppet::Node::Facts.new("apple", "three" => "four") + Puppet::Node::Facts.expects(:get).with("apple").returns(facts) + node = @searcher.get("apple") + node.parameters["three"].should == "four" + end + + it "should return nil when it cannot find the node" do + @searcher.get("honeydew").should be_nil + end + + # Make sure a nodesearch with arguments works + def test_nodesearch_external_arguments + mapper = mk_node_mapper + Puppet[:external_nodes] = "#{mapper} -s something -p somethingelse" + searcher = mk_searcher(:external) + node = nil + assert_nothing_raised do + node = searcher.nodesearch("apple") + end + assert_instance_of(SimpleNode, node, "did not create node") + end + + # A wrapper test, to make sure we're correctly calling the external search method. + def test_nodesearch_external_functional + mapper = mk_node_mapper + searcher = mk_searcher(:external) + + Puppet[:external_nodes] = mapper + + node = nil + assert_nothing_raised do + node = searcher.nodesearch("apple") + end + assert_instance_of(SimpleNode, node, "did not create node") + end + + after do + Puppet.config.clear + end +end diff --git a/spec/unit/indirector/node/ldap.rb b/spec/unit/indirector/node/ldap.rb new file mode 100755 index 000000000..c6eb45ffc --- /dev/null +++ b/spec/unit/indirector/node/ldap.rb @@ -0,0 +1,243 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../../spec_helper' + +require 'yaml' +require 'puppet/indirector' + +describe Puppet::Indirector.terminus(:node, :ldap), " when searching for nodes" do + require 'puppet/node' + + def setup + Puppet.config[:external_nodes] = "/yay/ness" + @searcher = Puppet::Indirector.terminus(:node, :ldap).new + nodetable = {} + @nodetable = nodetable + # Override the ldapsearch definition, so we don't have to actually set it up. + @searcher.meta_def(:ldapsearch) do |name| + nodetable[name] + end + end + + it "should return nil for hosts that cannot be found" do + @searcher.get("foo").should be_nil + end + + it "should return Puppet::Node instances" do + @nodetable["foo"] = [nil, %w{}, {}] + @searcher.get("foo").should be_instance_of(Puppet::Node) + end + + it "should set the node name" do + @nodetable["foo"] = [nil, %w{}, {}] + @searcher.get("foo").name.should == "foo" + end + + it "should set the classes" do + @nodetable["foo"] = [nil, %w{one two}, {}] + @searcher.get("foo").classes.should == %w{one two} + end + + it "should set the parameters" do + @nodetable["foo"] = [nil, %w{}, {"one" => "two"}] + @searcher.get("foo").parameters.should == {"one" => "two"} + end + + it "should set classes and parameters from the parent node" do + @nodetable["foo"] = ["middle", %w{one two}, {"one" => "two"}] + @nodetable["middle"] = [nil, %w{three four}, {"three" => "four"}] + node = @searcher.get("foo") + node.classes.sort.should == %w{one two three four}.sort + node.parameters.should == {"one" => "two", "three" => "four"} + end + + it "should prefer child parameters to parent parameters" do + @nodetable["foo"] = ["middle", %w{}, {"one" => "two"}] + @nodetable["middle"] = [nil, %w{}, {"one" => "four"}] + @searcher.get("foo").parameters["one"].should == "two" + end + + it "should recurse indefinitely through parent relationships" do + @nodetable["foo"] = ["middle", %w{one two}, {"one" => "two"}] + @nodetable["middle"] = ["top", %w{three four}, {"three" => "four"}] + @nodetable["top"] = [nil, %w{five six}, {"five" => "six"}] + node = @searcher.get("foo") + node.parameters.should == {"one" => "two", "three" => "four", "five" => "six"} + node.classes.sort.should == %w{one two three four five six}.sort + end + + # This can stay in the main test suite because it doesn't actually use ldapsearch, + # it just overrides the method so it behaves as though it were hitting ldap. + def test_ldap_nodesearch + + # Make sure we get nothing for nonexistent hosts + node = nil + assert_nothing_raised do + node = searcher.nodesearch("nosuchhost") + end + + assert_nil(node, "Got a node for a non-existent host") + + # Now add a base node with some classes and parameters + nodetable["base"] = [nil, %w{one two}, {"base" => "true"}] + + assert_nothing_raised do + node = searcher.nodesearch("base") + end + + assert_instance_of(SimpleNode, node, "Did not get node from ldap nodesearch") + assert_equal("base", node.name, "node name was not set") + + assert_equal(%w{one two}, node.classes, "node classes were not set") + assert_equal({"base" => "true"}, node.parameters, "node parameters were not set") + + # Now use a different with this as the base + nodetable["middle"] = ["base", %w{three}, {"center" => "boo"}] + assert_nothing_raised do + node = searcher.nodesearch("middle") + end + + assert_instance_of(SimpleNode, node, "Did not get node from ldap nodesearch") + assert_equal("middle", node.name, "node name was not set") + + assert_equal(%w{one two three}.sort, node.classes.sort, "node classes were not set correctly with a parent node") + assert_equal({"base" => "true", "center" => "boo"}, node.parameters, "node parameters were not set correctly with a parent node") + + # And one further, to make sure we fully recurse + nodetable["top"] = ["middle", %w{four five}, {"master" => "far"}] + assert_nothing_raised do + node = searcher.nodesearch("top") + end + + assert_instance_of(SimpleNode, node, "Did not get node from ldap nodesearch") + assert_equal("top", node.name, "node name was not set") + + assert_equal(%w{one two three four five}.sort, node.classes.sort, "node classes were not set correctly with the top node") + assert_equal({"base" => "true", "center" => "boo", "master" => "far"}, node.parameters, "node parameters were not set correctly with the top node") + end +end + +describe Puppet::Indirector.terminus(:node, :ldap), " when interacting with ldap" do + confine "LDAP is not available" => Puppet.features.ldap? + confine "No LDAP test data for networks other than Luke's" => Facter.value(:domain) == "madstop.com" + + def ldapconnect + + @ldap = LDAP::Conn.new("ldap", 389) + @ldap.set_option( LDAP::LDAP_OPT_PROTOCOL_VERSION, 3 ) + @ldap.simple_bind("", "") + + return @ldap + end + + def ldaphost(name) + node = Puppet::Node.new(name) + parent = nil + found = false + @ldap.search( "ou=hosts, dc=madstop, dc=com", 2, + "(&(objectclass=puppetclient)(cn=%s))" % name + ) do |entry| + node.classes = entry.vals("puppetclass") || [] + node.parameters = entry.to_hash.inject({}) do |hash, ary| + if ary[1].length == 1 + hash[ary[0]] = ary[1].shift + else + hash[ary[0]] = ary[1] + end + hash + end + parent = node.parameters["parentnode"] + found = true + end + raise "Could not find node %s" % name unless found + + return node, parent + end + + it "should have tests" do + raise ArgumentError + end + + def test_ldapsearch + Puppet[:ldapbase] = "ou=hosts, dc=madstop, dc=com" + Puppet[:ldapnodes] = true + + searcher = Object.new + searcher.extend(Node.node_source(:ldap)) + + ldapconnect() + + # Make sure we get nil and nil back when we search for something missing + parent, classes, parameters = nil + assert_nothing_raised do + parent, classes, parameters = searcher.ldapsearch("nosuchhost") + end + + assert_nil(parent, "Got a parent for a non-existent host") + assert_nil(classes, "Got classes for a non-existent host") + + # Make sure we can find 'culain' in ldap + assert_nothing_raised do + parent, classes, parameters = searcher.ldapsearch("culain") + end + + node, realparent = ldaphost("culain") + assert_equal(realparent, parent, "did not get correct parent node from ldap") + assert_equal(node.classes, classes, "did not get correct ldap classes from ldap") + assert_equal(node.parameters, parameters, "did not get correct ldap parameters from ldap") + + # Now compare when we specify the attributes to get. + Puppet[:ldapattrs] = "cn" + assert_nothing_raised do + parent, classes, parameters = searcher.ldapsearch("culain") + end + assert_equal(realparent, parent, "did not get correct parent node from ldap") + assert_equal(node.classes, classes, "did not get correct ldap classes from ldap") + + list = %w{cn puppetclass parentnode dn} + should = node.parameters.inject({}) { |h, a| h[a[0]] = a[1] if list.include?(a[0]); h } + assert_equal(should, parameters, "did not get correct ldap parameters from ldap") + end +end + +describe Puppet::Indirector.terminus(:node, :ldap), " when connecting to ldap" do + confine "Not running on culain as root" => (Puppet::Util::SUIDManager.uid == 0 and Facter.value("hostname") == "culain") + + it "should have tests" do + raise ArgumentError + end + + def test_ldapreconnect + Puppet[:ldapbase] = "ou=hosts, dc=madstop, dc=com" + Puppet[:ldapnodes] = true + + searcher = Object.new + searcher.extend(Node.node_source(:ldap)) + hostname = "culain.madstop.com" + + # look for our host + assert_nothing_raised { + parent, classes = searcher.nodesearch(hostname) + } + + # Now restart ldap + system("/etc/init.d/slapd restart 2>/dev/null >/dev/null") + sleep(1) + + # and look again + assert_nothing_raised { + parent, classes = searcher.nodesearch(hostname) + } + + # Now stop ldap + system("/etc/init.d/slapd stop 2>/dev/null >/dev/null") + cleanup do + system("/etc/init.d/slapd start 2>/dev/null >/dev/null") + end + + # And make sure we actually fail here + assert_raise(Puppet::Error) { + parent, classes = searcher.nodesearch(hostname) + } + end +end diff --git a/spec/unit/indirector/node/none.rb b/spec/unit/indirector/node/none.rb new file mode 100755 index 000000000..d52d7ca83 --- /dev/null +++ b/spec/unit/indirector/node/none.rb @@ -0,0 +1,32 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'puppet/indirector' +require 'puppet/node/facts' + +describe Puppet::Indirector.terminus(:node, :none), " when searching for nodes" do + before do + Puppet.config[:node_source] = "none" + @searcher = Puppet::Indirector.terminus(:node, :none).new + end + + it "should create a node instance" do + @searcher.get("yay").should be_instance_of(Puppet::Node) + end + + it "should create a new node with the correct name" do + @searcher.get("yay").name.should == "yay" + end + + it "should merge the node's facts" do + facts = Puppet::Node::Facts.new("yay", "one" => "two", "three" => "four") + Puppet::Node::Facts.expects(:get).with("yay").returns(facts) + node = @searcher.get("yay") + node.parameters["one"].should == "two" + node.parameters["three"].should == "four" + end + + after do + Puppet.config.clear + end +end diff --git a/spec/unit/node/facts.rb b/spec/unit/node/facts.rb index c7fc65f38..c677c1d2e 100755 --- a/spec/unit/node/facts.rb +++ b/spec/unit/node/facts.rb @@ -6,11 +6,12 @@ require 'puppet/node/facts' describe Puppet::Node::Facts, " when indirecting" do before do - Puppet[:fact_store] = "test_store" - @terminus_class = mock 'terminus_class' @terminus = mock 'terminus' - @terminus_class.expects(:new).returns(@terminus) - Puppet::Indirector.expects(:terminus).with(:facts, :test_store).returns(@terminus_class) + Puppet::Indirector.terminus(:facts, Puppet[:fact_store].intern).stubs(:new).returns(@terminus) + + # We have to clear the cache so that the facts ask for our terminus stub, + # instead of anything that might be cached. + Puppet::Indirector::Indirection.clear_cache end it "should redirect to the specified fact store for retrieval" do @@ -19,7 +20,19 @@ describe Puppet::Node::Facts, " when indirecting" do end it "should redirect to the specified fact store for storage" do - @terminus.expects(:put).with(:my_facts) - Puppet::Node::Facts.put(:my_facts) + @terminus.expects(:post).with(:my_facts) + Puppet::Node::Facts.post(:my_facts) + end + + after do + mocha_verify + Puppet::Indirector::Indirection.clear_cache + end +end + +describe Puppet::Node::Facts, " when storing and retrieving" do + it "should add metadata to the facts" do + facts = Puppet::Node::Facts.new("me", "one" => "two", "three" => "four") + facts.values[:_timestamp].should be_instance_of(Time) end end diff --git a/spec/unit/node/node.rb b/spec/unit/node/node.rb index a6cc1e301..9342dc5ce 100755 --- a/spec/unit/node/node.rb +++ b/spec/unit/node/node.rb @@ -85,32 +85,40 @@ end describe Puppet::Node, " when merging facts" do before do @node = Puppet::Node.new("testnode") + Puppet::Node::Facts.stubs(:get).with(@node.name).returns(Puppet::Node::Facts.new(@node.name, "one" => "c", "two" => "b")) end it "should prefer parameters already set on the node over facts from the node" do @node.parameters = {"one" => "a"} - @node.fact_merge("one" => "c") + @node.fact_merge @node.parameters["one"].should == "a" end it "should add passed parameters to the parameter list" do @node.parameters = {"one" => "a"} - @node.fact_merge("two" => "b") + @node.fact_merge @node.parameters["two"].should == "b" end + + it "should accept arbitrary parameters to merge into its parameters" do + @node.parameters = {"one" => "a"} + @node.merge "two" => "three" + @node.parameters["two"].should == "three" + end end describe Puppet::Node, " when indirecting" do before do - Puppet[:node_source] = :test_source - @terminus_class = mock 'terminus_class' @terminus = mock 'terminus' - @terminus_class.expects(:new).returns(@terminus) - Puppet::Indirector.expects(:terminus).with(:node, :test_source).returns(@terminus_class) + Puppet::Indirector.terminus(:node, Puppet[:node_source]).stubs(:new).returns(@terminus) end it "should redirect to the specified node source" do @terminus.expects(:get).with(:my_node) Puppet::Node.get(:my_node) end + + after do + Puppet::Indirector::Indirection.clear_cache + end end diff --git a/spec/unit/other/node.rb b/spec/unit/other/node.rb deleted file mode 100755 index 66d5ba9d7..000000000 --- a/spec/unit/other/node.rb +++ /dev/null @@ -1,101 +0,0 @@ -#!/usr/bin/env ruby - -require File.dirname(__FILE__) + '/../../spec_helper' - -describe Puppet::Node, " when initializing" do - before do - @node = Puppet::Node.new("testnode") - end - - it "should set the node name" do - @node.name.should == "testnode" - end - - it "should default to an empty parameter hash" do - @node.parameters.should == {} - end - - it "should default to an empty class array" do - @node.classes.should == [] - end - - it "should note its creation time" do - @node.time.should be_instance_of(Time) - end - - it "should accept parameters passed in during initialization" do - params = {"a" => "b"} - @node = Puppet::Node.new("testing", :parameters => params) - @node.parameters.should == params - end - - it "should accept classes passed in during initialization" do - classes = %w{one two} - @node = Puppet::Node.new("testing", :classes => classes) - @node.classes.should == classes - end - - it "should always return classes as an array" do - @node = Puppet::Node.new("testing", :classes => "myclass") - @node.classes.should == ["myclass"] - end - - it "should accept the environment during initialization" do - @node = Puppet::Node.new("testing", :environment => "myenv") - @node.environment.should == "myenv" - end - - it "should accept names passed in" do - @node = Puppet::Node.new("testing", :names => ["myenv"]) - @node.names.should == ["myenv"] - end -end - -describe Puppet::Node, " when returning the environment" do - before do - @node = Puppet::Node.new("testnode") - end - - it "should return the 'environment' fact if present and there is no explicit environment" do - @node.parameters = {"environment" => "myenv"} - @node.environment.should == "myenv" - end - - it "should return the central environment if there is no environment fact nor explicit environment" do - Puppet.config.expects(:[]).with(:environment).returns(:centralenv) - @node.environment.should == :centralenv - end - - it "should not use an explicit environment that is an empty string" do - @node.environment == "" - @node.environment.should be_nil - end - - it "should not use an environment fact that is an empty string" do - @node.parameters = {"environment" => ""} - @node.environment.should be_nil - end - - it "should not use an explicit environment that is an empty string" do - Puppet.config.expects(:[]).with(:environment).returns(nil) - @node.environment.should be_nil - end -end - -describe Puppet::Node, " when merging facts" do - before do - @node = Puppet::Node.new("testnode") - end - - it "should prefer parameters already set on the node over facts from the node" do - @node.parameters = {"one" => "a"} - @node.fact_merge("one" => "c") - @node.parameters["one"].should == "a" - end - - it "should add passed parameters to the parameter list" do - @node.parameters = {"one" => "a"} - @node.fact_merge("two" => "b") - @node.parameters["two"].should == "b" - end -end diff --git a/spec/unit/util/config.rb b/spec/unit/util/config.rb index 348a54893..28ccb04d7 100755 --- a/spec/unit/util/config.rb +++ b/spec/unit/util/config.rb @@ -387,22 +387,40 @@ describe Puppet::Util::Config, " when reparsing its configuration" do end end -#describe Puppet::Util::Config, " when being used to manage the host machine" do -# it "should provide a method that writes files with the correct modes" -# -# it "should provide a method that creates directories with the correct modes" -# -# it "should provide a method to declare what directories should exist" -# -# it "should provide a method to trigger enforcing of file modes on existing files and directories" -# -# it "should provide a method to convert the file mode enforcement into a Puppet manifest" -# -# it "should provide an option to create needed users and groups" -# -# it "should provide a method to print out the current configuration" -# -# it "should be able to provide all of its parameters in a format compatible with GetOpt::Long" -# -# it "should not attempt to manage files within /dev" -#end +describe Puppet::Util::Config, " when being used to manage the host machine" do + it "should provide a method that writes files with the correct modes" do + pending "Not converted from test/unit yet" + end + + it "should provide a method that creates directories with the correct modes" do + pending "Not converted from test/unit yet" + end + + it "should provide a method to declare what directories should exist" do + pending "Not converted from test/unit yet" + end + + it "should provide a method to trigger enforcing of file modes on existing files and directories" do + pending "Not converted from test/unit yet" + end + + it "should provide a method to convert the file mode enforcement into a Puppet manifest" do + pending "Not converted from test/unit yet" + end + + it "should provide an option to create needed users and groups" do + pending "Not converted from test/unit yet" + end + + it "should provide a method to print out the current configuration" do + pending "Not converted from test/unit yet" + end + + it "should be able to provide all of its parameters in a format compatible with GetOpt::Long" do + pending "Not converted from test/unit yet" + end + + it "should not attempt to manage files within /dev" do + pending "Not converted from test/unit yet" + end +end diff --git a/test/language/snippets.rb b/test/language/snippets.rb index 2c74543e7..ff8a09881 100755 --- a/test/language/snippets.rb +++ b/test/language/snippets.rb @@ -472,13 +472,14 @@ class TestSnippets < Test::Unit::TestCase :Manifest => snippet(file), :Local => true ) - server.send(:fact_handler).stubs(:set) - server.send(:fact_handler).stubs(:get).returns(facts) + facts = Puppet::Node::Facts.new("testhost", facts) + Puppet::Node::Facts.stubs(:post) + Puppet::Node::Facts.stubs(:get).returns(facts) client = Puppet::Network::Client.master.new( :Master => server, :Cache => false ) - client.class.stubs(:facts).returns(facts) + client.class.stubs(:facts).returns(facts.values) assert(client.local) assert_nothing_raised { diff --git a/test/lib/puppettest.rb b/test/lib/puppettest.rb index 45c5b2ed9..06b85f147 100755 --- a/test/lib/puppettest.rb +++ b/test/lib/puppettest.rb @@ -264,6 +264,7 @@ module PuppetTest Puppet::Type.allclear Puppet::Util::Storage.clear Puppet.clear + Puppet.config.clear @memoryatend = Puppet::Util.memory diff = @memoryatend - @memoryatstart diff --git a/test/lib/puppettest/parsertesting.rb b/test/lib/puppettest/parsertesting.rb index eef0cd8bc..c4bd7dc2b 100644 --- a/test/lib/puppettest/parsertesting.rb +++ b/test/lib/puppettest/parsertesting.rb @@ -42,7 +42,6 @@ module PuppetTest::ParserTesting end def mkcompile(parser = nil) - require 'puppet/network/handler/node' parser ||= mkparser node = mknode return Compile.new(node, parser) diff --git a/test/lib/puppettest/runnable_test.rb b/test/lib/puppettest/runnable_test.rb new file mode 100644 index 000000000..e4b0f9033 --- /dev/null +++ b/test/lib/puppettest/runnable_test.rb @@ -0,0 +1,30 @@ +# Manage whether a test is runnable. +module PuppetTest + module RunnableTest + # Confine this test based on specified criteria. The keys of the + # hash should be the message to use if the test is not suitable, + # and the values should be either 'true' or 'false'; true values + # mean the test is suitable. + def confine(hash) + @confines ||= {} + hash.each do |message, result| + @confines[message] = result + end + end + + # Evaluate all of our tests to see if any of them are false + # and thus whether this test is considered not runnable. + def runnable? + @messages ||= [] + return false unless @messages.empty? + return true unless defined? @confines + @confines.find_all do |message, result| + ! result + end.each do |message, result| + @messages << message + end + + return @messages.empty? + end + end +end diff --git a/test/lib/puppettest/testcase.rb b/test/lib/puppettest/testcase.rb index cfedeee26..15c835854 100644 --- a/test/lib/puppettest/testcase.rb +++ b/test/lib/puppettest/testcase.rb @@ -4,28 +4,11 @@ # Copyright (c) 2007. All rights reserved. require 'puppettest' +require 'puppettest/runnable_test' class PuppetTest::TestCase < Test::Unit::TestCase include PuppetTest - def self.confine(hash) - @confines ||= {} - hash.each do |message, result| - @confines[message] = result - end - end - - def self.runnable? - @messages ||= [] - return false unless @messages.empty? - return true unless defined? @confines - @confines.find_all do |message, result| - ! result - end.each do |message, result| - @messages << message - end - - return @messages.empty? - end + extend PuppetTest::RunnableTest def self.suite # Always skip this parent class. It'd be nice if there were a @@ -44,5 +27,3 @@ class PuppetTest::TestCase < Test::Unit::TestCase end end end - -# $Id$ diff --git a/test/network/handler/configuration.rb b/test/network/handler/configuration.rb index 0964a4c5e..29a393769 100755 --- a/test/network/handler/configuration.rb +++ b/test/network/handler/configuration.rb @@ -63,14 +63,14 @@ class TestHandlerConfiguration < Test::Unit::TestCase fakenode = Object.new # Set the server facts to something config.instance_variable_set("@server_facts", :facts) - fakenode.expects(:fact_merge).with(:facts) + fakenode.expects(:merge).with(:facts) config.send(:add_node_data, fakenode) # Now try it with classes. config.instance_variable_set("@options", {:Classes => %w{a b}}) list = [] fakenode = Object.new - fakenode.expects(:fact_merge).with(:facts) + fakenode.expects(:merge).with(:facts) fakenode.expects(:classes).returns(list).times(2) config.send(:add_node_data, fakenode) assert_equal(%w{a b}, list, "Did not add classes to node") diff --git a/test/network/handler/facts.rb b/test/network/handler/facts.rb deleted file mode 100755 index 03327b8c4..000000000 --- a/test/network/handler/facts.rb +++ /dev/null @@ -1,112 +0,0 @@ -#!/usr/bin/env ruby - -$:.unshift("../../lib") if __FILE__ =~ /\.rb$/ - -require 'puppettest' -require 'mocha' -require 'puppet/network/handler/facts' - -class TestFactsHandler < Test::Unit::TestCase - include PuppetTest::ServerTest - - def setup - super - - @class = Puppet::Network::Handler.handler(:facts) - - @@client_facts = {} - - unless Puppet::Util::FactStore.store(:testing) - Puppet::Util::FactStore.newstore(:testing) do - def get(node) - @@client_facts[node] - end - - def set(node, facts) - @@client_facts[node] = facts - end - end - end - - Puppet[:factstore] = :testing - - @handler = @class.new - - @facts = {:a => :b, :c => :d} - @name = "foo" - - @backend = @handler.instance_variable_get("@backend") - end - - def teardown - @@client_facts.clear - end - - def test_strip_internal - @facts[:_puppet_one] = "yay" - @facts[:_puppet_two] = "boo" - @facts[:_puppetthree] = "foo" - - newfacts = nil - assert_nothing_raised("Could not call strip_internal") do - newfacts = @handler.send(:strip_internal, @facts) - end - - [:_puppet_one, :_puppet_two, :_puppetthree].each do |name| - assert(@facts.include?(name), "%s was removed in strip_internal from original hash" % name) - end - [:_puppet_one, :_puppet_two].each do |name| - assert(! newfacts.include?(name), "%s was not removed in strip_internal" % name) - end - assert_equal("foo", newfacts[:_puppetthree], "_puppetthree was removed in strip_internal") - end - - def test_add_internal - newfacts = nil - assert_nothing_raised("Could not call strip_internal") do - newfacts = @handler.send(:add_internal, @facts) - end - - assert_instance_of(Time, newfacts[:_puppet_timestamp], "Did not set timestamp in add_internal") - assert(! @facts.include?(:_puppet_timestamp), "Modified original hash in add_internal") - end - - def test_set - newfacts = @facts.dup - newfacts[:_puppet_timestamp] = Time.now - @handler.expects(:add_internal).with(@facts).returns(newfacts) - @backend.expects(:set).with(@name, newfacts).returns(nil) - - assert_nothing_raised("Could not set facts") do - assert_nil(@handler.set(@name, @facts), "handler.set did not return nil") - end - end - - def test_get - prefacts = @facts.dup - prefacts[:_puppet_timestamp] = Time.now - @@client_facts[@name] = prefacts - @handler.expects(:strip_internal).with(prefacts).returns(@facts) - @backend.expects(:get).with(@name).returns(prefacts) - - assert_nothing_raised("Could not retrieve facts") do - assert_equal(@facts, @handler.get(@name), "did not get correct answer from handler.get") - end - - @handler = @class.new - assert_nothing_raised("Failed to call 'get' with no stored facts") do - @handler.get("nosuchname") - end - end - - def test_store_date - time = Time.now - @facts[:_puppet_timestamp] = time - - @handler.expects(:get).with(@name).returns(@facts) - - assert_equal(time.to_i, @handler.store_date(@name), "Did not retrieve timestamp correctly") - end -end - -# $Id$ diff --git a/test/network/handler/master.rb b/test/network/handler/master.rb index a976726ef..9749c7bdf 100755 --- a/test/network/handler/master.rb +++ b/test/network/handler/master.rb @@ -8,6 +8,11 @@ require 'puppet/network/handler/master' class TestMaster < Test::Unit::TestCase include PuppetTest::ServerTest + def teardown + super + Puppet::Indirector::Indirection.clear_cache + end + def test_defaultmanifest textfiles { |file| Puppet[:manifest] = file |