diff --git a/lib/puppet/parser/collector.rb b/lib/puppet/parser/collector.rb index c9d5ed5f0..d995bf7a7 100644 --- a/lib/puppet/parser/collector.rb +++ b/lib/puppet/parser/collector.rb @@ -1,178 +1,180 @@ # An object that collects stored objects from the central cache and returns # them to the current host, yo. class Puppet::Parser::Collector attr_accessor :type, :scope, :vquery, :rquery, :form, :resources # Collect exported objects. def collect_exported # First get everything from the export table. Just reuse our # collect_virtual method but tell it to use 'exported? for the test. resources = collect_virtual(true).reject { |r| ! r.virtual? } count = 0 unless @scope.host raise Puppet::DevError, "Cannot collect resources for a nil host" end # We're going to collect objects from rails, but we don't want any # objects from this host. unless ActiveRecord::Base.connected? Puppet::Rails.init end host = Puppet::Rails::Host.find_by_name(@scope.host) args = {:include => {:param_values => :param_name}} args[:conditions] = "(exported = 't' AND restype = '%s')" % [@type] if @equery args[:conditions] += " AND (%s)" % [@equery] end if host args[:conditions] = "host_id != %s AND %s" % [host.id, args[:conditions]] else #Puppet.info "Host %s is uninitialized" % @scope.host end # Now look them up in the rails db. When we support attribute comparison # and such, we'll need to vary the conditions, but this works with no # attributes, anyway. time = Puppet::Util.thinmark do Puppet::Rails::Resource.find(:all, @type, true, args ).each do |obj| if resource = export_resource(obj) count += 1 resources << resource end end end scope.debug("Collected %s %s resource%s in %.2f seconds" % [count, @type, count == 1 ? "" : "s", time]) return resources end def collect_resources unless @resources.is_a?(Array) @resources = [@resources] end method = "collect_#{form.to_s}_resources" send(method) end def collect_exported_resources raise Puppet::ParseError, "realize() is not yet implemented for exported resources" end # Collect resources directly; this is the result of using 'realize', # which specifies resources, rather than using a normal collection. def collect_virtual_resources result = @resources.dup.collect do |ref| if res = @scope.findresource(ref.to_s) @resources.delete(ref) res end end.reject { |r| r.nil? }.each do |res| res.virtual = false end # If there are no more resources to find, delete this from the list # of collections. if @resources.empty? @scope.compile.delete_collection(self) end return result end # Collect just virtual objects, from our local compile. def collect_virtual(exported = false) if exported method = :exported? else method = :virtual? end scope.compile.resources.find_all do |resource| resource.type == @type and resource.send(method) and match?(resource) end end # Call the collection method, mark all of the returned objects as non-virtual, # and then delete this object from the list of collections to evaluate. def evaluate if self.resources if objects = collect_resources and ! objects.empty? return objects else return false end else method = "collect_#{@form.to_s}" objects = send(method).each { |obj| obj.virtual = false } if objects.empty? return false else return objects end end end def initialize(scope, type, equery, vquery, form) @scope = scope + + unless scope.resource + raise "wtf?" + end @type = type @equery = equery @vquery = vquery @form = form @tests = [] end # Does the resource match our tests? We don't yet support tests, # so it's always true at the moment. def match?(resource) if self.vquery return self.vquery.call(resource) else return true end end def export_resource(obj) if existing = @scope.findresource(obj.restype, obj.title) # See if we exported it; if so, just move on if @scope.host == obj.host.name return nil else # Next see if we've already collected this resource if existing.rails_id == obj.id # This is the one we've already collected return nil else raise Puppet::ParseError, "Exported resource %s cannot override local resource" % [obj.ref] end end end begin resource = obj.to_resource(self.scope) # XXX Because the scopes don't expect objects to return values, # we have to manually add our objects to the scope. This is # über-lame. - scope.setresource(resource) + scope.compile.store_resource(scope, resource) rescue => detail if Puppet[:trace] puts detail.backtrace end raise end resource.exported = false return resource end end - -# $Id$ diff --git a/lib/puppet/parser/compile.rb b/lib/puppet/parser/compile.rb index cc9938e50..6aeebeaae 100644 --- a/lib/puppet/parser/compile.rb +++ b/lib/puppet/parser/compile.rb @@ -1,494 +1,498 @@ # Created by Luke A. Kanies on 2007-08-13. # Copyright (c) 2007. All rights reserved. require 'puppet/external/gratr/digraph' require 'puppet/external/gratr/import' require 'puppet/external/gratr/dot' require 'puppet/node' require 'puppet/node/configuration' require 'puppet/util/errors' # Maintain a graph of scopes, along with a bunch of data # about the individual configuration we're compiling. class Puppet::Parser::Compile include Puppet::Util include Puppet::Util::Errors attr_reader :topscope, :parser, :node, :facts, :collections, :configuration attr_writer :ast_nodes # Add a collection to the global list. def add_collection(coll) @collections << coll end # Do we use nodes found in the code, vs. the external node sources? def ast_nodes? defined?(@ast_nodes) and @ast_nodes end # Store the fact that we've evaluated a class, and store a reference to # the scope in which it was evaluated, so that we can look it up later. def class_set(name, scope) if existing = @class_scopes[name] if existing.nodescope? or scope.nodescope? raise Puppet::ParseError, "Cannot have classes, nodes, or definitions with the same name" else raise Puppet::DevError, "Somehow evaluated the same class twice" end end @class_scopes[name] = scope @configuration.add_class(name) unless name == "" end # Return the scope associated with a class. This is just here so # that subclasses can set their parent scopes to be the scope of # their parent class, and it's also used when looking up qualified # variables. def class_scope(klass) # They might pass in either the class or class name if klass.respond_to?(:classname) @class_scopes[klass.classname] else @class_scopes[klass] end end # Return a list of all of the defined classes. def classlist return @configuration.classes end # Compile our configuration. This mostly revolves around finding and evaluating classes. # This is the main entry into our configuration. def compile # Set the client's parameters into the top scope. set_node_parameters() evaluate_main() evaluate_ast_node() evaluate_node_classes() evaluate_generators() fail_on_unevaluated() finish() if Puppet[:storeconfigs] store() end return @configuration end # FIXME There are no tests for this. def delete_collection(coll) @collections.delete(coll) if @collections.include?(coll) end # FIXME There are no tests for this. def delete_resource(resource) @resource_table.delete(resource.ref) if @resource_table.include?(resource.ref) end # Return the node's environment. def environment unless defined? @environment if node.environment and node.environment != "" @environment = node.environment else @environment = nil end end @environment end # Evaluate all of the classes specified by the node. def evaluate_node_classes evaluate_classes(@node.classes, @topscope) end # Evaluate each specified class in turn. If there are any classes we can't # find, just tag the configuration and move on. This method really just # creates resource objects that point back to the classes, and then the # resources are themselves evaluated later in the process. def evaluate_classes(classes, scope) unless scope.source raise Puppet::DevError, "No source for scope passed to evaluate_classes" end found = [] classes.each do |name| # If we can find the class, then make a resource that will evaluate it. if klass = scope.findclass(name) # Create a resource to model this class, and then add it to the list # of resources. resource = Puppet::Parser::Resource.new(:type => "class", :title => klass.classname, :scope => scope, :source => scope.source) store_resource(scope, resource) @configuration.tag(klass.classname) found << name else Puppet.info "Could not find class %s for %s" % [name, node.name] @configuration.tag(name) end end found end # Return a resource by either its ref or its type and title. def findresource(string, name = nil) if name string = "%s[%s]" % [string.capitalize, name] end @resource_table[string] end # Set up our compile. We require a parser # and a node object; the parser is so we can look up classes # and AST nodes, and the node has all of the client's info, # like facts and environment. def initialize(node, parser, options = {}) @node = node @parser = parser options.each do |param, value| begin send(param.to_s + "=", value) rescue NoMethodError raise ArgumentError, "Compile objects do not accept %s" % param end end initvars() init_main() end # Create a new scope, with either a specified parent scope or # using the top scope. Adds an edge between the scope and # its parent to the graph. def newscope(parent, options = {}) parent ||= @topscope options[:compile] = self options[:parser] ||= self.parser scope = Puppet::Parser::Scope.new(options) @scope_graph.add_edge!(parent, scope) scope end # Find the parent of a given scope. Assumes scopes only ever have # one in edge, which will always be true. def parent(scope) if ary = @scope_graph.adjacent(scope, :direction => :in) and ary.length > 0 ary[0] else nil end end # Return any overrides for the given resource. def resource_overrides(resource) @resource_overrides[resource.ref] end # Return a list of all resources. def resources @resource_table.values end # Store a resource override. def store_override(override) override.override = true # If possible, merge the override in immediately. if resource = @resource_table[override.ref] resource.merge(override) else # Otherwise, store the override for later; these # get evaluated in Resource#finish. @resource_overrides[override.ref] << override end end # Store a resource in our resource table. def store_resource(scope, resource) # This might throw an exception verify_uniqueness(resource) # Store it in the global table. @resource_table[resource.ref] = resource # And in the resource graph. At some point, this might supercede # the global resource table, but the table is a lot faster # so it makes sense to maintain for now. @configuration.add_edge!(scope.resource, resource) end private # If ast nodes are enabled, then see if we can find and evaluate one. def evaluate_ast_node return unless ast_nodes? # Now see if we can find the node. astnode = nil @node.names.each do |name| break if astnode = @parser.nodes[name.to_s.downcase] end unless astnode astnode = @parser.nodes["default"] end unless astnode raise Puppet::ParseError, "Could not find default node or by name with '%s'" % node.names.join(", ") end - astnode.safeevaluate :scope => topscope + # Create a resource to model this node, and then add it to the list + # of resources. + resource = Puppet::Parser::Resource.new(:type => "node", :title => astnode.classname, :scope => topscope, :source => topscope.source) + store_resource(topscope, resource) + @configuration.tag(astnode.classname) end # Evaluate our collections and return true if anything returned an object. # The 'true' is used to continue a loop, so it's important. def evaluate_collections return false if @collections.empty? found_something = false exceptwrap do @collections.each do |collection| if collection.evaluate found_something = true end end end return found_something end # Make sure all of our resources have been evaluated into native resources. # We return true if any resources have, so that we know to continue the # evaluate_generators loop. def evaluate_definitions exceptwrap do if ary = unevaluated_resources ary.each do |resource| resource.evaluate end # If we evaluated, let the loop know. return true else return false end end end # Iterate over collections and resources until we're sure that the whole # compile is evaluated. This is necessary because both collections # and defined resources can generate new resources, which themselves could # be defined resources. def evaluate_generators count = 0 loop do done = true # Call collections first, then definitions. done = false if evaluate_collections done = false if evaluate_definitions break if done if count > 1000 raise Puppet::ParseError, "Somehow looped more than 1000 times while evaluating host configuration" end end end # Find and evaluate our main object, if possible. def evaluate_main @main = @parser.findclass("", "") || @parser.newclass("") @topscope.source = @main @main_resource = Puppet::Parser::Resource.new(:type => "class", :title => :main, :scope => @topscope, :source => @main) @topscope.resource = @main_resource @configuration.add_vertex!(@main_resource) @resource_table["Class[main]"] = @main_resource end # Make sure the entire configuration is evaluated. def fail_on_unevaluated fail_on_unevaluated_overrides fail_on_unevaluated_resource_collections end # If there are any resource overrides remaining, then we could # not find the resource they were supposed to override, so we # want to throw an exception. def fail_on_unevaluated_overrides remaining = [] @resource_overrides.each do |name, overrides| remaining += overrides end unless remaining.empty? fail Puppet::ParseError, "Could not find object(s) %s" % remaining.collect { |o| o.ref }.join(", ") end end # Make sure we don't have any remaining collections that specifically # look for resources, because we want to consider those to be # parse errors. def fail_on_unevaluated_resource_collections remaining = [] @collections.each do |coll| # We're only interested in the 'resource' collections, # which result from direct calls of 'realize'. Anything # else is allowed not to return resources. # Collect all of them, so we have a useful error. if r = coll.resources if r.is_a?(Array) remaining += r else remaining << r end end end unless remaining.empty? raise Puppet::ParseError, "Failed to realize virtual resources %s" % remaining.join(', ') end end # Make sure all of our resources and such have done any last work # necessary. def finish @resource_table.each { |name, resource| resource.finish if resource.respond_to?(:finish) } end # Initialize the top-level scope, class, and resource. def init_main # Create our initial scope and a resource that will evaluate main. @topscope = Puppet::Parser::Scope.new(:compile => self, :parser => self.parser) @scope_graph.add_vertex!(@topscope) end # Set up all of our internal variables. def initvars # The table for storing class singletons. This will only actually # be used by top scopes and node scopes. @class_scopes = {} # The table for all defined resources. @resource_table = {} # The list of objects that will available for export. @exported_resources = {} # The list of overrides. This is used to cache overrides on objects # that don't exist yet. We store an array of each override. @resource_overrides = Hash.new do |overs, ref| overs[ref] = [] end # The list of collections that have been created. This is a global list, # but they each refer back to the scope that created them. @collections = [] # A list of tags we've generated; most class names. @tags = [] # A graph for maintaining scope relationships. @scope_graph = GRATR::Digraph.new @scope_graph.add_vertex!(@topscope) # For maintaining the relationship between scopes and their resources. @configuration = Puppet::Node::Configuration.new(@node.name) @configuration.version = @parser.version end # Set the node's parameters into the top-scope as variables. def set_node_parameters node.parameters.each do |param, value| @topscope.setvar(param, value) end end # Store the configuration into the database. def store unless Puppet.features.rails? raise Puppet::Error, "storeconfigs is enabled but rails is unavailable" end unless ActiveRecord::Base.connected? Puppet::Rails.connect end # We used to have hooks here for forking and saving, but I don't # think it's worth retaining at this point. store_to_active_record(@node, @resource_table.values) end # Do the actual storage. def store_to_active_record(node, resources) begin # We store all of the objects, even the collectable ones benchmark(:info, "Stored configuration for #{node.name}") do Puppet::Rails::Host.transaction do Puppet::Rails::Host.store(node, resources) end end rescue => detail if Puppet[:trace] puts detail.backtrace end Puppet.err "Could not store configs: %s" % detail.to_s end end # Return an array of all of the unevaluated resources. These will be definitions, # which need to get evaluated into native resources. def unevaluated_resources ary = @resource_table.find_all do |name, object| ! object.builtin? and ! object.evaluated? end.collect { |name, object| object } if ary.empty? return nil else return ary end end # Verify that the given resource isn't defined elsewhere. def verify_uniqueness(resource) # Short-curcuit the common case, unless existing_resource = @resource_table[resource.ref] return true end if typeclass = Puppet::Type.type(resource.type) and ! typeclass.isomorphic? Puppet.info "Allowing duplicate %s" % typeclass.name return true end # Either it's a defined type, which are never # isomorphic, or it's a non-isomorphic type, so # we should throw an exception. msg = "Duplicate definition: %s is already defined" % resource.ref if existing_resource.file and existing_resource.line msg << " in file %s at line %s" % [existing_resource.file, existing_resource.line] end if resource.line or resource.file msg << "; cannot redefine" end raise Puppet::ParseError.new(msg) end end diff --git a/test/language/compile.rb b/test/language/compile.rb index ceec3c346..5732acba3 100755 --- a/test/language/compile.rb +++ b/test/language/compile.rb @@ -1,668 +1,669 @@ #!/usr/bin/env ruby $:.unshift("../lib").unshift("../../lib") if __FILE__ =~ /\.rb$/ require 'mocha' require 'puppettest' require 'puppettest/parsertesting' require 'puppet/parser/compile' # Test our compile object. class TestCompile < Test::Unit::TestCase include PuppetTest include PuppetTest::ParserTesting Compile = Puppet::Parser::Compile Scope = Puppet::Parser::Scope Node = Puppet::Network::Handler.handler(:node) SimpleNode = Puppet::Node def mknode(name = "foo") @node = SimpleNode.new(name) end def mkparser # This should mock an interpreter @parser = stub 'parser', :version => "1.0" end def mkcompile(options = {}) if node = options[:node] options.delete(:node) else node = mknode end @compile = Compile.new(node, mkparser, options) end def test_initialize compile = nil node = stub 'node', :name => "foo" parser = stub 'parser', :version => "1.0" assert_nothing_raised("Could not init compile with all required options") do compile = Compile.new(node, parser) end assert_equal(node, compile.node, "Did not set node correctly") assert_equal(parser, compile.parser, "Did not set parser correctly") # We're not testing here whether we call initvars, because it's too difficult to # mock. # Now try it with some options assert_nothing_raised("Could not init compile with extra options") do compile = Compile.new(node, parser, :ast_nodes => false) end assert_equal(false, compile.ast_nodes?, "Did not set ast_nodes? correctly") end def test_initvars compile = mkcompile [:class_scopes, :resource_table, :exported_resources, :resource_overrides].each do |table| assert_instance_of(Hash, compile.send(:instance_variable_get, "@#{table}"), "Did not set %s table correctly" % table) end assert_instance_of(Scope, compile.topscope, "Did not create a topscope") graph = compile.instance_variable_get("@scope_graph") assert_instance_of(GRATR::Digraph, graph, "Did not create scope graph") assert(graph.vertex?(compile.topscope), "Did not add top scope as a vertex in the graph") end # Make sure we store and can retrieve references to classes and their scopes. def test_class_set_and_class_scope klass = mock 'ast_class' klass.expects(:classname).returns("myname") compile = mkcompile compile.configuration.expects(:tag).with("myname") assert_nothing_raised("Could not set class") do compile.class_set "myname", "myscope" end # First try to retrieve it by name. assert_equal("myscope", compile.class_scope("myname"), "Could not retrieve class scope by name") # Then by object assert_equal("myscope", compile.class_scope(klass), "Could not retrieve class scope by object") end def test_classlist compile = mkcompile compile.class_set "", "empty" compile.class_set "one", "yep" compile.class_set "two", "nope" # Make sure our class list is correct assert_equal(%w{one two}.sort, compile.classlist.sort, "Did not get correct class list") end # Make sure collections get added to our internal array def test_add_collection compile = mkcompile assert_nothing_raised("Could not add collection") do compile.add_collection "nope" end assert_equal(%w{nope}, compile.instance_variable_get("@collections"), "Did not add collection") end # Make sure we create a graph of scopes. def test_newscope compile = mkcompile graph = compile.instance_variable_get("@scope_graph") assert_instance_of(Scope, compile.topscope, "Did not create top scope") assert_instance_of(GRATR::Digraph, graph, "Did not create graph") assert(graph.vertex?(compile.topscope), "The top scope is not a vertex in the graph") # Now that we've got the top scope, create a new, subscope subscope = nil assert_nothing_raised("Could not create subscope") do subscope = compile.newscope(compile.topscope) end assert_instance_of(Scope, subscope, "Did not create subscope") assert(graph.edge?(compile.topscope, subscope), "An edge between top scope and subscope was not added") # Make sure a scope can find its parent. assert(compile.parent(subscope), "Could not look up parent scope on compile") assert_equal(compile.topscope.object_id, compile.parent(subscope).object_id, "Did not get correct parent scope from compile") assert_equal(compile.topscope.object_id, subscope.parent.object_id, "Scope did not correctly retrieve its parent scope") # Now create another, this time specifying options another = nil assert_nothing_raised("Could not create subscope") do another = compile.newscope(subscope, :level => 5) end assert_equal(5, another.level, "did not set scope option correctly") assert_instance_of(Scope, another, "Did not create second subscope") assert(graph.edge?(subscope, another), "An edge between parent scope and second subscope was not added") # Make sure it can find its parent. assert(compile.parent(another), "Could not look up parent scope of second subscope on compile") assert_equal(subscope.object_id, compile.parent(another).object_id, "Did not get correct parent scope of second subscope from compile") assert_equal(subscope.object_id, another.parent.object_id, "Second subscope did not correctly retrieve its parent scope") # And make sure both scopes show up in the right order in the search path assert_equal([another.object_id, subscope.object_id, compile.topscope.object_id], another.scope_path.collect { |p| p.object_id }, "Did not get correct scope path") end # The heart of the action. def test_compile compile = mkcompile [:set_node_parameters, :evaluate_main, :evaluate_ast_node, :evaluate_node_classes, :evaluate_generators, :fail_on_unevaluated, :finish].each do |method| compile.expects(method) end assert_instance_of(Puppet::Node::Configuration, compile.compile, "Did not return the configuration") end # Test setting the node's parameters into the top scope. def test_set_node_parameters compile = mkcompile @node.parameters = {"a" => "b", "c" => "d"} scope = compile.topscope @node.parameters.each do |param, value| scope.expects(:setvar).with(param, value) end assert_nothing_raised("Could not call 'set_node_parameters'") do compile.send(:set_node_parameters) end end # Test that we can evaluate the main class, which is the one named "" in namespace # "". def test_evaluate_main compile = mkcompile main = mock 'main_class' compile.topscope.expects(:source=).with(main) @parser.expects(:findclass).with("", "").returns(main) assert_nothing_raised("Could not call evaluate_main") do compile.send(:evaluate_main) end assert(compile.resources.find { |r| r.to_s == "Class[main]" }, "Did not create a 'main' resource") end # Make sure we either don't look for nodes, or that we find and evaluate the right object. def test_evaluate_ast_node # First try it with ast_nodes disabled compile = mkcompile :ast_nodes => false + name = compile.node.name compile.expects(:ast_nodes?).returns(false) compile.parser.expects(:nodes).never assert_nothing_raised("Could not call evaluate_ast_node when ast nodes are disabled") do compile.send(:evaluate_ast_node) end + assert_nil(compile.resources.find { |r| r.to_s == "Node[#{name}]" }, "Created node object when ast_nodes was false") + # Now try it with them enabled, but no node found. nodes = mock 'node_hash' compile = mkcompile :ast_nodes => true + name = compile.node.name compile.expects(:ast_nodes?).returns(true) - compile.parser.expects(:nodes).returns(nodes).times(4) + compile.parser.stubs(:nodes).returns(nodes) # Set some names for our test @node.names = %w{a b c} nodes.expects(:[]).with("a").returns(nil) nodes.expects(:[]).with("b").returns(nil) nodes.expects(:[]).with("c").returns(nil) # It should check this last, of course. nodes.expects(:[]).with("default").returns(nil) # And make sure the lack of a node throws an exception assert_raise(Puppet::ParseError, "Did not fail when we couldn't find an ast node") do compile.send(:evaluate_ast_node) end # Finally, make sure it works dandily when we have a node - nodes = mock 'hash' compile = mkcompile :ast_nodes => true compile.expects(:ast_nodes?).returns(true) - compile.parser.expects(:nodes).returns(nodes).times(3) - node = mock 'node' - node.expects(:safeevaluate).with(:scope => compile.topscope) + node = stub 'node', :classname => "c" + nodes = {"c" => node} + compile.parser.stubs(:nodes).returns(nodes) + # Set some names for our test @node.names = %w{a b c} - nodes.expects(:[]).with("a").returns(nil) - nodes.expects(:[]).with("b").returns(nil) - nodes.expects(:[]).with("c").returns(node) - nodes.expects(:[]).with("default").never - # And make sure the lack of a node throws an exception + # And make sure we throw no exceptions. assert_nothing_raised("Failed when a node was found") do compile.send(:evaluate_ast_node) end + assert_instance_of(Puppet::Parser::Resource, compile.resources.find { |r| r.to_s == "Node[c]" }, + "Did not create node resource") + # Lastly, check when we actually find the default. - nodes = mock 'hash' compile = mkcompile :ast_nodes => true compile.expects(:ast_nodes?).returns(true) - compile.parser.expects(:nodes).returns(nodes).times(4) - node = mock 'node' - node.expects(:safeevaluate).with(:scope => compile.topscope) + node = stub 'node', :classname => "default" + nodes = {"default" => node} + compile.parser.stubs(:nodes).returns(nodes) + # Set some names for our test @node.names = %w{a b c} - nodes.expects(:[]).with("a").returns(nil) - nodes.expects(:[]).with("b").returns(nil) - nodes.expects(:[]).with("c").returns(nil) - nodes.expects(:[]).with("default").returns(node) # And make sure the lack of a node throws an exception assert_nothing_raised("Failed when a node was found") do compile.send(:evaluate_ast_node) end + assert_instance_of(Puppet::Parser::Resource, compile.resources.find { |r| r.to_s == "Node[default]" }, + "Did not create default node resource") end def test_evaluate_node_classes compile = mkcompile @node.classes = %w{one two three four} compile.expects(:evaluate_classes).with(%w{one two three four}, compile.topscope) assert_nothing_raised("could not call evaluate_node_classes") do compile.send(:evaluate_node_classes) end end def test_evaluate_classes compile = mkcompile compile.parser.expects(:findclass).with("", "").returns(stub('main', :classname => "")) compile.send :evaluate_main classes = { "one" => stub('class one', :classname => "one"), "three" => stub('class three', :classname => "three") } classes.each do |name, obj| compile.parser.expects(:findclass).with("", name).returns(obj) end %w{two four}.each do |name| compile.parser.expects(:findclass).with("", name).returns(nil) end %w{one two three four}.each do |name| compile.configuration.expects(:tag).with(name) end result = nil assert_nothing_raised("could not call evaluate_node_classes") do result = compile.send(:evaluate_classes, %w{one two three four}, compile.topscope) end %w{one three}.each do |found| assert(compile.resources.find { |r| r.to_s == "Class[#{found}]" }, "Did not create a class resource for %s" % found) end assert_equal(%w{one three}, result, "Did not return the list of evaluated classes") end def test_evaluate_collections compile = mkcompile colls = [] # Make sure we return false when there's nothing there. assert(! compile.send(:evaluate_collections), "Returned true when there were no collections") # And when the collections fail to evaluate. colls << mock("coll1-false") colls << mock("coll2-false") colls.each { |c| c.expects(:evaluate).returns(false) } compile.instance_variable_set("@collections", colls) assert(! compile.send(:evaluate_collections), "Returned true when collections both evaluated nothing") # Now have one of the colls evaluate colls.clear colls << mock("coll1-one-true") colls << mock("coll2-one-true") colls[0].expects(:evaluate).returns(true) colls[1].expects(:evaluate).returns(false) assert(compile.send(:evaluate_collections), "Did not return true when one collection evaluated true") # And have them both eval true colls.clear colls << mock("coll1-both-true") colls << mock("coll2-both-true") colls[0].expects(:evaluate).returns(true) colls[1].expects(:evaluate).returns(true) assert(compile.send(:evaluate_collections), "Did not return true when both collections evaluated true") end def test_unevaluated_resources compile = mkcompile resources = {} compile.instance_variable_set("@resource_table", resources) # First test it when the table is empty assert_nil(compile.send(:unevaluated_resources), "Somehow found unevaluated resources in an empty table") # Then add a builtin resources resources["one"] = mock("builtin only") resources["one"].expects(:builtin?).returns(true) assert_nil(compile.send(:unevaluated_resources), "Considered a builtin resource unevaluated") # And do both builtin and non-builtin but already evaluated resources.clear resources["one"] = mock("builtin (with eval)") resources["one"].expects(:builtin?).returns(true) resources["two"] = mock("evaled (with builtin)") resources["two"].expects(:builtin?).returns(false) resources["two"].expects(:evaluated?).returns(true) assert_nil(compile.send(:unevaluated_resources), "Considered either a builtin or evaluated resource unevaluated") # Now a single unevaluated resource. resources.clear resources["one"] = mock("unevaluated") resources["one"].expects(:builtin?).returns(false) resources["one"].expects(:evaluated?).returns(false) assert_equal([resources["one"]], compile.send(:unevaluated_resources), "Did not find unevaluated resource") # With two uneval'ed resources, and an eval'ed one thrown in resources.clear resources["one"] = mock("unevaluated one") resources["one"].expects(:builtin?).returns(false) resources["one"].expects(:evaluated?).returns(false) resources["two"] = mock("unevaluated two") resources["two"].expects(:builtin?).returns(false) resources["two"].expects(:evaluated?).returns(false) resources["three"] = mock("evaluated") resources["three"].expects(:builtin?).returns(false) resources["three"].expects(:evaluated?).returns(true) result = compile.send(:unevaluated_resources) %w{one two}.each do |name| assert(result.include?(resources[name]), "Did not find %s in the unevaluated list" % name) end end def test_evaluate_definitions # First try the case where there's nothing to return compile = mkcompile compile.expects(:unevaluated_resources).returns(nil) assert_nothing_raised("Could not test for unevaluated resources") do assert(! compile.send(:evaluate_definitions), "evaluate_definitions returned true when no resources were evaluated") end # Now try it with resources left to evaluate resources = [] res1 = mock("resource1") res1.expects(:evaluate) res2 = mock("resource2") res2.expects(:evaluate) resources << res1 << res2 compile = mkcompile compile.expects(:unevaluated_resources).returns(resources) assert_nothing_raised("Could not test for unevaluated resources") do assert(compile.send(:evaluate_definitions), "evaluate_definitions returned false when resources were evaluated") end end def test_evaluate_generators # First try the case where we have nothing to do compile = mkcompile compile.expects(:evaluate_definitions).returns(false) compile.expects(:evaluate_collections).returns(false) assert_nothing_raised("Could not call :eval_iterate") do compile.send(:evaluate_generators) end # FIXME I could not get this test to work, but the code is short # enough that I'm ok with it. # It's important that collections are evaluated before definitions, # so make sure that's the case by verifying that collections get tested # twice but definitions only once. #compile = mkcompile #compile.expects(:evaluate_collections).returns(true).returns(false) #compile.expects(:evaluate_definitions).returns(false) #compile.send(:eval_iterate) end def test_store compile = mkcompile Puppet.features.expects(:rails?).returns(true) Puppet::Rails.expects(:connect) node = mock 'node' resource_table = mock 'resources' resource_table.expects(:values).returns(:resources) compile.instance_variable_set("@node", node) compile.instance_variable_set("@resource_table", resource_table) compile.expects(:store_to_active_record).with(node, :resources) compile.send(:store) end def test_store_to_active_record compile = mkcompile node = mock 'node' node.expects(:name).returns("myname") Puppet::Rails::Host.stubs(:transaction).yields Puppet::Rails::Host.expects(:store).with(node, :resources) compile.send(:store_to_active_record, node, :resources) end # Make sure that 'finish' gets called on all of our resources. def test_finish compile = mkcompile table = compile.instance_variable_get("@resource_table") # Add a resource that does respond to :finish yep = mock("finisher") yep.expects(:respond_to?).with(:finish).returns(true) yep.expects(:finish) table["yep"] = yep # And one that does not dnf = mock("dnf") dnf.expects(:respond_to?).with(:finish).returns(false) table["dnf"] = dnf compile.send(:finish) end def test_verify_uniqueness compile = mkcompile resources = compile.instance_variable_get("@resource_table") resource = mock("noconflict") resource.expects(:ref).returns("File[yay]") assert_nothing_raised("Raised an exception when there should have been no conflict") do compile.send(:verify_uniqueness, resource) end # Now try the case where our type is isomorphic resources["thing"] = true isoconflict = mock("isoconflict") isoconflict.expects(:ref).returns("thing") isoconflict.expects(:type).returns("testtype") faketype = mock("faketype") faketype.expects(:isomorphic?).returns(false) faketype.expects(:name).returns("whatever") Puppet::Type.expects(:type).with("testtype").returns(faketype) assert_nothing_raised("Raised an exception when was a conflict in non-isomorphic types") do compile.send(:verify_uniqueness, isoconflict) end # Now test for when we actually have an exception initial = mock("initial") resources["thing"] = initial initial.expects(:file).returns(false) conflict = mock("conflict") conflict.expects(:ref).returns("thing").times(2) conflict.expects(:type).returns("conflict") conflict.expects(:file).returns(false) conflict.expects(:line).returns(false) faketype = mock("faketype") faketype.expects(:isomorphic?).returns(true) Puppet::Type.expects(:type).with("conflict").returns(faketype) assert_raise(Puppet::ParseError, "Did not fail when two isomorphic resources conflicted") do compile.send(:verify_uniqueness, conflict) end end def test_store_resource # Run once when there's no conflict compile = mkcompile table = compile.instance_variable_get("@resource_table") resource = mock("resource") resource.expects(:ref).returns("yay") compile.expects(:verify_uniqueness).with(resource) scope = stub("scope", :resource => mock('resource')) compile.configuration.expects(:add_edge!).with(scope.resource, resource) assert_nothing_raised("Could not store resource") do compile.store_resource(scope, resource) end assert_equal(resource, table["yay"], "Did not store resource in table") # Now for conflicts compile = mkcompile table = compile.instance_variable_get("@resource_table") resource = mock("resource") compile.expects(:verify_uniqueness).with(resource).raises(ArgumentError) assert_raise(ArgumentError, "Did not raise uniqueness exception") do compile.store_resource(scope, resource) end assert(table.empty?, "Conflicting resource was stored in table") end def test_fail_on_unevaluated compile = mkcompile compile.expects(:fail_on_unevaluated_overrides) compile.expects(:fail_on_unevaluated_resource_collections) compile.send :fail_on_unevaluated end def test_store_override # First test the case when the resource is not present. compile = mkcompile overrides = compile.instance_variable_get("@resource_overrides") override = Object.new override.expects(:ref).returns(:myref).times(2) override.expects(:override=).with(true) assert_nothing_raised("Could not call store_override") do compile.store_override(override) end assert_instance_of(Array, overrides[:myref], "Overrides table is not a hash of arrays") assert_equal(override, overrides[:myref][0], "Did not store override in appropriately named array") # And when the resource already exists. resource = mock 'resource' resources = compile.instance_variable_get("@resource_table") resources[:resref] = resource override = mock 'override' resource.expects(:merge).with(override) override.expects(:override=).with(true) override.expects(:ref).returns(:resref) assert_nothing_raised("Could not call store_override when the resource already exists.") do compile.store_override(override) end end def test_resource_overrides compile = mkcompile overrides = compile.instance_variable_get("@resource_overrides") overrides[:test] = :yay resource = mock 'resource' resource.expects(:ref).returns(:test) assert_equal(:yay, compile.resource_overrides(resource), "Did not return overrides from table") end def test_fail_on_unevaluated_resource_collections compile = mkcompile collections = compile.instance_variable_get("@collections") # Make sure we're fine when the list is empty assert_nothing_raised("Failed when no collections were present") do compile.send :fail_on_unevaluated_resource_collections end # And that we're fine when we've got collections but with no resources collections << mock('coll') collections[0].expects(:resources).returns(nil) assert_nothing_raised("Failed when no resource collections were present") do compile.send :fail_on_unevaluated_resource_collections end # But that we do fail when we've got resource collections left. collections.clear # return both an array and a string, because that's tested internally collections << mock('coll returns one') collections[0].expects(:resources).returns(:something) collections << mock('coll returns many') collections[1].expects(:resources).returns([:one, :two]) assert_raise(Puppet::ParseError, "Did not fail on unevaluated resource collections") do compile.send :fail_on_unevaluated_resource_collections end end def test_fail_on_unevaluated_overrides compile = mkcompile overrides = compile.instance_variable_get("@resource_overrides") # Make sure we're fine when the list is empty assert_nothing_raised("Failed when no collections were present") do compile.send :fail_on_unevaluated_overrides end # But that we fail if there are any overrides left in the table. overrides[:yay] = [] overrides[:foo] = [] overrides[:bar] = [mock("override")] overrides[:bar][0].expects(:ref).returns("yay") assert_raise(Puppet::ParseError, "Failed to fail when overrides remain") do compile.send :fail_on_unevaluated_overrides end end def test_find_resource compile = mkcompile resources = compile.instance_variable_get("@resource_table") assert_nothing_raised("Could not call findresource when the resource table was empty") do assert_nil(compile.findresource("yay", "foo"), "Returned a non-existent resource") assert_nil(compile.findresource("yay[foo]"), "Returned a non-existent resource") end resources["Foo[bar]"] = :yay assert_nothing_raised("Could not call findresource when the resource table was not empty") do assert_equal(:yay, compile.findresource("foo", "bar"), "Returned a non-existent resource") assert_equal(:yay, compile.findresource("Foo[bar]"), "Returned a non-existent resource") end end # #620 - Nodes and classes should conflict, else classes don't get evaluated def test_nodes_and_classes_name_conflict # Test node then class compile = mkcompile node = stub :nodescope? => true klass = stub :nodescope? => false compile.class_set("one", node) assert_raise(Puppet::ParseError, "Did not fail when replacing node with class") do compile.class_set("one", klass) end # and class then node compile = mkcompile node = stub :nodescope? => true klass = stub :nodescope? => false compile.class_set("two", klass) assert_raise(Puppet::ParseError, "Did not fail when replacing node with class") do compile.class_set("two", node) end end end diff --git a/test/lib/puppettest/parsertesting.rb b/test/lib/puppettest/parsertesting.rb index c71508803..eef0cd8bc 100644 --- a/test/lib/puppettest/parsertesting.rb +++ b/test/lib/puppettest/parsertesting.rb @@ -1,408 +1,408 @@ require 'puppettest' require 'puppet/rails' module PuppetTest::ParserTesting include PuppetTest AST = Puppet::Parser::AST Compile = Puppet::Parser::Compile # A fake class that we can use for testing evaluation. class FakeAST attr_writer :evaluate def evaluated? defined? @evaluated and @evaluated end def evaluate(*args) @evaluated = true return @evaluate end def initialize(val = nil) if val @evaluate = val end end def reset @evaluated = nil end def safeevaluate(*args) evaluate() end end def astarray(*args) AST::ASTArray.new( :children => args ) end - def mkconfig(parser = nil) + def mkcompile(parser = nil) require 'puppet/network/handler/node' parser ||= mkparser node = mknode return Compile.new(node, parser) end def mknode(name = nil) require 'puppet/node' name ||= "nodename" Puppet::Network::Handler.handler(:node) Puppet::Node.new(name) end def mkinterp(args = {}) args[:Code] ||= "" unless args.include?(:Manifest) args[:Local] ||= true Puppet::Parser::Interpreter.new(args) end def mkparser Puppet::Parser::Parser.new() end def mkscope(hash = {}) hash[:parser] ||= mkparser - config ||= mkconfig(hash[:parser]) - config.topscope.source = (hash[:parser].findclass("", "") || hash[:parser].newclass("")) + compile ||= mkcompile(hash[:parser]) + compile.topscope.source = (hash[:parser].findclass("", "") || hash[:parser].newclass("")) - unless config.topscope.source + unless compile.topscope.source raise "Could not find source for scope" end # Make the 'main' stuff - config.send(:evaluate_main) - config.topscope + compile.send(:evaluate_main) + compile.topscope end def classobj(name, hash = {}) hash[:file] ||= __FILE__ hash[:line] ||= __LINE__ hash[:type] ||= name AST::HostClass.new(hash) end def tagobj(*names) args = {} newnames = names.collect do |name| if name.is_a? AST name else nameobj(name) end end args[:type] = astarray(*newnames) assert_nothing_raised("Could not create tag %s" % names.inspect) { return AST::Tag.new(args) } end def resourcedef(type, title, params) unless title.is_a?(AST) title = stringobj(title) end assert_nothing_raised("Could not create %s %s" % [type, title]) { return AST::Resource.new( :file => __FILE__, :line => __LINE__, :title => title, :type => type, :params => resourceinst(params) ) } end def virt_resourcedef(*args) res = resourcedef(*args) res.virtual = true res end def resourceoverride(type, title, params) assert_nothing_raised("Could not create %s %s" % [type, name]) { return AST::ResourceOverride.new( :file => __FILE__, :line => __LINE__, :object => resourceref(type, title), :type => type, :params => resourceinst(params) ) } end def resourceref(type, title) assert_nothing_raised("Could not create %s %s" % [type, title]) { return AST::ResourceReference.new( :file => __FILE__, :line => __LINE__, :type => type, :title => stringobj(title) ) } end def fileobj(path, hash = {"owner" => "root"}) assert_nothing_raised("Could not create file %s" % path) { return resourcedef("file", path, hash) } end def nameobj(name) assert_nothing_raised("Could not create name %s" % name) { return AST::Name.new( :file => tempfile(), :line => rand(100), :value => name ) } end def typeobj(name) assert_nothing_raised("Could not create type %s" % name) { return AST::Type.new( :file => tempfile(), :line => rand(100), :value => name ) } end def nodedef(name) assert_nothing_raised("Could not create node %s" % name) { return AST::NodeDef.new( :file => tempfile(), :line => rand(100), :names => nameobj(name), :code => AST::ASTArray.new( :children => [ varobj("%svar" % name, "%svalue" % name), fileobj("/%s" % name) ] ) ) } end def resourceinst(hash) assert_nothing_raised("Could not create resource instance") { params = hash.collect { |param, value| resourceparam(param, value) } return AST::ResourceInstance.new( :file => tempfile(), :line => rand(100), :children => params ) } end def resourceparam(param, value) # Allow them to pass non-strings in if value.is_a?(String) value = stringobj(value) end assert_nothing_raised("Could not create param %s" % param) { return AST::ResourceParam.new( :file => tempfile(), :line => rand(100), :param => param, :value => value ) } end def stringobj(value) AST::String.new( :file => tempfile(), :line => rand(100), :value => value ) end def varobj(name, value) unless value.is_a? AST value = stringobj(value) end assert_nothing_raised("Could not create %s code" % name) { return AST::VarDef.new( :file => tempfile(), :line => rand(100), :name => nameobj(name), :value => value ) } end def varref(name) assert_nothing_raised("Could not create %s variable" % name) { return AST::Variable.new( :file => __FILE__, :line => __LINE__, :value => name ) } end def argobj(name, value) assert_nothing_raised("Could not create %s compargument" % name) { return AST::CompArgument.new( :children => [nameobj(name), stringobj(value)] ) } end def defaultobj(type, params) pary = [] params.each { |p,v| pary << AST::ResourceParam.new( :file => __FILE__, :line => __LINE__, :param => p, :value => stringobj(v) ) } past = AST::ASTArray.new( :file => __FILE__, :line => __LINE__, :children => pary ) assert_nothing_raised("Could not create defaults for %s" % type) { return AST::ResourceDefaults.new( :file => __FILE__, :line => __LINE__, :type => type, :params => past ) } end def taggedobj(name, ftype = :statement) functionobj("tagged", name, ftype) end def functionobj(function, name, ftype = :statement) func = nil assert_nothing_raised do func = Puppet::Parser::AST::Function.new( :name => function, :ftype => ftype, :arguments => AST::ASTArray.new( :children => [nameobj(name)] ) ) end return func end # This assumes no nodes def assert_creates(manifest, *files) interp = nil assert_nothing_raised { interp = Puppet::Parser::Interpreter.new( :Manifest => manifest, :UseNodes => false ) } config = nil assert_nothing_raised { config = interp.compile(mknode) } comp = nil assert_nothing_raised { comp = config.extract.to_type } assert_apply(comp) files.each do |file| assert(FileTest.exists?(file), "Did not create %s" % file) end end def mk_transobject(file = "/etc/passwd") obj = nil assert_nothing_raised { obj = Puppet::TransObject.new("file", file) obj["owner"] = "root" obj["mode"] = "644" } return obj end def mk_transbucket(*resources) bucket = nil assert_nothing_raised { bucket = Puppet::TransBucket.new bucket.name = "yayname" bucket.type = "yaytype" } resources.each { |o| bucket << o } return bucket end # Make a tree of resources, yielding if desired def mk_transtree(depth = 4, width = 2) top = nil assert_nothing_raised { top = Puppet::TransBucket.new top.name = "top" top.type = "bucket" } bucket = top file = tempfile() depth.times do |i| resources = [] width.times do |j| path = tempfile + i.to_s obj = Puppet::TransObject.new("file", path) obj["owner"] = "root" obj["mode"] = "644" # Yield, if they want if block_given? yield(obj, i, j) end resources << obj end newbucket = mk_transbucket(*resources) bucket.push newbucket bucket = newbucket end return top end # Take a list of AST resources, evaluate them, and return the results def assert_evaluate(children) top = nil assert_nothing_raised("Could not create top object") { top = AST::ASTArray.new( :children => children ) } trans = nil scope = nil assert_nothing_raised { scope = Puppet::Parser::Scope.new() trans = scope.evaluate(:ast => top) } return trans end end diff --git a/test/network/client/client.rb b/test/network/client/client.rb index 3f540d10f..93c63d637 100755 --- a/test/network/client/client.rb +++ b/test/network/client/client.rb @@ -1,256 +1,259 @@ #!/usr/bin/env ruby $:.unshift("../../lib") if __FILE__ =~ /\.rb$/ require 'puppettest' require 'mocha' require 'puppet/network/client' class TestClient < Test::Unit::TestCase include PuppetTest::ServerTest class FakeClient < Puppet::Network::Client @drivername = :Test end class FakeDriver end # a single run through of connect, auth, etc. def disabled_test_sslInitWithAutosigningLocalServer # autosign everything, for simplicity Puppet[:autosign] = true # create a server to which to connect mkserver() # create our client client = nil assert_nothing_raised { client = Puppet::Network::Client.master.new( :Server => "localhost", :Port => @@port ) } # get our certs assert_nothing_raised { client.initcerts } # make sure all of our cert files exist certfile = File.join(Puppet[:certdir], [client.fqdn, "pem"].join(".")) keyfile = File.join(Puppet[:privatekeydir], [client.fqdn, "pem"].join(".")) publickeyfile = File.join(Puppet[:publickeydir], [client.fqdn, "pem"].join(".")) assert(File.exists?(keyfile)) assert(File.exists?(certfile)) assert(File.exists?(publickeyfile)) # verify we can retrieve the configuration assert_nothing_raised("Client could not retrieve configuration") { client.getconfig } # and apply it assert_nothing_raised("Client could not apply configuration") { client.apply } # and verify that it did what it was supposed to assert(FileTest.exists?(@createdfile), "Applied file does not exist") end # here we create two servers; we def disabled_test_failureWithUntrustedCerts Puppet[:autosign] = true # create a pair of clients with no certs nonemaster = nil assert_nothing_raised { nonemaster = Puppet::Network::Client.master.new( :Server => "localhost", :Port => @@port ) } nonebucket = nil assert_nothing_raised { nonebucket = Puppet::Network::Client.dipper.new( :Server => "localhost", :Port => @@port ) } # create a ca so we can create a set of certs # make a new ssldir for it ca = nil assert_nothing_raised { ca = Puppet::Network::Client.ca.new( :CA => true, :Local => true ) ca.requestcert } # initialize our clients with this set of certs certmaster = nil assert_nothing_raised { certmaster = Puppet::Network::Client.master.new( :Server => "localhost", :Port => @@port ) } certbucket = nil assert_nothing_raised { certbucket = Puppet::Network::Client.dipper.new( :Server => "localhost", :Port => @@port ) } # Create a new ssl root. confdir = tempfile() Puppet[:ssldir] = confdir Puppet.config.mkdir(:ssldir) Puppet.config.clearused Puppet.config.use(:ssl, :ca) mkserver # now verify that our client cannot do non-cert operations # because its certs are signed by a different CA assert_raise(Puppet::Error, "Client was allowed to call getconfig with no certs") { nonemaster.getconfig } assert_raise(Puppet::Error, "Client was allowed to call getconfig with untrusted certs") { certmaster.getconfig } assert_raise(Puppet::Network::XMLRPCClientError, "Client was allowed to call backup with no certs") { nonebucket.backup("/etc/passwd") } assert_raise(Puppet::Network::XMLRPCClientError, "Client was allowed to call backup with untrusted certs") { certbucket.backup("/etc/passwd") } end def test_classfile manifest = tempfile() File.open(manifest, "w") do |file| file.puts "class yaytest {}\n class bootest {}\n include yaytest, bootest" end master = client = nil assert_nothing_raised() { master = Puppet::Network::Handler.master.new( :Manifest => manifest, :UseNodes => false, :Local => false ) } assert_nothing_raised() { client = Puppet::Network::Client.master.new( :Master => master ) } # Fake that it's local, so it creates the class file client.local = false - client.expects(:setclasses).with(%w{yaytest bootest}) + # We can't guarantee class ordering + client.expects(:setclasses).with do |array| + array.length == 2 and array.include?("yaytest") and array.include?("bootest") + end assert_nothing_raised { client.getconfig } end def test_client_loading # Make sure we don't get a failure but that we also get nothing back assert_nothing_raised do assert_nil(Puppet::Network::Client.client(:fake), "Got something back from a missing client") assert_nil(Puppet::Network::Client.fake, "Got something back from missing client method") end # Make a fake client dir = tempfile() libdir = File.join([dir, %w{puppet network client}].flatten) FileUtils.mkdir_p(libdir) file = File.join(libdir, "faker.rb") File.open(file, "w") do |f| f.puts %{class Puppet::Network::Client class Faker < Client end end } end $: << dir cleanup { $:.delete(dir) if $:.include?(dir) } client = nil assert_nothing_raised do client = Puppet::Network::Client.client(:faker) end assert(client, "did not load client") assert_nothing_raised do assert_equal(client, Puppet::Network::Client.faker, "Did not get client back from client method") end # Now make sure the client behaves correctly assert_equal(:Faker, client.name, "name was not calculated correctly") end # Make sure we get a client class for each handler type. def test_loading_all_clients %w{ca dipper file master report resource runner status}.each do |name| client = nil assert_nothing_raised do client = Puppet::Network::Client.client(name) end assert(client, "did not get client for %s" % name) [:name, :handler, :drivername].each do |thing| assert(client.send(thing), "did not get %s for %s" % [thing, name]) end end end # Make sure that reading the cert in also sets up the cert stuff for the driver def test_read_cert Puppet::Util::SUIDManager.stubs(:asuser).yields ca = Puppet::Network::Handler.ca.new caclient = Puppet::Network::Client.ca.new :CA => ca caclient.request_cert # First make sure it doesn't get called when the driver doesn't support :cert_setup client = FakeClient.new :Test => FakeDriver.new driver = client.driver assert_nothing_raised("Could not read cert") do client.read_cert end # And then that it does when the driver supports it client = FakeClient.new :Test => FakeDriver.new driver = client.driver driver.meta_def(:cert_setup) { |c| } driver.expects(:cert_setup).with(client) assert_nothing_raised("Could not read cert") do client.read_cert end end end # $Id$ diff --git a/test/rails/ast.rb b/test/rails/ast.rb index b205aa0d5..fb6374401 100755 --- a/test/rails/ast.rb +++ b/test/rails/ast.rb @@ -1,73 +1,74 @@ #!/usr/bin/env ruby $:.unshift("../lib").unshift("../../lib") if __FILE__ =~ /\.rb$/ require 'puppettest' require 'puppet/rails' require 'puppet/parser/parser' require 'puppettest/resourcetesting' require 'puppettest/parsertesting' require 'puppettest/railstesting' require 'puppettest/support/collection' class TestRailsAST < PuppetTest::TestCase confine "Missing rails" => Puppet.features.rails? include PuppetTest::RailsTesting include PuppetTest::ParserTesting include PuppetTest::ResourceTesting include PuppetTest::Support::Collection def test_exported_collexp railsinit Puppet[:storeconfigs] = true - @interp, @scope, @source = mkclassframing + + @scope = mkscope # make a rails resource railsresource "file", "/tmp/testing", :owner => "root", :group => "bin", :mode => "644" run_collection_queries(:exported) do |string, result, query| code = nil str = nil # We don't support more than one search criteria at the moment. retval = nil bad = false # Figure out if the search is for anything rails will ignore if string =~ /\band\b|\bor\b/ bad = true else bad = false end # And if it is, make sure we throw an error. if bad assert_raise(Puppet::ParseError, "Evaluated '#{string}'") do str, code = query.evaluate :scope => @scope end next else assert_nothing_raised("Could not evaluate '#{string}'") do str, code = query.evaluate :scope => @scope end end assert_nothing_raised("Could not find resource") do retval = Puppet::Rails::Resource.find(:all, :include => {:param_values => :param_name}, :conditions => str) end if result assert_equal(1, retval.length, "Did not find resource with '#{string}'") res = retval.shift assert_equal("file", res.restype) assert_equal("/tmp/testing", res.title) else assert_equal(0, retval.length, "found a resource with '#{string}'") end end end end # $Id$ diff --git a/test/rails/collection.rb b/test/rails/collection.rb index 31aa02928..56f71e635 100755 --- a/test/rails/collection.rb +++ b/test/rails/collection.rb @@ -1,239 +1,241 @@ #!/usr/bin/env ruby $:.unshift("../lib").unshift("../../lib") if __FILE__ =~ /\.rb$/ require 'puppet' require 'puppet/rails' require 'puppettest' require 'puppettest/railstesting' require 'puppettest/resourcetesting' # A separate class for testing rails integration class TestRailsCollection < PuppetTest::TestCase confine "Missing rails support" => Puppet.features.rails? include PuppetTest include PuppetTest::ParserTesting include PuppetTest::ResourceTesting include PuppetTest::RailsTesting Parser = Puppet::Parser AST = Parser::AST def setup super Puppet[:trace] = false @scope = mkscope + @scope.compile.send(:evaluate_main) end def test_collect_exported railsinit # make an exported resource exported = mkresource(:type => "file", :title => "/tmp/exported", :exported => true, :params => {:owner => "root"}) - @scope.setresource exported + @scope.compile.store_resource @scope, exported assert(exported.exported?, "Object was not marked exported") assert(exported.virtual?, "Object was not marked virtual") # And a non-exported real = mkresource(:type => "file", :title => "/tmp/real", :params => {:owner => "root"}) - @scope.setresource real + @scope.compile.store_resource @scope, real # Now make a collector coll = nil assert_nothing_raised do coll = Puppet::Parser::Collector.new(@scope, "file", nil, nil, :exported) end # Set it in our scope @scope.compile.add_collection(coll) # Make sure it's in the collections assert_equal([coll], @scope.compile.collections) # And try to collect the virtual resources. ret = nil assert_nothing_raised do ret = coll.collect_exported end assert_equal([exported], ret) # Now make sure evaluate does the right thing. assert_nothing_raised do ret = coll.evaluate end # Make sure that the collection does not find the resource on the # next run. ret = nil assert_nothing_raised do ret = coll.collect_exported end assert(ret.empty?, "Exported resource was collected on the second run") # And make sure our exported object is no longer exported assert(! exported.virtual?, "Virtual object did not get realized") # But it should still be marked exported. assert(exported.exported?, "Resource got un-exported") # Now make a new collector of a different type and make sure it # finds nothing. assert_nothing_raised do coll = Puppet::Parser::Collector.new(@scope, "exec", nil, nil, :exported) end # Remark this as virtual exported.virtual = true assert_nothing_raised do ret = coll.evaluate end assert(! ret, "got resources back") # Now create a whole new scope and make sure we can actually retrieve # the resource from the database, not just from the scope. # First create a host object and store our resource in it. # Now collect our facts facts = {} Facter.each do |fact, value| facts[fact] = value end # Now try storing our crap # Remark this as exported exported.exported = true exported.scope.stubs(:tags).returns([]) node = mknode(facts["hostname"]) node.parameters = facts host = Puppet::Rails::Host.store(node, [exported]) assert(host, "did not get rails host") host.save # And make sure it's in there newres = host.resources.find_by_restype_and_title_and_exported("file", "/tmp/exported", true) assert(newres, "Did not find resource in db") assert(newres.exported?, "Resource was not exported") # Make a new set with a different node name node = mknode("other") - config = Puppet::Parser::Compile.new(node, mkparser) - config.topscope.source = mock("source") + compile = Puppet::Parser::Compile.new(node, mkparser) + compile.send(:evaluate_main) + compile.topscope.source = mock("source") # It's important that it's a different name, since same-name resources are ignored. - assert_equal("other", config.node.name, "Did not get correct node name") + assert_equal("other", compile.node.name, "Did not get correct node name") # Now make a collector coll = nil assert_nothing_raised do - coll = Puppet::Parser::Collector.new(config.topscope, "file", nil, nil, :exported) + coll = Puppet::Parser::Collector.new(compile.topscope, "file", nil, nil, :exported) end # And try to collect the virtual resources. ret = nil assert_nothing_raised("Could not collect exported resources") do ret = coll.collect_exported end assert_equal(["/tmp/exported"], ret.collect { |f| f.title }, "Did not find resource in collction") # Make sure we can evaluate the same collection multiple times and # that later collections do nothing assert_nothing_raised("Collection found same resource twice") do ret = coll.evaluate end end def test_collection_conflicts railsinit # First make a railshost we can conflict with host = Puppet::Rails::Host.new(:name => "myhost") host.resources.build(:title => "/tmp/conflicttest", :restype => "file", :exported => true) host.save # Now make a normal resource normal = mkresource(:type => "file", :title => "/tmp/conflicttest", :params => {:owner => "root"}) - @scope.setresource normal + @scope.compile.store_resource @scope, normal # Now make a collector coll = nil assert_nothing_raised do coll = Puppet::Parser::Collector.new(@scope, "file", nil, nil, :exported) end # And try to collect the virtual resources. assert_raise(Puppet::ParseError) do ret = coll.collect_exported end end # Make sure we do not collect resources from the host we're on def test_no_resources_from_me railsinit # Make our configuration host = Puppet::Rails::Host.new(:name => @scope.host) host.resources.build(:title => "/tmp/hosttest", :restype => "file", :exported => true) host.save # Now make a collector coll = nil assert_nothing_raised do coll = Puppet::Parser::Collector.new(@scope, "file", nil, nil, :exported) end # And make sure we get nada back ret = nil assert_nothing_raised do ret = coll.collect_exported end assert(ret.empty?, "Found exports from our own host") end # #731 -- we're collecting all resources, not just exported resources. def test_only_collecting_exported_resources railsinit # Make our configuration host = Puppet::Rails::Host.new(:name => "myhost") host.resources.build(:title => "/tmp/exporttest1", :restype => "file", :exported => true) host.resources.build(:title => "/tmp/exporttest2", :restype => "file", :exported => false) host.save # Now make a collector coll = nil assert_nothing_raised do coll = Puppet::Parser::Collector.new(@scope, "file", nil, nil, :exported) end # And make sure we get nada back ret = nil assert_nothing_raised do ret = coll.collect_exported end names = ret.collect { |res| res.title } assert_equal(%w{/tmp/exporttest1}, names, "Collected incorrect resource list") end end # $Id$ diff --git a/test/rails/configuration.rb b/test/rails/configuration.rb index 31d1cf779..752ea5375 100755 --- a/test/rails/configuration.rb +++ b/test/rails/configuration.rb @@ -1,82 +1,82 @@ #!/usr/bin/env ruby $:.unshift("../lib").unshift("../../lib") if __FILE__ =~ /\.rb$/ require 'puppettest' require 'puppet/parser/parser' require 'puppet/network/client' require 'puppet/rails' require 'puppettest/resourcetesting' require 'puppettest/parsertesting' require 'puppettest/servertest' require 'puppettest/railstesting' class ConfigurationRailsTests < PuppetTest::TestCase include PuppetTest include PuppetTest::ServerTest include PuppetTest::ParserTesting include PuppetTest::ResourceTesting include PuppetTest::RailsTesting AST = Puppet::Parser::AST confine "No rails support" => Puppet.features.rails? # We need to make sure finished objects are stored in the db. def test_finish_before_store railsinit - config = mkconfig - config.ast_nodes = true - parser = config.parser + compile = mkcompile + compile.ast_nodes = true + parser = compile.parser - node = parser.newnode [config.node.name], :code => AST::ASTArray.new(:children => [ + node = parser.newnode [compile.node.name], :code => AST::ASTArray.new(:children => [ resourcedef("file", "/tmp/yay", :group => "root"), defaultobj("file", :owner => "root") ]) # Now do the rails crap Puppet[:storeconfigs] = true Puppet::Rails::Host.expects(:store).with do |node, resources| if res = resources.find { |r| r.type == "file" and r.title == "/tmp/yay" } assert_equal("root", res["owner"], "Did not set default on resource") true else raise "Resource was not passed to store()" end end - config.compile + compile.compile end def test_hoststorage assert_nothing_raised { Puppet[:storeconfigs] = true } file = tempfile() File.open(file, "w") { |f| f.puts "file { \"/etc\": owner => root }" } interp = nil assert_nothing_raised { interp = Puppet::Parser::Interpreter.new( :Manifest => file, :UseNodes => false, :ForkSave => false ) } facts = {} Facter.each { |fact, val| facts[fact] = val } node = mknode(facts["hostname"]) node.parameters = facts objects = nil assert_nothing_raised { objects = interp.compile(node) } obj = Puppet::Rails::Host.find_by_name(node.name) assert(obj, "Could not find host object") end end diff --git a/test/rails/host.rb b/test/rails/host.rb index 67095a18a..5ac2f763e 100755 --- a/test/rails/host.rb +++ b/test/rails/host.rb @@ -1,192 +1,192 @@ #!/usr/bin/env ruby $:.unshift("../lib").unshift("../../lib") if __FILE__ =~ /\.rb$/ require 'puppet' require 'puppet/rails' require 'puppet/parser/interpreter' require 'puppet/parser/parser' require 'puppet/network/client' require 'puppettest' require 'puppettest/parsertesting' require 'puppettest/resourcetesting' require 'puppettest/railstesting' class TestRailsHost < PuppetTest::TestCase confine "Missing ActiveRecord" => Puppet.features.rails? include PuppetTest::ParserTesting include PuppetTest::ResourceTesting include PuppetTest::RailsTesting def setup super railsinit if Puppet.features.rails? end def teardown railsteardown if Puppet.features.rails? super end def test_includerails assert_nothing_raised { require 'puppet/rails' } end def test_store - @interp, @scope, @source = mkclassframing + @scope = mkscope # First make some objects resources = [] 4.times { |i| # Make a file resources << mkresource(:type => "file", :title => "/tmp/file#{i.to_s}", :params => {:owner => "user#{i}"}) # And an exec, so we're checking multiple types resources << mkresource(:type => "exec", :title => "/bin/echo file#{i.to_s}", :params => {:user => "user#{i}"}) } # Now collect our facts facts = {"hostname" => Facter.value(:hostname), "test1" => "funtest", "ipaddress" => Facter.value(:ipaddress)} # Now try storing our crap host = nil node = mknode(facts["hostname"]) node.parameters = facts assert_nothing_raised { host = Puppet::Rails::Host.store(node, resources) } assert(host, "Did not create host") host = nil assert_nothing_raised { host = Puppet::Rails::Host.find_by_name(facts["hostname"]) } assert(host, "Could not find host object") assert(host.resources, "No objects on host") facts.each do |fact, value| assert_equal(value, host.fact(fact)[0].value, "fact %s is wrong" % fact) end assert_equal(facts["ipaddress"], host.ip, "IP did not get set") count = 0 host.resources.each do |resource| assert_equal(host, resource.host) count += 1 i = nil if resource[:title] =~ /file([0-9]+)/ i = $1 else raise "Got weird resource %s" % resource.inspect end assert(resource[:restype] != "", "Did not get a type from the resource") case resource["restype"] when "file": assert_equal("user#{i}", resource.parameter("owner"), "got no owner for %s" % resource.ref) when "exec": assert_equal("user#{i}", resource.parameter("user"), "got no user for %s" % resource.ref) else raise "Unknown type %s" % resource[:restype].inspect end end assert_equal(8, count, "Did not get enough resources") # Now remove a couple of resources resources.reject! { |r| r.title =~ /file3/ } # Change a few resources resources.find_all { |r| r.title =~ /file2/ }.each do |r| r.send(:set_parameter, "loglevel", "notice") end # And add a new resource resources << mkresource(:type => "file", :title => "/tmp/file_added", :params => {:owner => "user_added"}) # And change some facts facts["test2"] = "yaytest" facts["test3"] = "funtest" facts["test1"] = "changedfact" facts.delete("ipaddress") host = nil node = mknode(facts["hostname"]) node.parameters = facts assert_nothing_raised { host = Puppet::Rails::Host.store(node, resources) } # Make sure it sets the last_compile time assert_nothing_raised do assert_instance_of(Time, host.last_compile, "did not set last_compile") end assert_equal(0, host.fact('ipaddress').size, "removed fact was not deleted") facts.each do |fact, value| assert_equal(value, host.fact(fact)[0].value, "fact %s is wrong" % fact) end # And check the changes we made. assert(! host.resources.find(:all).detect { |r| r.title =~ /file3/ }, "Removed resources are still present") res = host.resources.find_by_title("/tmp/file_added") assert(res, "New resource was not added") assert_equal("user_added", res.parameter("owner"), "user info was not stored") host.resources.find(:all, :conditions => [ "title like ?", "%file2%"]).each do |r| assert_equal("notice", r.parameter("loglevel"), "loglevel was not added") end end def test_freshness_connect_update Puppet::Rails.init Puppet[:storeconfigs] = true # this is the default server setup master = Puppet::Network::Handler.configuration.new( :Code => "", :UseNodes => true, :Local => true ) # Create a host Puppet::Rails::Host.new(:name => "test", :ip => "192.168.0.3").save assert_nothing_raised("Failed to update last_connect for unknown host") do master.version("created",'192.168.0.1') end # Make sure it created the host created = Puppet::Rails::Host.find_by_name("created") assert(created, "Freshness did not create host") assert(created.last_freshcheck, "Did not set last_freshcheck on created host") # Now check on the existing host assert_nothing_raised("Failed to update last_connect for unknown host") do master.version("test",'192.168.0.2') end # Recreate it, so we're not using the cached object. host = Puppet::Rails::Host.find_by_name("test") # Make sure it created the host assert(host.last_freshcheck, "Did not set last_freshcheck on existing host") end end # $Id$ diff --git a/test/rails/railsresource.rb b/test/rails/railsresource.rb index b8e5450b3..ca582b8b0 100755 --- a/test/rails/railsresource.rb +++ b/test/rails/railsresource.rb @@ -1,249 +1,251 @@ #!/usr/bin/env ruby $:.unshift("../lib").unshift("../../lib") if __FILE__ =~ /\.rb$/ require 'puppet' require 'puppet/rails' require 'puppettest' require 'puppettest/railstesting' require 'puppettest/resourcetesting' +require 'puppettest/parsertesting' # Don't do any tests w/out this class if Puppet.features.rails? class TestRailsResource < Test::Unit::TestCase include PuppetTest::RailsTesting include PuppetTest::ResourceTesting + include PuppetTest::ParserTesting def setup super railsinit end def teardown railsteardown super end def mktest_resource # We need a host for resources host = Puppet::Rails::Host.new(:name => "myhost") # Now build a resource resource = host.resources.create( :title => "/tmp/to_resource", :restype => "file", :exported => true) # Now add some params params.each do |param, value| pn = Puppet::Rails::ParamName.find_or_create_by_name(param) pv = resource.param_values.create(:value => value, :param_name => pn) end host.save return resource end def params {"owner" => "root", "mode" => "644"} end # Create a resource param from a rails parameter def test_to_resource resource = mktest_resource # We need a scope - interp, scope, source = mkclassframing + scope = mkscope # Find the new resource and include all it's parameters. resource = Puppet::Rails::Resource.find_by_id(resource.id) # Now, try to convert our resource to a real resource res = nil assert_nothing_raised do res = resource.to_resource(scope) end assert_instance_of(Puppet::Parser::Resource, res) assert_equal("root", res[:owner]) assert_equal("644", res[:mode]) assert_equal("/tmp/to_resource", res.title) - assert_equal(source, res.source) + assert_equal(scope.source, res.source) end def test_parameters resource = mktest_resource setparams = nil assert_nothing_raised do setparams = resource.parameters.inject({}) { |h, a| h[a[0]] = a[1][0] h } end assert_equal(params, setparams, "Did not get the right answer from #parameters") end # Make sure we can retrieve individual parameters by name. def test_parameter resource = mktest_resource params.each do |p,v| assert_equal(v, resource.parameter(p), "%s is not correct" % p) end end end else $stderr.puts "Install Rails for Rails and Caching tests" end # A separate class for testing rails integration class TestExportedResources < PuppetTest::TestCase include PuppetTest include PuppetTest::ParserTesting include PuppetTest::ResourceTesting include PuppetTest::RailsTesting Parser = Puppet::Parser AST = Parser::AST Reference = Puppet::Parser::Resource::Reference def setup super Puppet[:trace] = false - @interp, @scope, @source = mkclassframing + @scope = mkscope end confine "Missing rails support" => Puppet.features.rails? # Compare a parser resource to a rails resource. def compare_resources(host, res, updating, options = {}) newobj = nil # If the resource is in the db, then use modify_rails, else use to_rails if newobj = Puppet::Rails::Resource.find_by_restype_and_title(res.type, res.title) assert_nothing_raised("Call to modify_rails failed") do res.modify_rails(newobj) end else assert_nothing_raised("Call to to_rails failed") do newobj = res.to_rails(host) end end assert_instance_of(Puppet::Rails::Resource, newobj) newobj.save if updating tail = "on update" else tail = "" end # Make sure we find our object and only our object count = 0 obj = nil Puppet::Rails::Resource.find(:all).each do |obj| assert_equal(newobj.id, obj.id, "A new resource was created instead of modifying an existing resource") count += 1 [:title, :restype, :line, :exported].each do |param| if param == :restype method = :type else method = param end assert_equal(res.send(method), obj[param], "attribute %s was not set correctly in rails %s" % [param, tail]) end end assert_equal(1, count, "Got too many resources %s" % tail) # Now make sure we can find it again assert_nothing_raised do obj = Puppet::Rails::Resource.find_by_restype_and_title( res.type, res.title, :include => :param_names ) end assert_instance_of(Puppet::Rails::Resource, obj) # Make sure we get the parameters back params = options[:params] || [obj.param_names.collect { |p| p.name }, res.to_hash.keys].flatten.collect { |n| n.to_s }.uniq params.each do |name| param = obj.param_names.find_by_name(name) if res[name] assert(param, "resource did not keep %s %s" % [name, tail]) else assert(! param, "resource did not delete %s %s" % [name, tail]) end if param values = param.param_values.collect { |pv| pv.value } should = res[param.name] should = [should] unless should.is_a?(Array) assert_equal(should, values, "%s was different %s" % [param.name, tail]) end end return obj end def test_to_rails railsteardown railsinit ref1 = Reference.new :type => "exec", :title => "one" ref2 = Reference.new :type => "exec", :title => "two" res = mkresource :type => "file", :title => "/tmp/testing", :source => @source, :scope => @scope, :params => {:owner => "root", :source => ["/tmp/A", "/tmp/B"], :mode => "755", :require => [ref1, ref2], :subscribe => ref1} res.line = 50 # We also need a Rails Host to store under host = Puppet::Rails::Host.new(:name => Facter.hostname) railsres = compare_resources(host, res, false, :params => %w{owner source mode}) # Now make sure our parameters did not change assert_instance_of(Array, res[:require], "Parameter array changed") res[:require].each do |ref| assert_instance_of(Reference, ref, "Resource reference changed") end assert_instance_of(Reference, res[:subscribe], "Resource reference changed") # And make sure that the rails resource actually has resource references params = railsres.parameters [params["subscribe"], params["require"]].flatten.each do |ref| assert_instance_of(Reference, ref, "Resource reference is no longer a reference") end # Now make some changes to our resource. We're removing the mode, # changing the source, and adding 'check'. res = mkresource :type => "file", :title => "/tmp/testing", :source => @source, :scope => @scope, :params => {:owner => "bin", :source => ["/tmp/A", "/tmp/C"], :check => "checksum", :require => [ref1, ref2], :subscribe => ref2} res.line = 75 res.exported = true railsres = compare_resources(host, res, true, :params => %w{owner source mode check}) # Again make sure our parameters did not change assert_instance_of(Array, res[:require], "Parameter array changed") res[:require].each do |ref| assert_instance_of(Reference, ref, "Resource reference changed") end # Again with the serialization checks params = railsres.parameters [params["subscribe"], params["require"]].flatten.each do |ref| assert_instance_of(Reference, ref, "Resource reference is no longer a reference") end end end # $Id$ diff --git a/test/tagging/tagging.rb b/test/tagging/tagging.rb deleted file mode 100755 index afab3faa4..000000000 --- a/test/tagging/tagging.rb +++ /dev/null @@ -1,170 +0,0 @@ -#!/usr/bin/env ruby - -$:.unshift("../lib").unshift("../../lib") if __FILE__ =~ /\.rb$/ - -require 'puppet' -require 'puppettest' -require 'puppettest/parsertesting' -require 'puppettest/resourcetesting' - -class TestTagging < Test::Unit::TestCase - include PuppetTest - include PuppetTest::ParserTesting - include PuppetTest::ResourceTesting - - # Make sure the scopes are getting the right tags - def test_scopetags - scope = nil - assert_nothing_raised { - scope = mkscope - scope.name = "yayness" - scope.type = "solaris" - } - - assert_nothing_raised { - assert_equal(%w{solaris}, scope.tags, "Incorrect scope tags") - } - end - - # Test deeper tags, where a scope gets all of its parent scopes' tags - def test_deepscopetags - scope = nil - assert_nothing_raised { - scope = mkscope - scope.name = "yayness" - scope.type = "solaris" - scope = scope.newscope - scope.name = "booness" - scope.type = "apache" - } - - assert_nothing_raised { - # Scopes put their own tags first - assert_equal(%w{apache solaris}, scope.tags, "Incorrect scope tags") - } - end - - # Verify that the tags make their way to the objects - def test_objecttags - scope = nil - assert_nothing_raised { - scope = mkscope - scope.name = "yayness" - scope.type = "solaris" - } - - resource = mkresource :type => "file", :title => "/tmp/testing", - :params => {:owner => "root"}, :file => "/yay", :line => 1, - :scope => scope - - assert_nothing_raised { - scope.setresource(resource) - } - - assert_nothing_raised { - assert_equal(%w{solaris file}, resource.tags, - "Incorrect tags") - } - end - - # Make sure that specifying tags results in only those objects getting - # run. - def test_tagspecs - a = tempfile() - b = tempfile() - - afile = Puppet.type(:file).create( - :path => a, - :ensure => :file - ) - afile.tag("a") - - bfile = Puppet.type(:file).create( - :path => b, - :ensure => :file - ) - bfile.tag(:b) - - # First, make sure they get created when no spec'ed tags - assert_events([:file_created,:file_created], afile, bfile) - assert(FileTest.exists?(a), "A did not get created") - assert(FileTest.exists?(b), "B did not get created") - File.unlink(a) - File.unlink(b) - - # Set the tags to a - assert_nothing_raised { - Puppet[:tags] = "a" - } - - assert_events([:file_created], afile, bfile) - assert(FileTest.exists?(a), "A did not get created") - assert(!FileTest.exists?(b), "B got created") - File.unlink(a) - - # Set the tags to b - assert_nothing_raised { - Puppet[:tags] = "b" - } - - assert_events([:file_created], afile, bfile) - assert(!FileTest.exists?(a), "A got created") - assert(FileTest.exists?(b), "B did not get created") - File.unlink(b) - - # Set the tags to something else - assert_nothing_raised { - Puppet[:tags] = "c" - } - - assert_events([], afile, bfile) - assert(!FileTest.exists?(a), "A got created") - assert(!FileTest.exists?(b), "B got created") - - # Now set both tags - assert_nothing_raised { - Puppet[:tags] = "b, a" - } - - assert_events([:file_created, :file_created], afile, bfile) - assert(FileTest.exists?(a), "A did not get created") - assert(FileTest.exists?(b), "B did not get created") - File.unlink(a) - - end - - def test_metaparamtag - path = tempfile() - - start = %w{some tags} - tags = %w{a list of tags} - - obj = nil - assert_nothing_raised do - obj = Puppet.type(:file).create( - :path => path, - :ensure => "file", - :tag => start - ) - end - - - assert(obj, "Did not make object") - - start.each do |tag| - assert(obj.tagged?(tag), "Object was not tagged with %s" % tag) - end - - tags.each do |tag| - assert_nothing_raised { - obj[:tag] = tag - } - end - - tags.each do |tag| - assert(obj.tagged?(tag), "Object was not tagged with %s" % tag) - end - end -end - -# $Id$