diff options
| author | Luke Kanies <luke@madstop.com> | 2007-08-20 13:28:40 -0500 |
|---|---|---|
| committer | Luke Kanies <luke@madstop.com> | 2007-08-20 13:28:40 -0500 |
| commit | 6467c21e15b8a28e627d1395f76fe8f42ee77d70 (patch) | |
| tree | c36f4e350074a028ba6cc9f8e4230284e880ab46 | |
| parent | a846ea900f9fa7a2baaa4fbd0742f080e7fd7a04 (diff) | |
The first pass where at least all of the snippet tests pass. I have unfortunately had to stop being so assiduous in my rewriting of tests, but I am in too much of a time crunch to do this "right". The basic structure is definitely in place, though, and from here it is a question of making the rest of the tests work and hopefully writing some sufficient new tests, rather than making the code itself work.
| -rw-r--r-- | lib/puppet/network/handler/configuration.rb | 7 | ||||
| -rw-r--r-- | lib/puppet/network/handler/master.rb | 192 | ||||
| -rw-r--r-- | lib/puppet/parser/ast/astarray.rb | 63 | ||||
| -rw-r--r-- | lib/puppet/parser/ast/collection.rb | 2 | ||||
| -rw-r--r-- | lib/puppet/parser/ast/hostclass.rb | 1 | ||||
| -rw-r--r-- | lib/puppet/parser/collector.rb | 11 | ||||
| -rw-r--r-- | lib/puppet/parser/configuration.rb | 70 | ||||
| -rw-r--r-- | lib/puppet/parser/functions.rb | 7 | ||||
| -rw-r--r-- | lib/puppet/parser/interpreter.rb | 3 | ||||
| -rw-r--r-- | lib/puppet/parser/resource.rb | 319 | ||||
| -rw-r--r-- | lib/puppet/parser/resource/reference.rb | 2 | ||||
| -rw-r--r-- | lib/puppet/parser/scope.rb | 75 | ||||
| -rwxr-xr-x | test/language/ast/component.rb | 12 | ||||
| -rwxr-xr-x | test/language/configuration.rb | 16 | ||||
| -rwxr-xr-x | test/language/interpreter.rb | 156 | ||||
| -rwxr-xr-x | test/language/parser.rb | 17 | ||||
| -rwxr-xr-x | test/language/resource.rb | 425 | ||||
| -rwxr-xr-x | test/language/scope.rb | 250 | ||||
| -rw-r--r-- | test/lib/puppettest/parsertesting.rb | 21 | ||||
| -rw-r--r-- | test/lib/puppettest/resourcetesting.rb | 46 | ||||
| -rwxr-xr-x | test/network/handler/master.rb | 74 |
21 files changed, 718 insertions, 1051 deletions
diff --git a/lib/puppet/network/handler/configuration.rb b/lib/puppet/network/handler/configuration.rb index c1c77a357..f1a20ee74 100644 --- a/lib/puppet/network/handler/configuration.rb +++ b/lib/puppet/network/handler/configuration.rb @@ -46,6 +46,8 @@ class Puppet::Network::Handler # immediately. Mostly, this is so we can create the interpreter # on-demand, which is easier for testing. @options = options + + set_server_facts end # Are we running locally, or are our clients networked? @@ -58,7 +60,7 @@ class Puppet::Network::Handler v = interpreter.configuration_version # If we can find the node, then store the fact that the node # has checked in. - if node = node_handler.details(client) + if client and node = node_handler.details(client) update_node_check(node) end @@ -95,6 +97,9 @@ class Puppet::Network::Handler begin config = interpreter.compile(node) rescue Puppet::Error => detail + if Puppet[:trace] + puts detail.backtrace + end Puppet.err detail raise XMLRPC::FaultException.new( 1, detail.to_s diff --git a/lib/puppet/network/handler/master.rb b/lib/puppet/network/handler/master.rb index e889c1ba8..0aa50a426 100644 --- a/lib/puppet/network/handler/master.rb +++ b/lib/puppet/network/handler/master.rb @@ -21,66 +21,9 @@ class Puppet::Network::Handler iface.add_method("int freshness()") } - # FIXME At some point, this should be autodocumenting. - def addfacts(facts) - # Add our server version to the fact list - facts["serverversion"] = Puppet.version.to_s - - # And then add the server name and IP - {"servername" => "fqdn", - "serverip" => "ipaddress" - }.each do |var, fact| - if obj = Facter[fact] - facts[var] = obj.value - else - Puppet.warning "Could not retrieve fact %s" % fact - end - end - - if facts["servername"].nil? - host = Facter.value(:hostname) - if domain = Facter.value(:domain) - facts["servername"] = [host, domain].join(".") - else - facts["servername"] = host - end - end - end - - # Manipulate the client name as appropriate. - def clientname(name, ip, facts) - # Always use the hostname from Facter. - client = facts["hostname"] - clientip = facts["ipaddress"] - if Puppet[:node_name] == 'cert' - if name - client = name - end - if ip - clientip = ip - end - end - - return client, clientip - end - # Tell a client whether there's a fresh config for it def freshness(client = nil, clientip = nil) - if Puppet.features.rails? and Puppet[:storeconfigs] - Puppet::Rails.connect - - host = Puppet::Rails::Host.find_or_create_by_name(client) - host.last_freshcheck = Time.now - if clientip and (! host.ip or host.ip == "" or host.ip == "NULL") - host.ip = clientip - end - host.save - end - if defined? @interpreter - return @interpreter.parsedate - else - return 0 - end + config_handler.version(client) end def initialize(hash = {}) @@ -121,104 +64,81 @@ class Puppet::Network::Handler args[:Classes] = hash[:Classes] end - @interpreter = Puppet::Parser::Interpreter.new(args) + @config_handler = Puppet::Network::Handler.handler(:configuration).new(args) end + # Call our various handlers; this handler is getting deprecated. def getconfig(facts, format = "marshal", client = nil, clientip = nil) - if @local - # we don't need to do anything, since we should already - # have raw objects - Puppet.debug "Our client is local" - else - Puppet.debug "Our client is remote" - - # XXX this should definitely be done in the protocol, somehow - case format - when "marshal": - Puppet.warning "You should upgrade your client. 'Marshal' will not be supported much longer." - begin - facts = Marshal::load(CGI.unescape(facts)) - rescue => detail - raise XMLRPC::FaultException.new( - 1, "Could not rebuild facts" - ) - end - when "yaml": - begin - facts = YAML.load(CGI.unescape(facts)) - rescue => detail - raise XMLRPC::FaultException.new( - 1, "Could not rebuild facts" - ) - end - else - raise XMLRPC::FaultException.new( - 1, "Unavailable config format %s" % format - ) - end - end - + facts = decode_facts(facts) client, clientip = clientname(client, clientip, facts) - # Add any server-side facts to our server. - addfacts(facts) + # Pass the facts to the fact handler + fact_handler.set(client, facts) - retobjects = nil + # And get the configuration from the config handler + return config_handler.configuration(client) + end - # This is hackish, but there's no "silence" option for benchmarks - # right now - if @local - #begin - retobjects = @interpreter.run(client, facts) - #rescue Puppet::Error => detail - # Puppet.err detail - # raise XMLRPC::FaultException.new( - # 1, detail.to_s - # ) - #rescue => detail - # Puppet.err detail.to_s - # return "" - #end + def local? + if defined? @local and @local + return true else - benchmark(:notice, "Compiled configuration for %s" % client) do - begin - retobjects = @interpreter.run(client, facts) - rescue Puppet::Error => detail - Puppet.err detail - raise XMLRPC::FaultException.new( - 1, detail.to_s - ) - rescue => detail - Puppet.err detail.to_s - return "" - end + return false + end + end + + private + + # Manipulate the client name as appropriate. + def clientname(name, ip, facts) + # Always use the hostname from Facter. + client = facts["hostname"] + clientip = facts["ipaddress"] + if Puppet[:node_name] == 'cert' + if name + client = name end + if ip + clientip = ip + end + end + + return client, clientip + end + + def config_handler + unless defined? @config_handler + @config_handler = Puppet::Network::Handler.handler(:config).new :local => local? end + @config_handler + end + # + def decode_facts(facts) if @local - return retobjects + # we don't need to do anything, since we should already + # have raw objects + Puppet.debug "Our client is local" else - str = nil - case format - when "marshal": - str = Marshal::dump(retobjects) - when "yaml": - str = retobjects.to_yaml(:UseBlock => true) - else + Puppet.debug "Our client is remote" + + begin + facts = YAML.load(CGI.unescape(facts)) + rescue => detail raise XMLRPC::FaultException.new( - 1, "Unavailable config format %s" % format + 1, "Could not rebuild facts" ) end - return CGI.escape(str) end + + return facts end - def local? - if defined? @local and @local - return true - else - return false + def fact_handler + unless defined? @fact_handler + @fact_handler = Puppet::Network::Handler.handler(:facts).new :local => local? end + @fact_handler end end end diff --git a/lib/puppet/parser/ast/astarray.rb b/lib/puppet/parser/ast/astarray.rb index a0bd5bf89..c0212f919 100644 --- a/lib/puppet/parser/ast/astarray.rb +++ b/lib/puppet/parser/ast/astarray.rb @@ -21,45 +21,38 @@ class Puppet::Parser::AST # We basically always operate declaratively, and when we # do we need to evaluate the settor-like statements first. This # is basically variable and type-default declarations. - if scope.declarative? - # This is such a stupid hack. I've no real idea how to make a - # "real" declarative language, so I hack it so it looks like - # one, yay. - settors = [] - others = [] + # This is such a stupid hack. I've no real idea how to make a + # "real" declarative language, so I hack it so it looks like + # one, yay. + settors = [] + others = [] - # Make a new array, so we don't have to deal with the details of - # flattening and such - items = [] - - # First clean out any AST::ASTArrays - @children.each { |child| - if child.instance_of?(AST::ASTArray) - child.each do |ac| - if ac.class.settor? - settors << ac - else - others << ac - end - end - else - if child.class.settor? - settors << child + # Make a new array, so we don't have to deal with the details of + # flattening and such + items = [] + + # First clean out any AST::ASTArrays + @children.each { |child| + if child.instance_of?(AST::ASTArray) + child.each do |ac| + if ac.class.settor? + settors << ac else - others << child + others << ac end end - } - rets = [settors, others].flatten.collect { |child| - child.safeevaluate(:scope => scope) - } - return rets.reject { |o| o.nil? } - else - # If we're not declarative, just do everything in order. - return @children.collect { |item| - item.safeevaluate(:scope => scope) - }.reject { |o| o.nil? } - end + else + if child.class.settor? + settors << child + else + others << child + end + end + } + rets = [settors, others].flatten.collect { |child| + child.safeevaluate(:scope => scope) + } + return rets.reject { |o| o.nil? } end def push(*ary) diff --git a/lib/puppet/parser/ast/collection.rb b/lib/puppet/parser/ast/collection.rb index c817b5c5e..7daf031cf 100644 --- a/lib/puppet/parser/ast/collection.rb +++ b/lib/puppet/parser/ast/collection.rb @@ -20,7 +20,7 @@ class Collection < AST::Branch newcoll = Puppet::Parser::Collector.new(scope, @type, str, code, self.form) - scope.newcollection(newcoll) + scope.configuration.add_collection(newcoll) newcoll end diff --git a/lib/puppet/parser/ast/hostclass.rb b/lib/puppet/parser/ast/hostclass.rb index d1ce370da..9b60c692f 100644 --- a/lib/puppet/parser/ast/hostclass.rb +++ b/lib/puppet/parser/ast/hostclass.rb @@ -27,7 +27,6 @@ class Puppet::Parser::AST # Verify that we haven't already been evaluated, and if we have been evaluated, # make sure that we match the class. if existing_scope = scope.class_scope(self) - raise "Fix this portion of the code -- check that the scopes match classes" #if existing_scope.source.object_id == self.object_id Puppet.debug "%s class already evaluated" % @type return nil diff --git a/lib/puppet/parser/collector.rb b/lib/puppet/parser/collector.rb index 6c49c6d57..0846c40ab 100644 --- a/lib/puppet/parser/collector.rb +++ b/lib/puppet/parser/collector.rb @@ -81,7 +81,7 @@ class Puppet::Parser::Collector # If there are no more resources to find, delete this from the list # of collections. if @resources.empty? - @scope.collections.delete(self) + @scope.configuration.delete_collection(self) end return result @@ -94,7 +94,7 @@ class Puppet::Parser::Collector else method = :virtual? end - scope.resources.find_all do |resource| + scope.configuration.resources.find_all do |resource| resource.type == @type and resource.send(method) and match?(resource) end end @@ -117,13 +117,6 @@ class Puppet::Parser::Collector return objects end end - -# if objects and ! objects.empty? -# objects.each { |r| r.virtual = false } -# return objects -# else -# return false -# end end def initialize(scope, type, equery, vquery, form) diff --git a/lib/puppet/parser/configuration.rb b/lib/puppet/parser/configuration.rb index 617d7d231..90812899a 100644 --- a/lib/puppet/parser/configuration.rb +++ b/lib/puppet/parser/configuration.rb @@ -60,7 +60,7 @@ class Puppet::Parser::Configuration evaluate_main() - evaluate_ast_nodes() + evaluate_ast_node() evaluate_classes() @@ -73,9 +73,32 @@ class Puppet::Parser::Configuration return extract() end - # Should the scopes behave declaratively? - def declarative? - true + # 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) + + @resource_graph.remove_vertex!(resource) if @resource_graph.vertex?(resource) + end + + # Evaluate each class in turn. If there are any classes we can't find, + # just tag the configuration and move on. + def evaluate_classes(classes = nil) + classes ||= node.classes + classes.each do |name| + if klass = @parser.findclass("", name) + # This will result in class_set getting called, which + # will in turn result in tags. Yay. + klass.safeevaluate(:scope => topscope) + else + Puppet.info "Could not find class %s for %s" % [name, node.name] + tag(name) + end + end end # Make sure we support the requested extraction format. @@ -119,9 +142,11 @@ class Puppet::Parser::Configuration # 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 = nil) + def newscope(parent, options = {}) parent ||= @topscope - scope = Puppet::Parser::Scope.new(:configuration => self) + options[:configuration] = self + options[:parser] ||= self.parser + scope = Puppet::Parser::Scope.new(options) @scope_graph.add_edge!(parent, scope) scope end @@ -141,6 +166,11 @@ class Puppet::Parser::Configuration @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 @@ -179,7 +209,7 @@ class Puppet::Parser::Configuration astnode = nil #nodes = @parser.nodes @node.names.each do |name| - break if astnode = @parser.nodes[name] + break if astnode = @parser.nodes[name.to_s.downcase] end unless astnode @@ -192,21 +222,6 @@ class Puppet::Parser::Configuration astnode.safeevaluate :scope => topscope end - # Evaluate each class in turn. If there are any classes we can't find, - # just tag the configuration and move on. - def evaluate_classes - node.classes.each do |name| - if klass = @parser.findclass("", name) - # This will result in class_set getting called, which - # will in turn result in tags. Yay. - klass.safeevaluate(:scope => topscope) - else - Puppet.info "Could not find class %s for %s" % [name, node.name] - tag(name) - end - end - 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 @@ -305,8 +320,13 @@ class Puppet::Parser::Configuration end # Then add the resources. - @resource_graph.adjacent(scope, :direction => :out).each do |vertex| - bucket.push vertex.to_trans + if @resource_graph.vertex?(scope) + @resource_graph.adjacent(scope, :direction => :out).each do |vertex| + # Some resources don't get translated, e.g., virtual resources. + if obj = vertex.to_trans + bucket.push obj + end + end end end @@ -396,7 +416,7 @@ class Puppet::Parser::Configuration @tags = [] # Create our initial scope, our scope graph, and add the initial scope to the graph. - @topscope = Puppet::Parser::Scope.new(:configuration => self, :type => "main", :name => "top") + @topscope = Puppet::Parser::Scope.new(:configuration => self, :type => "main", :name => "top", :parser => self.parser) # For maintaining scope relationships. @scope_graph = GRATR::Digraph.new diff --git a/lib/puppet/parser/functions.rb b/lib/puppet/parser/functions.rb index 946501154..ad58c7040 100644 --- a/lib/puppet/parser/functions.rb +++ b/lib/puppet/parser/functions.rb @@ -109,7 +109,8 @@ module Functions # Include the specified classes newfunction(:include, :doc => "Evaluate one or more classes.") do |vals| - klasses = evalclasses(*vals) + vals = [vals] unless vals.is_a?(Array) + klasses = configuration.evaluate_classes(vals) missing = vals.find_all do |klass| ! klasses.include?(klass) @@ -144,7 +145,7 @@ module Functions tells you whether the current container is tagged with the specified tags. The tags are ANDed, so that all of the specified tags must be included for the function to return true.") do |vals| - classlist = self.classlist + classlist = configuration.classlist retval = true vals.each do |val| @@ -234,7 +235,7 @@ module Functions vals = [vals] unless vals.is_a?(Array) coll.resources = vals - newcollection(coll) + configuration.add_collection(coll) end newfunction(:search, :doc => "Add another namespace for this class to search. diff --git a/lib/puppet/parser/interpreter.rb b/lib/puppet/parser/interpreter.rb index f0b9d0179..cf3027a5a 100644 --- a/lib/puppet/parser/interpreter.rb +++ b/lib/puppet/parser/interpreter.rb @@ -3,6 +3,7 @@ require 'timeout' require 'puppet/rails' require 'puppet/util/methodhelper' require 'puppet/parser/parser' +require 'puppet/parser/configuration' require 'puppet/parser/scope' # The interpreter is a very simple entry-point class that @@ -93,7 +94,7 @@ class Puppet::Parser::Interpreter def compile(node) parsefiles() - return Puppet::Parser::Configuration.new(node).compile + return Puppet::Parser::Configuration.new(node, @parser).compile end private diff --git a/lib/puppet/parser/resource.rb b/lib/puppet/parser/resource.rb index 371f56ec1..eace88645 100644 --- a/lib/puppet/parser/resource.rb +++ b/lib/puppet/parser/resource.rb @@ -10,9 +10,9 @@ class Puppet::Parser::Resource include Puppet::Util::Logging attr_accessor :source, :line, :file, :scope, :rails_id - attr_accessor :virtual, :override, :params, :translated + attr_accessor :virtual, :override, :translated - attr_reader :exported + attr_reader :exported, :evaluated, :params attr_writer :tags @@ -24,7 +24,7 @@ class Puppet::Parser::Resource end # Set up some boolean test methods - [:exported, :translated, :override].each do |method| + [:exported, :translated, :override, :virtual, :evaluated].each do |method| newmeth = (method.to_s + "?").intern define_method(newmeth) do self.send(method) @@ -43,47 +43,6 @@ class Puppet::Parser::Resource end end - # Add default values from our definition. - def adddefaults - defaults = scope.lookupdefaults(self.type) - - defaults.each do |name, param| - unless @params.include?(param.name) - self.debug "Adding default for %s" % param.name - - @params[param.name] = param - end - end - end - - # Add any metaparams defined in our scope. This actually adds any metaparams - # from any parent scope, and there's currently no way to turn that off. - def addmetaparams - Puppet::Type.eachmetaparam do |name| - next if self[name] - if val = scope.lookupvar(name.to_s, false) - unless val == :undefined - set Param.new(:name => name, :value => val, - :source => scope.source) - end - end - end - end - - # Add any overrides for this object. - def addoverrides - overrides = scope.configuration.resource_overrides(self) - raise "fix this test" - - overrides.each do |over| - self.merge(over) - end - - # Remove the overrides, so that the configuration knows there - # are none left. - overrides.clear - end - def builtin=(bool) @ref.builtin = bool end @@ -92,7 +51,7 @@ class Puppet::Parser::Resource def evaluate if klass = @ref.definedtype finish() - scope.deleteresource(self) + scope.configuration.delete_resource(self) return klass.evaluate(:scope => scope, :type => self.type, :title => self.title, @@ -110,6 +69,8 @@ class Puppet::Parser::Resource @evaluated = true end + # Mark this resource as both exported and virtual, + # or remove the exported mark. def exported=(value) if value @virtual = true @@ -119,63 +80,71 @@ class Puppet::Parser::Resource end end - def evaluated? - if defined? @evaluated and @evaluated - true - else - false - end - end - # Do any finishing work on this object, called before evaluation or # before storage/translation. def finish - addoverrides() - adddefaults() - addmetaparams() + add_overrides() + add_defaults() + add_metaparams() + validate() end def initialize(options) - options = symbolize_options(options) - - # Collect the options necessary to make the reference. - refopts = [:type, :title].inject({}) do |hash, param| - hash[param] = options[param] - options.delete(param) - hash + # Set all of the options we can. + options.each do |option, value| + if respond_to?(option.to_s + "=") + send(option.to_s + "=", value) + options.delete(option) + end end - @params = {} - tmpparams = nil - if tmpparams = options[:params] - options.delete(:params) + [:scope, :source].each do |attribute| + unless self.send(attribute) + raise ArgumentError, "Resources require a %s" % attribute + end end - # Now set the rest of the options. - set_options(options) - - @ref = Reference.new(refopts) + # Set up our reference. + if type = options[:type] and title = options[:title] + options.delete(:type) + options.delete(:title) + else + raise ArgumentError, "Resources require a type and title" + end - requiredopts(:scope, :source) + @ref = Reference.new(:type => type, :title => title, :scope => self.scope) - @ref.scope = self.scope + @params = {} - if tmpparams - tmpparams.each do |param| - # We use the method here, because it does type-checking. - set(param) + # Define all of the parameters + if params = options[:params] + options.delete(:params) + params.each do |param| + set_parameter(param) end end + + # Throw an exception if we've got any arguments left to set. + unless options.empty? + raise ArgumentError, "Resources do not accept %s" % options.keys.collect { |k| k.to_s }.join(", ") + end end - # Merge an override resource in. + # Merge an override resource in. This will throw exceptions if + # any overrides aren't allowed. def merge(resource) + # Test the resource scope, to make sure the resource is even allowed + # to override. + unless self.source.object_id == resource.source.object_id || resource.source.child_of?(self.source) + raise Puppet::ParseError.new("Only subclasses can override parameters", resource.line, resource.file) + end # Some of these might fail, but they'll fail in the way we want. resource.params.each do |name, param| - set(param) + override_parameter(param) end end + # Modify this resource in the Rails database. Poor design, yo. def modify_rails(db_resource) args = rails_args args.each do |param, value| @@ -226,23 +195,6 @@ class Puppet::Parser::Resource @@paramcheck end - # Verify that all passed parameters are valid. This throws an error if - # there's a problem, so we don't have to worry about the return value. - def paramcheck(param) - param = param.to_s - # Now make sure it's a valid argument to our class. These checks - # are organized in order of commonhood -- most types, it's a valid - # argument and paramcheck is enabled. - if @ref.typeclass.validattr?(param) - true - elsif %w{name title}.include?(param) # always allow these - true - elsif paramcheck? - self.fail Puppet::ParseError, "Invalid parameter '%s' for type '%s'" % - [param.inspect, @ref.type] - end - end - # A temporary occasion, until I get paths in the scopes figured out. def path to_s @@ -253,59 +205,6 @@ class Puppet::Parser::Resource @ref.to_s end - # You have to pass a Resource::Param to this. - def set(param, value = nil, source = nil) - if value and source - param = Puppet::Parser::Resource::Param.new( - :name => param, :value => value, :source => source - ) - elsif ! param.is_a?(Puppet::Parser::Resource::Param) - raise ArgumentError, "Must pass a parameter or all necessary values" - end - # Because definitions are now parse-time, I can paramcheck immediately. - paramcheck(param.name) - - if current = @params[param.name] - # This is where we'd ignore any equivalent values if we wanted to, - # but that would introduce a lot of really bad ordering issues. - if param.source.child_of?(current.source) - if param.add - # Merge with previous value. - param.value = [ current.value, param.value ].flatten - end - - # Replace it, keeping all of its info. - @params[param.name] = param - else - if Puppet[:trace] - puts caller - end - msg = "Parameter '%s' is already set on %s" % - [param.name, self.to_s] - if current.source.to_s != "" - msg += " by %s" % current.source - end - if current.file or current.line - fields = [] - fields << current.file if current.file - fields << current.line.to_s if current.line - msg += " at %s" % fields.join(":") - end - msg += "; cannot redefine" - error = Puppet::ParseError.new(msg) - error.file = param.file if param.file - error.line = param.line if param.line - raise error - end - else - if self.source == param.source or param.source.child_of?(self.source) - @params[param.name] = param - else - fail Puppet::ParseError, "Only subclasses can set parameters" - end - end - end - def tags unless defined? @tags @tags = scope.tags @@ -387,12 +286,102 @@ class Puppet::Parser::Resource return obj end - - def virtual? - self.virtual - end private + + # Add default values from our definition. + def add_defaults + scope.lookupdefaults(self.type).each do |name, param| + unless @params.include?(name) + self.debug "Adding default for %s" % name + + @params[name] = param + end + end + end + + # Add any metaparams defined in our scope. This actually adds any metaparams + # from any parent scope, and there's currently no way to turn that off. + def add_metaparams + Puppet::Type.eachmetaparam do |name| + # Skip metaparams that we already have defined. + next if @params[name] + if val = scope.lookupvar(name.to_s, false) + unless val == :undefined + set_parameter(name, val) + end + end + end + end + + # Add any overrides for this object. + def add_overrides + if overrides = scope.configuration.resource_overrides(self) + overrides.each do |over| + self.merge(over) + end + + # Remove the overrides, so that the configuration knows there + # are none left. + overrides.clear + end + end + + # Accept a parameter from an override. + def override_parameter(param) + # This can happen if the override is defining a new parameter, rather + # than replacing an existing one. + unless current = @params[param.name] + @params[param.name] = param + return + end + + # The parameter is already set. See if they're allowed to override it. + if param.source.child_of?(current.source) + if param.add + # Merge with previous value. + param.value = [ current.value, param.value ].flatten + end + + # Replace it, keeping all of its info. + @params[param.name] = param + else + if Puppet[:trace] + puts caller + end + msg = "Parameter '%s' is already set on %s" % + [param.name, self.to_s] + if current.source.to_s != "" + msg += " by %s" % current.source + end + if current.file or current.line + fields = [] + fields << current.file if current.file + fields << current.line.to_s if current.line + msg += " at %s" % fields.join(":") + end + msg += "; cannot redefine" + raise Puppet::ParseError.new(msg, param.line, param.file) + end + end + + # Verify that all passed parameters are valid. This throws an error if + # there's a problem, so we don't have to worry about the return value. + def paramcheck(param) + param = param.to_s + # Now make sure it's a valid argument to our class. These checks + # are organized in order of commonhood -- most types, it's a valid + # argument and paramcheck is enabled. + if @ref.typeclass.validattr?(param) + true + elsif %w{name title}.include?(param) # always allow these + true + elsif paramcheck? + self.fail Puppet::ParseError, "Invalid parameter '%s' for type '%s'" % + [param, @ref.type] + end + end + def rails_args return [:type, :title, :line, :exported].inject({}) do |hash, param| # 'type' isn't a valid column name, so we have to use another name. @@ -403,6 +392,26 @@ class Puppet::Parser::Resource hash end end -end -# $Id$ + # Define a parameter in our resource. + def set_parameter(param, value = nil) + if value + param = Puppet::Parser::Resource::Param.new( + :name => param, :value => value, :source => self.source + ) + elsif ! param.is_a?(Puppet::Parser::Resource::Param) + raise ArgumentError, "Must pass a parameter or all necessary values" + end + + # And store it in our parameter hash. + @params[param.name] = param + end + + # Make sure the resource's parameters are all valid for the type. + def validate + @params.each do |name, param| + # Make sure it's a valid parameter. + paramcheck(name) + end + end +end diff --git a/lib/puppet/parser/resource/reference.rb b/lib/puppet/parser/resource/reference.rb index 19d179660..b19dd2258 100644 --- a/lib/puppet/parser/resource/reference.rb +++ b/lib/puppet/parser/resource/reference.rb @@ -67,5 +67,3 @@ class Puppet::Parser::Resource::Reference @typeclass end end - -# $Id$ diff --git a/lib/puppet/parser/scope.rb b/lib/puppet/parser/scope.rb index cb6d98584..808362858 100644 --- a/lib/puppet/parser/scope.rb +++ b/lib/puppet/parser/scope.rb @@ -15,7 +15,7 @@ class Puppet::Parser::Scope include Enumerable include Puppet::Util::Errors - attr_accessor :parent, :level, :interp, :source + attr_accessor :parent, :level, :parser, :source attr_accessor :name, :type, :base, :keyword attr_accessor :top, :translated, :exported, :virtual, :configuration @@ -56,6 +56,11 @@ class Puppet::Parser::Scope end end + # Retrieve a given class scope from the configuration. + def class_scope(klass) + configuration.class_scope(klass) + end + # Are we the top scope? def topscope? @level == 1 @@ -67,7 +72,7 @@ class Puppet::Parser::Scope def findclass(name) @namespaces.each do |namespace| - if r = interp.findclass(namespace, name) + if r = parser.findclass(namespace, name) return r end end @@ -76,7 +81,7 @@ class Puppet::Parser::Scope def finddefine(name) @namespaces.each do |namespace| - if r = interp.finddefine(namespace, name) + if r = parser.finddefine(namespace, name) return r end end @@ -87,8 +92,7 @@ class Puppet::Parser::Scope configuration.findresource(string, name) end - # Initialize our new scope. Defaults to having no parent and to - # being declarative. + # Initialize our new scope. Defaults to having no parent. def initialize(hash = {}) if hash.include?(:namespace) if n = hash[:namespace] @@ -115,7 +119,7 @@ class Puppet::Parser::Scope # All of the defaults set for types. It's a hash of hashes, # with the first key being the type, then the second key being # the parameter. - @defaultstable = Hash.new { |dhash,type| + @defaults = Hash.new { |dhash,type| dhash[type] = {} } end @@ -136,8 +140,8 @@ class Puppet::Parser::Scope # then override them with any current values # this should probably be done differently - if @defaultstable.include?(type) - @defaultstable[type].each { |var,value| + if @defaults.include?(type) + @defaults[type].each { |var,value| values[var] = value } end @@ -195,11 +199,9 @@ class Puppet::Parser::Scope @namespaces.dup end - # Create a new scope. - def newscope(hash = {}) - hash[:parent] = self - #debug "Creating new scope, level %s" % [self.level + 1] - return Puppet::Parser::Scope.new(hash) + # Create a new scope and set these options. + def newscope(options) + configuration.newscope(self, options) end # Is this class for a node? This is used to make sure that @@ -256,7 +258,7 @@ class Puppet::Parser::Scope # Add a new object to our object table and the global list, and do any necessary # checks. def setresource(resource) - @configuration.store_resource(resource) + @configuration.store_resource(self, resource) # Mark the resource as virtual or exported, as necessary. if self.exported? @@ -264,7 +266,6 @@ class Puppet::Parser::Scope elsif self.virtual? resource.virtual = true end - raise "setresource's tests aren't fixed" return resource end @@ -274,19 +275,13 @@ class Puppet::Parser::Scope # at the end. def setoverride(resource) @configuration.store_override(resource) - raise "setoverride tests aren't fixed" - if obj = @definedtable[resource.ref] - obj.merge(resource) - else - @overridetable[resource.ref] << resource - end end # Set defaults for a type. The typename should already be downcased, # so that the syntax is isolated. We don't do any kind of type-checking # here; instead we let the resource do it when the defaults are used. def setdefaults(type, params) - table = @defaultstable[type] + table = @defaults[type] # if we got a single param, it'll be in its own array params = [params] unless params.is_a?(Array) @@ -294,17 +289,8 @@ class Puppet::Parser::Scope params.each { |param| #Puppet.debug "Default for %s is %s => %s" % # [type,ary[0].inspect,ary[1].inspect] - if @@declarative - if table.include?(param.name) - self.fail "Default already defined for %s { %s }" % - [type,param.name] - end - else - if table.include?(param.name) - # we should maybe allow this warning to be turned off... - Puppet.warning "Replacing default for %s { %s }" % - [type,param.name] - end + if table.include?(param.name) + raise Puppet::ParseError.new("Default already defined for %s { %s }; cannot redefine" % [type, param.name], param.line, param.file) end table[param.name] = param } @@ -312,23 +298,19 @@ class Puppet::Parser::Scope # Set a variable in the current scope. This will override settings # in scopes above, but will not allow variables in the current scope - # to be reassigned if we're declarative (which is the default). + # to be reassigned. def setvar(name,value, file = nil, line = nil) #Puppet.debug "Setting %s to '%s' at level %s" % # [name.inspect,value,self.level] if @symtable.include?(name) - if @@declarative - error = Puppet::ParseError.new("Cannot reassign variable %s" % name) - if file - error.file = file - end - if line - error.line = line - end - raise error - else - Puppet.warning "Reassigning %s to %s" % [name,value] + error = Puppet::ParseError.new("Cannot reassign variable %s" % name) + if file + error.file = file + end + if line + error.line = line end + raise error end @symtable[name] = value end @@ -446,8 +428,7 @@ class Puppet::Parser::Scope # Convert our resource to a TransBucket. def to_trans - raise "Scope#to_trans needs to be tested" - bucket = Puppet::TransBucket.new ret + bucket = Puppet::TransBucket.new([]) case self.type when "": bucket.type = "main" diff --git a/test/language/ast/component.rb b/test/language/ast/component.rb index 40543e9ab..13cf60857 100755 --- a/test/language/ast/component.rb +++ b/test/language/ast/component.rb @@ -17,10 +17,10 @@ class TestASTComponent < Test::Unit::TestCase AST = Puppet::Parser::AST def test_component - interp, scope, source = mkclassframing + parser, scope, source = mkclassframing # Create a new definition - klass = interp.newdefine "yayness", + klass = parser.newdefine "yayness", :arguments => [["owner", stringobj("nobody")], %w{mode}], :code => AST::ASTArray.new( :children => [resourcedef("file", "/tmp/$name", @@ -90,7 +90,7 @@ class TestASTComponent < Test::Unit::TestCase # #539 - definitions should support both names and titles def test_names_and_titles - interp, scope, source = mkclassframing + parser, scope, source = mkclassframing [ {:name => "one", :title => "two"}, @@ -98,7 +98,7 @@ class TestASTComponent < Test::Unit::TestCase ].each_with_index do |hash, i| # Create a definition that uses both name and title - klass = interp.newdefine "yayness%s" % i + klass = parser.newdefine "yayness%s" % i subscope = klass.subscope(scope, "yayness%s" % i) @@ -133,8 +133,8 @@ class TestASTComponent < Test::Unit::TestCase # Testing the root cause of #615. We should be using the fqname for the type, instead # of just the short name. def test_fully_qualified_types - interp = mkinterp - klass = interp.newclass("one::two") + parser = mkparser + klass = parser.newclass("one::two") assert_equal("one::two", klass.classname, "Class did not get fully qualified class name") end diff --git a/test/language/configuration.rb b/test/language/configuration.rb index aafdf8356..688782f7b 100755 --- a/test/language/configuration.rb +++ b/test/language/configuration.rb @@ -27,7 +27,12 @@ class TestConfiguration < Test::Unit::TestCase end def mkconfig(options = {}) - @config = Config.new(mknode, mkparser, options) + if node = options[:node] + options.delete(:node) + else + node = mknode + end + @config = Config.new(node, mkparser, options) end def test_initialize @@ -111,7 +116,7 @@ class TestConfiguration < Test::Unit::TestCase # Now that we've got the top scope, create a new, subscope subscope = nil assert_nothing_raised("Could not create subscope") do - subscope = config.newscope + subscope = config.newscope(config.topscope) end assert_instance_of(Scope, subscope, "Did not create subscope") assert(graph.edge?(config.topscope, subscope), "An edge between top scope and subscope was not added") @@ -121,11 +126,12 @@ class TestConfiguration < Test::Unit::TestCase assert_equal(config.topscope.object_id, config.parent(subscope).object_id, "Did not get correct parent scope from configuration") assert_equal(config.topscope.object_id, subscope.parent.object_id, "Scope did not correctly retrieve its parent scope") - # Now create another, this time specifying the parent scope + # Now create another, this time specifying options another = nil assert_nothing_raised("Could not create subscope") do - another = config.newscope(subscope) + another = config.newscope(subscope, :name => "testing") end + assert_equal("testing", another.name, "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") @@ -142,7 +148,7 @@ class TestConfiguration < Test::Unit::TestCase # The heart of the action. def test_compile config = mkconfig - [:set_node_parameters, :evaluate_main, :evaluate_ast_nodes, :evaluate_classes, :evaluate_generators, :fail_on_unevaluated, :finish].each do |method| + [:set_node_parameters, :evaluate_main, :evaluate_ast_node, :evaluate_classes, :evaluate_generators, :fail_on_unevaluated, :finish].each do |method| config.expects(method) end config.expects(:extract).returns(:config) diff --git a/test/language/interpreter.rb b/test/language/interpreter.rb index 070e2e77e..6b9aa7258 100755 --- a/test/language/interpreter.rb +++ b/test/language/interpreter.rb @@ -20,7 +20,6 @@ class TestInterpreter < PuppetTest::TestCase include PuppetTest::ParserTesting include PuppetTest::ResourceTesting AST = Puppet::Parser::AST - NodeDef = Puppet::Parser::Interpreter::NodeDef # create a simple manifest that uses nodes to create a file def mknodemanifest(node, file) @@ -34,23 +33,13 @@ class TestInterpreter < PuppetTest::TestCase return [file, createdfile] end - def test_simple - file = tempfile() - File.open(file, "w") { |f| - f.puts "file { \"/etc\": owner => root }" - } - assert_nothing_raised { - Puppet::Parser::Interpreter.new(:Manifest => file) - } - end - def test_reloadfiles - hostname = Facter["hostname"].value + node = mknode(Facter["hostname"].value) file = tempfile() # Create a first version - createdfile = mknodemanifest(hostname, file) + createdfile = mknodemanifest(node.name, file) interp = nil assert_nothing_raised { @@ -59,61 +48,21 @@ class TestInterpreter < PuppetTest::TestCase config = nil assert_nothing_raised { - config = interp.run(hostname, {}) + config = interp.compile(node) } - sleep(1) + Puppet[:filetimeout] = -5 # Now create a new file - createdfile = mknodemanifest(hostname, file) + createdfile = mknodemanifest(node.name, file) newconfig = nil assert_nothing_raised { - newconfig = interp.run(hostname, {}) + newconfig = interp.compile(node) } assert(config != newconfig, "Configs are somehow the same") end - # Make sure searchnode behaves as we expect. - def test_nodesearch - # We use two sources here to catch a weird bug where the default - # node is used if the host isn't in the first source. - interp = mkinterp - - # Make some nodes - names = %w{node1 node2 node2.domain.com} - interp.newnode names - interp.newnode %w{default} - - nodes = {} - # Make sure we can find them all, using the direct method - names.each do |name| - nodes[name] = interp.nodesearch_code(name) - assert(nodes[name], "Could not find %s" % name) - nodes[name].file = __FILE__ - end - - # Now let's try it with the nodesearch method - names.each do |name| - node = interp.nodesearch(name) - assert(node, "Could not find #{name} via nodesearch") - end - - # Make sure we find the default node when we search for nonexistent nodes - assert_nothing_raised do - default = interp.nodesearch("nosuchnode") - assert(default, "Did not find default node") - assert_equal("default", default.classname) - end - - # Now make sure the longest match always wins - node = interp.nodesearch(*%w{node2 node2.domain.com}) - - assert(node, "Did not find node2") - assert_equal("node2.domain.com", node.classname, - "Did not get longest match") - end - def test_parsedate Puppet[:filetimeout] = 0 main = tempfile() @@ -160,35 +109,6 @@ class TestInterpreter < PuppetTest::TestCase newdate = interp.parsedate assert(date != newdate, "Parsedate was not updated") end - - # Make sure class, node, and define methods are case-insensitive - def test_structure_case_insensitivity - interp = mkinterp - - result = nil - assert_nothing_raised do - result = interp.newclass "Yayness" - end - assert_equal(result, interp.findclass("", "yayNess")) - - assert_nothing_raised do - result = interp.newdefine "FunTest" - end - assert_equal(result, interp.finddefine("", "fUntEst"), - "%s was not matched" % "fUntEst") - - assert_nothing_raised do - result = interp.newnode("MyNode").shift - end - assert_equal(result, interp.nodesearch("mYnOde"), - "mYnOde was not matched") - - assert_nothing_raised do - result = interp.newnode("YayTest.Domain.Com").shift - end - assert_equal(result, interp.nodesearch("yaYtEst.domAin.cOm"), - "yaYtEst.domAin.cOm was not matched") - end # Make sure our whole chain works. def test_evaluate @@ -444,70 +364,6 @@ class TestInterpreter < PuppetTest::TestCase end end - def test_nodedef - interp = mkinterp - interp.newclass("base") - interp.newclass("sub", :parent => "base") - interp.newclass("other") - - node = nil - assert_nothing_raised("Could not create a node definition") do - node = NodeDef.new :name => "yay", :classes => "sub", :parameters => {"one" => "two", "three" => "four"} - end - - scope = mkscope :interp => interp - assert_nothing_raised("Could not evaluate the node definition") do - node.evaluate(:scope => scope) - end - - assert_equal("two", scope.lookupvar("one"), "NodeDef did not set variable") - assert_equal("four", scope.lookupvar("three"), "NodeDef did not set variable") - - assert(scope.classlist.include?("sub"), "NodeDef did not evaluate class") - assert(scope.classlist.include?("base"), "NodeDef did not evaluate base class") - - # Now try a node def with multiple classes - assert_nothing_raised("Could not create a node definition") do - node = NodeDef.new :name => "yay", :classes => %w{sub other base}, :parameters => {"one" => "two", "three" => "four"} - end - - scope = mkscope :interp => interp - assert_nothing_raised("Could not evaluate the node definition") do - node.evaluate(:scope => scope) - end - - assert_equal("two", scope.lookupvar("one"), "NodeDef did not set variable") - assert_equal("four", scope.lookupvar("three"), "NodeDef did not set variable") - - assert(scope.classlist.include?("sub"), "NodeDef did not evaluate class") - assert(scope.classlist.include?("other"), "NodeDef did not evaluate other class") - - # And a node def with no params - assert_nothing_raised("Could not create a node definition with no params") do - node = NodeDef.new :name => "yay", :classes => %w{sub other base} - end - - scope = mkscope :interp => interp - assert_nothing_raised("Could not evaluate the node definition") do - node.evaluate(:scope => scope) - end - - assert(scope.classlist.include?("sub"), "NodeDef did not evaluate class") - assert(scope.classlist.include?("other"), "NodeDef did not evaluate other class") - - # Now make sure nodedef doesn't fail when some classes are not defined (#687). - assert_nothing_raised("Could not create a node definition with some invalid classes") do - node = NodeDef.new :name => "yay", :classes => %w{base unknown} - end - - scope = mkscope :interp => interp - assert_nothing_raised("Could not evaluate the node definition with some invalid classes") do - node.evaluate(:scope => scope) - end - - assert(scope.classlist.include?("base"), "NodeDef did not evaluate class") - end - # Make sure that reparsing is atomic -- failures don't cause a broken state, and we aren't subject # to race conditions if someone contacts us while we're reparsing. def test_atomic_reparsing diff --git a/test/language/parser.rb b/test/language/parser.rb index afffa9293..77595b155 100755 --- a/test/language/parser.rb +++ b/test/language/parser.rb @@ -1175,6 +1175,23 @@ file { "/tmp/yayness": assert_instance_of(AST::HostClass, klass, "Did not autoload sub class from alone file with no namespace") assert_equal("alone::sub", klass.classname, "Incorrect class was returned") end + + # Make sure class, node, and define methods are case-insensitive + def test_structure_case_insensitivity + parser = mkparser + + result = nil + assert_nothing_raised do + result = parser.newclass "Yayness" + end + assert_equal(result, parser.findclass("", "yayNess")) + + assert_nothing_raised do + result = parser.newdefine "FunTest" + end + assert_equal(result, parser.finddefine("", "fUntEst"), + "%s was not matched" % "fUntEst") + end end # $Id$ diff --git a/test/language/resource.rb b/test/language/resource.rb index 039c67216..73d516f51 100755 --- a/test/language/resource.rb +++ b/test/language/resource.rb @@ -11,149 +11,198 @@ class TestResource < PuppetTest::TestCase include PuppetTest::ResourceTesting Parser = Puppet::Parser AST = Parser::AST + Resource = Puppet::Parser::Resource Reference = Puppet::Parser::Resource::Reference def setup super Puppet[:trace] = false - @interp, @scope, @source = mkclassframing end def test_initialize args = {:type => "resource", :title => "testing", - :source => @source, :scope => @scope} + :source => "source", :scope => "scope"} # Check our arg requirements args.each do |name, value| try = args.dup try.delete(name) - assert_raise(Puppet::DevError) do + assert_raise(ArgumentError, "Did not fail when %s was missing" % name) do Parser::Resource.new(try) end end - args[:params] = paramify @source, :one => "yay", :three => "rah" + Reference.expects(:new).with(:type => "resource", :title => "testing", :scope => "scope").returns(:ref) res = nil assert_nothing_raised do res = Parser::Resource.new(args) end - - # Make sure it got the parameters correctly. - assert_equal("yay", res[:one]) - assert_equal("rah", res[:three]) - - assert_equal({:one => "yay", :three => "rah"}, res.to_hash) end - def test_override + def test_merge res = mkresource + other = mkresource - # Now verify we can't override with any random class - assert_raise(Puppet::ParseError) do - res.set paramify(@scope.findclass("other"), "one" => "boo").shift + # First try the case where the resource is not allowed to override + res.source = "source1" + other.source = "source2" + other.source.expects(:child_of?).with("source1").returns(false) + assert_raise(Puppet::ParseError, "Allowed unrelated resources to override") do + res.merge(other) end - # And that we can with a subclass - assert_nothing_raised do - res.set paramify(@scope.findclass("sub1"), "one" => "boo").shift - end + # Next try it when the sources are equal. + res.source = "source3" + other.source = res.source + other.source.expects(:child_of?).with("source3").never + params = {:a => :b, :c => :d} + other.expects(:params).returns(params) + res.expects(:override_parameter).with(:b) + res.expects(:override_parameter).with(:d) + res.merge(other) + + # And then parentage is involved + other = mkresource + res.source = "source3" + other.source = "source4" + other.source.expects(:child_of?).with("source3").returns(true) + params = {:a => :b, :c => :d} + other.expects(:params).returns(params) + res.expects(:override_parameter).with(:b) + res.expects(:override_parameter).with(:d) + res.merge(other) + end - # And that a different subclass can override a different parameter - assert_nothing_raised do - res.set paramify(@scope.findclass("sub2"), "three" => "boo").shift - end + # the [] method + def test_array_accessors + res = mkresource + params = res.instance_variable_get("@params") + assert_nil(res[:missing], "Found a missing parameter somehow") + params[:something] = stub(:value => "yay") + assert_equal("yay", res[:something], "Did not correctly call value on the parameter") - # But not the same one - assert_raise(Puppet::ParseError) do - res.set paramify(@scope.findclass("sub2"), "one" => "something").shift - end + res.expects(:title).returns(:mytitle) + assert_equal(:mytitle, res[:title], "Did not call title when asked for it as a param") end - def check_paramadd(val1, val2, merged_val) - res = mkresource :params => {"one" => val1} - assert_nothing_raised do - res.set Parser::Resource::Param.new( - :name => "one", :value => val2, - :add => true, :source => @scope.findclass("sub1")) - end - assert_equal(merged_val, res[:one]) + # Make sure any defaults stored in the scope get added to our resource. + def test_add_defaults + res = mkresource + params = res.instance_variable_get("@params") + params[:a] = :b + res.scope.expects(:lookupdefaults).with(res.type).returns(:a => :replaced, :c => :d) + res.expects(:debug) + + res.send(:add_defaults) + assert_equal(:d, params[:c], "Did not set default") + assert_equal(:b, params[:a], "Replaced parameter with default") end - def test_paramadd - check_paramadd([], [], []) - check_paramadd([], "rah", ["rah"]) - check_paramadd([], ["rah", "bah"], ["rah", "bah"]) - - check_paramadd("yay", [], ["yay"]) - check_paramadd("yay", "rah", ["yay", "rah"]) - check_paramadd("yay", ["rah", "bah"], ["yay", "rah", "bah"]) - - check_paramadd(["yay", "boo"], [], ["yay", "boo"]) - check_paramadd(["yay", "boo"], "rah", ["yay", "boo", "rah"]) - check_paramadd(["yay", "boo"], ["rah", "bah"], - ["yay", "boo", "rah", "bah"]) + def test_finish + res = mkresource + res.expects(:add_overrides) + res.expects(:add_defaults) + res.expects(:add_metaparams) + res.expects(:validate) + res.finish end - def test_merge - # Start with the normal one + # Make sure we paramcheck our params + def test_validate res = mkresource + params = res.instance_variable_get("@params") + params[:one] = :two + params[:three] = :four + res.expects(:paramcheck).with(:one) + res.expects(:paramcheck).with(:three) + res.send(:validate) + end - # Now create a resource from a different scope - other = mkresource :source => other, :params => {"one" => "boo"} - - # Make sure we can't merge it - assert_raise(Puppet::ParseError) do - res.merge(other) - end - - # Make one from a subscope - other = mkresource :source => "sub1", :params => {"one" => "boo"} - - # Make sure it merges - assert_nothing_raised do - res.merge(other) - end + def test_override_parameter + res = mkresource + params = res.instance_variable_get("@params") + + # There are three cases, with the second having two options: + + # No existing parameter. + param = stub(:name => "myparam") + res.send(:override_parameter, param) + assert_equal(param, params["myparam"], "Override was not added to param list") + + # An existing parameter that we can override. + source = stub(:child_of? => true) + # Start out without addition + params["param2"] = stub(:source => :whatever) + param = stub(:name => "param2", :source => source, :add => false) + res.send(:override_parameter, param) + assert_equal(param, params["param2"], "Override was not added to param list") + + # Try with addition. + params["param2"] = stub(:value => :a, :source => :whatever) + param = stub(:name => "param2", :source => source, :add => true, :value => :b) + param.expects(:value=).with([:a, :b]) + res.send(:override_parameter, param) + assert_equal(param, params["param2"], "Override was not added to param list") + + # And finally, make sure we throw an exception when the sources aren't related + source = stub(:child_of? => false) + params["param2"] = stub(:source => :whatever, :file => :f, :line => :l) + old = params["param2"] + param = stub(:name => "param2", :source => source, :file => :f, :line => :l) + assert_raise(Puppet::ParseError, "Did not fail when params conflicted") do + res.send(:override_parameter, param) + end + assert_equal(old, params["param2"], "Param was replaced irrespective of conflict") + end - assert_equal("boo", res["one"]) + def test_set_parameter + res = mkresource + params = res.instance_variable_get("@params") + + # First test the simple case: It's already a parameter + param = mock('param') + param.expects(:is_a?).with(Resource::Param).returns(true) + param.expects(:name).returns("pname") + res.send(:set_parameter, param) + assert_equal(param, params["pname"], "Parameter was not added to hash") + + # Now the case where there's no value but it's not a param + param = mock('param') + param.expects(:is_a?).with(Resource::Param).returns(false) + assert_raise(ArgumentError, "Did not fail when a non-param was passed") do + res.send(:set_parameter, param) + end + + # and the case where a value is passed in + param = stub :name => "pname", :value => "whatever" + Resource::Param.expects(:new).with(:name => "pname", :value => "myvalue", :source => res.source).returns(param) + res.send(:set_parameter, "pname", "myvalue") + assert_equal(param, params["pname"], "Did not put param in hash") end def test_paramcheck - # First make a builtin resource - res = nil - assert_nothing_raised do - res = Parser::Resource.new :type => "file", :title => tempfile(), - :source => @source, :scope => @scope - end - - %w{path group source schedule subscribe}.each do |param| - assert_nothing_raised("Param %s was considered invalid" % param) do - res.paramcheck(param) - end - end - - %w{this bad noness}.each do |param| - assert_raise(Puppet::ParseError, "%s was considered valid" % param) do - res.paramcheck(param) - end - end + # There are three cases here: - # Now create a defined resource - assert_nothing_raised do - res = Parser::Resource.new :type => "resource", :title => "yay", - :source => @source, :scope => @scope - end - - %w{one two three schedule subscribe}.each do |param| - assert_nothing_raised("Param %s was considered invalid" % param) do - res.paramcheck(param) - end - end - - %w{this bad noness}.each do |param| - assert_raise(Puppet::ParseError, "%s was considered valid" % param) do - res.paramcheck(param) - end - end + # It's a valid parameter + res = mkresource + ref = mock('ref') + res.instance_variable_set("@ref", ref) + klass = mock("class") + ref.expects(:typeclass).returns(klass).times(4) + klass.expects(:validattr?).with("good").returns(true) + assert(res.send(:paramcheck, :good), "Did not allow valid param") + + # It's name or title + klass.expects(:validattr?).with("name").returns(false) + assert(res.send(:paramcheck, :name), "Did not allow name") + klass.expects(:validattr?).with("title").returns(false) + assert(res.send(:paramcheck, :title), "Did not allow title") + + # It's not actually allowed + klass.expects(:validattr?).with("other").returns(false) + res.expects(:fail) + ref.expects(:type) + res.send(:paramcheck, :other) end def test_to_trans @@ -186,62 +235,10 @@ class TestResource < PuppetTest::TestCase assert_equal(["file", refs[3].title], obj["notify"], "Array with single resource reference was not turned into single value") end - def test_adddefaults - # Set some defaults at the top level - top = {:one => "fun", :two => "shoe"} - - @scope.setdefaults("resource", paramify(@source, top)) - - # Make a resource at that level - res = Parser::Resource.new :type => "resource", :title => "yay", - :source => @source, :scope => @scope - - # Add the defaults - assert_nothing_raised do - res.adddefaults - end - - # And make sure we got them - top.each do |p, v| - assert_equal(v, res[p]) - end - - # Now got a bit lower - other = @scope.newscope - - # And create a resource - lowerres = Parser::Resource.new :type => "resource", :title => "funtest", - :source => @source, :scope => other - - assert_nothing_raised do - lowerres.adddefaults - end - - # And check - top.each do |p, v| - assert_equal(v, lowerres[p]) - end - - # Now add some of our own defaults - lower = {:one => "shun", :three => "free"} - other.setdefaults("resource", paramify(@source, lower)) - otherres = Parser::Resource.new :type => "resource", :title => "yaytest", - :source => @source, :scope => other - - should = top.dup - # Make sure the lower defaults beat the higher ones. - lower.each do |p, v| should[p] = v end - - otherres.adddefaults - - should.each do |p,v| - assert_equal(v, otherres[p]) - end - end - def test_evaluate + @parser = mkparser # Make a definition that we know will, um, do something - @interp.newdefine "evaltest", + @parser.newdefine "evaltest", :arguments => [%w{one}, ["two", stringobj("755")]], :code => resourcedef("file", "/tmp", "owner" => varref("one"), "mode" => varref("two")) @@ -272,49 +269,36 @@ class TestResource < PuppetTest::TestCase "Evaluated resource was not deleted") end - def test_addoverrides - # First create an override for an object that doesn't yet exist - over1 = mkresource :source => "sub1", :params => {:one => "yay"} - - assert_nothing_raised do - @scope.setoverride(over1) - end - - assert(over1.override, "Override was not marked so") - - # Now make the resource - res = mkresource :source => "base", :params => {:one => "rah", - :three => "foo"} - - # And add it to our scope - @scope.setresource(res) - - # And make sure over1 has not yet taken affect - assert_equal("foo", res[:three], "Lost value") - - # Now add an immediately binding override - over2 = mkresource :source => "sub1", :params => {:three => "yay"} - - assert_nothing_raised do - @scope.setoverride(over2) - end - - # And make sure it worked - assert_equal("yay", res[:three], "Override 2 was ignored") - - # Now add our late-binding override - assert_nothing_raised do - res.addoverrides - end - - # And make sure they're still around - assert_equal("yay", res[:one], "Override 1 lost") - assert_equal("yay", res[:three], "Override 2 lost") - - # And finally, make sure that there are no remaining overrides - assert_nothing_raised do - res.addoverrides - end + def test_add_overrides + # Try it with nil + res = mkresource + res.scope = mock('scope') + config = mock("config") + res.scope.expects(:configuration).returns(config) + config.expects(:resource_overrides).with(res).returns(nil) + res.expects(:merge).never + res.send(:add_overrides) + + # And an empty array + res = mkresource + res.scope = mock('scope') + config = mock("config") + res.scope.expects(:configuration).returns(config) + config.expects(:resource_overrides).with(res).returns([]) + res.expects(:merge).never + res.send(:add_overrides) + + # And with some overrides + res = mkresource + res.scope = mock('scope') + config = mock("config") + res.scope.expects(:configuration).returns(config) + returns = %w{a b} + config.expects(:resource_overrides).with(res).returns(returns) + res.expects(:merge).with("a") + res.expects(:merge).with("b") + res.send(:add_overrides) + assert(returns.empty?, "Did not clear overrides") end def test_proxymethods @@ -326,28 +310,18 @@ class TestResource < PuppetTest::TestCase assert_equal(false, res.builtin?) end - def test_addmetaparams - mkevaltest @interp - res = Parser::Resource.new :type => "evaltest", :title => "yay", - :source => @source, :scope => @scope, - :params => paramify(@source, :tag => "yay") - - assert_nil(res[:schedule], "Got schedule already") - assert_nothing_raised do - res.addmetaparams - end - @scope.setvar("schedule", "daily") - - # This is so we can test that it won't override already-set metaparams - @scope.setvar("tag", "funtest") + def test_add_metaparams + res = mkresource + params = res.instance_variable_get("@params") + params[:a] = :b + Puppet::Type.expects(:eachmetaparam).multiple_yields(:a, :b, :c) + res.scope.expects(:lookupvar).with("b", false).returns(:something) + res.scope.expects(:lookupvar).with("c", false).returns(:undefined) + res.expects(:set_parameter).with(:b, :something) - assert_nothing_raised do - res.addmetaparams - end + res.send(:add_metaparams) - assert_equal("daily", res[:schedule], "Did not get metaparam") - assert_equal("yay", res[:tag], "Overrode explicitly-set metaparam") - assert_nil(res[:noop], "Got invalid metaparam") + assert_nil(params[:c], "A value was created somehow for an unset metaparam") end def test_reference_conversion @@ -397,18 +371,19 @@ class TestResource < PuppetTest::TestCase # #472. Really, this still isn't the best behaviour, but at least # it's consistent with what we have elsewhere. def test_defaults_from_parent_classes + @parser = mkparser # Make a parent class with some defaults in it - @interp.newclass("base", + @parser.newclass("base", :code => defaultobj("file", :owner => "root", :group => "root") ) # Now a mid-level class with some different values - @interp.newclass("middle", :parent => "base", + @parser.newclass("middle", :parent => "base", :code => defaultobj("file", :owner => "bin", :mode => "755") ) # Now a lower class with its own defaults plus a resource - @interp.newclass("bottom", :parent => "middle", + @parser.newclass("bottom", :parent => "middle", :code => AST::ASTArray.new(:children => [ defaultobj("file", :owner => "adm", :recurse => "true"), resourcedef("file", "/tmp/yayness", {}) @@ -435,17 +410,18 @@ class TestResource < PuppetTest::TestCase # The second part of #539 - make sure resources pass the arguments # correctly. def test_title_with_definitions - define = @interp.newdefine "yayness", + @parser = mkparser + define = @parser.newdefine "yayness", :code => resourcedef("file", "/tmp", "owner" => varref("name"), "mode" => varref("title")) - klass = @interp.findclass("", "") + klass = @parser.findclass("", "") should = {:name => :owner, :title => :mode} [ {:name => "one", :title => "two"}, {:title => "three"}, ].each do |hash| - scope = mkscope :interp => @interp + scope = mkscope :parser => @parser args = {:type => "yayness", :title => hash[:title], :source => klass, :scope => scope} if hash[:name] @@ -487,7 +463,8 @@ class TestResource < PuppetTest::TestCase # #643 - Make sure virtual defines result in virtual resources def test_virtual_defines - define = @interp.newdefine("yayness", + @parser = mkparser + define = @parser.newdefine("yayness", :code => resourcedef("file", varref("name"), "mode" => "644")) diff --git a/test/language/scope.rb b/test/language/scope.rb index f0feee156..bd90caa53 100755 --- a/test/language/scope.rb +++ b/test/language/scope.rb @@ -98,8 +98,8 @@ class TestScope < Test::Unit::TestCase end def test_lookupvar - interp = mkinterp - scope = mkscope :interp => interp + parser = mkparser + scope = mkscope :parser => parser # first do the plain lookups assert_equal("", scope.lookupvar("var"), "scope did not default to string") @@ -111,7 +111,7 @@ class TestScope < Test::Unit::TestCase assert_equal("yep", scope.lookupvar("var"), "did not retrieve value correctly") # Now test the parent lookups - subscope = mkscope :interp => interp + subscope = mkscope :parser => parser subscope.parent = scope assert_equal("", subscope.lookupvar("nope"), "scope did not default to string with parent") assert_equal("", subscope.lookupvar("nope", true), "scope ignored usestring setting with parent") @@ -129,12 +129,12 @@ class TestScope < Test::Unit::TestCase end def test_lookup_qualified_var - interp = mkinterp - scope = mkscope :interp => interp + parser = mkparser + scope = mkscope :parser => parser scopes = {} classes = ["", "one", "one::two", "one::two::three"].each do |name| - klass = interp.newclass(name) + klass = parser.newclass(name) klass.evaluate(:scope => scope) scopes[name] = scope.class_scope(klass) end @@ -149,7 +149,7 @@ class TestScope < Test::Unit::TestCase def test_declarative # set to declarative - top = mkscope(:declarative => true) + top = mkscope sub = mkscope(:parent => top) assert_nothing_raised { @@ -166,93 +166,89 @@ class TestScope < Test::Unit::TestCase } end - def test_notdeclarative - # set to not declarative - top = mkscope(:declarative => false) - sub = mkscope(:parent => top) + def test_setdefaults + config = mkconfig - assert_nothing_raised { - top.setvar("test","value") - } - assert_nothing_raised { - top.setvar("test","other") - } - assert_nothing_raised { - sub.setvar("test","later") - } - assert_nothing_raised { - sub.setvar("test","yayness") - } - end + scope = config.topscope - def test_setdefaults - interp, scope, source = mkclassframing + defaults = scope.instance_variable_get("@defaults") - # The setdefaults method doesn't really check what we're doing, - # so we're just going to use fake defaults here. + # First the case where there are no defaults and we pass a single param + param = stub :name => "myparam" + scope.setdefaults(:mytype, param) + assert_equal({"myparam" => param}, defaults[:mytype], "Did not set default correctly") - # First do a simple local lookup - params = paramify(source, :one => "fun", :two => "shoe") - origshould = {} - params.each do |p| origshould[p.name] = p end - assert_nothing_raised do - scope.setdefaults(:file, params) - end + # Now the case where we pass in multiple parameters + param1 = stub :name => "one" + param2 = stub :name => "two" + scope.setdefaults(:newtype, [param1, param2]) + assert_equal({"one" => param1, "two" => param2}, defaults[:newtype], "Did not set multiple defaults correctly") - ret = nil - assert_nothing_raised do - ret = scope.lookupdefaults(:file) + # And the case where there's actually a conflict. Use the first default for this. + newparam = stub :name => "myparam" + assert_raise(Puppet::ParseError, "Allowed resetting of defaults") do + scope.setdefaults(:mytype, param) end + assert_equal({"myparam" => param}, defaults[:mytype], "Replaced default even though there was a failure") + end - assert_equal(origshould, ret) + def test_lookupdefaults + config = mkconfig + top = config.topscope - # Now create a subscope and add some more params. - newscope = scope.newscope + # Make a subscope + sub = config.newscope(top) - newparams = paramify(source, :one => "shun", :three => "free") - assert_nothing_raised { - newscope.setdefaults(:file, newparams) - } + topdefs = top.instance_variable_get("@defaults") + subdefs = sub.instance_variable_get("@defaults") - # And make sure we get the appropriate ones back - should = {} - params.each do |p| should[p.name] = p end - newparams.each do |p| should[p.name] = p end + # First add some defaults to our top scope + topdefs[:t1] = {:p1 => :p2, :p3 => :p4} + topdefs[:t2] = {:p5 => :p6} - assert_nothing_raised do - ret = newscope.lookupdefaults(:file) - end - - assert_equal(should, ret) + # Then the sub scope + subdefs[:t1] = {:p1 => :p7, :p8 => :p9} + subdefs[:t2] = {:p5 => :p10, :p11 => :p12} - # Make sure we still only get the originals from the top scope - assert_nothing_raised do - ret = scope.lookupdefaults(:file) + # Now make sure we get the correct list back + result = nil + assert_nothing_raised("Could not get defaults") do + result = sub.lookupdefaults(:t1) end + assert_equal(:p9, result[:p8], "Did not get child defaults") + assert_equal(:p4, result[:p3], "Did not override parent defaults with child default") + assert_equal(:p7, result[:p1], "Did not get parent defaults") + end - assert_equal(origshould, ret) + def test_parent + config = mkconfig + top = config.topscope - # Now create another scope and make sure we only get the top defaults - otherscope = scope.newscope - assert_equal(origshould, otherscope.lookupdefaults(:file)) + # Make a subscope + sub = config.newscope(top) - # And make sure none of the scopes has defaults for other types - [scope, newscope, otherscope].each do |sc| - assert_equal({}, sc.lookupdefaults(:exec)) - end + assert_equal(top, sub.parent, "Did not find parent scope correctly") + assert_equal(top, sub.parent, "Did not find parent scope on second call") + end + + def test_class_scope + config = mkconfig + scope = config.topscope + config.expects(:class_scope).with(:testing).returns(:myscope) + assert_equal(:myscope, scope.class_scope(:testing), "Did not pass back the results of config.class_scope") end - def test_strinterp + def test_strparser # Make and evaluate our classes so the qualified lookups work - interp = mkinterp - klass = interp.newclass("") - scope = mkscope(:interp => interp) + parser = mkparser + klass = parser.newclass("") + scope = mkscope(:parser => parser) klass.evaluate(:scope => scope) - klass = interp.newclass("one") + klass = parser.newclass("one") klass.evaluate(:scope => scope) - klass = interp.newclass("one::two") + klass = parser.newclass("one::two") klass.evaluate(:scope => scope) @@ -264,7 +260,7 @@ class TestScope < Test::Unit::TestCase scopes = {"" => scope} %w{one one::two one::two::three}.each do |name| - klass = interp.newclass(name) + klass = parser.newclass(name) klass.evaluate(:scope => scope) scopes[name] = scope.class_scope(klass) scopes[name].setvar("test", "value-%s" % name.sub(/.+::/,'')) @@ -297,8 +293,8 @@ class TestScope < Test::Unit::TestCase tests.each do |input, output| assert_nothing_raised("Failed to scan %s" % input.inspect) do - assert_equal(output, scope.strinterp(input), - 'did not interpret %s correctly' % input.inspect) + assert_equal(output, scope.strparser(input), + 'did not parserret %s correctly' % input.inspect) end end @@ -310,8 +306,8 @@ class TestScope < Test::Unit::TestCase %w{d f h l w z}.each do |l| string = "\\" + l assert_nothing_raised do - assert_equal(string, scope.strinterp(string), - 'did not interpret %s correctly' % string) + assert_equal(string, scope.strparser(string), + 'did not parserret %s correctly' % string) end assert(logs.detect { |m| m.message =~ /Unrecognised escape/ }, @@ -321,7 +317,7 @@ class TestScope < Test::Unit::TestCase end def test_setclass - interp, scope, source = mkclassframing + parser, scope, source = mkclassframing base = scope.findclass("base") assert(base, "Could not find base class") @@ -392,11 +388,11 @@ class TestScope < Test::Unit::TestCase end def test_includefunction - interp = mkinterp - scope = mkscope :interp => interp + parser = mkparser + scope = mkscope :parser => parser - myclass = interp.newclass "myclass" - otherclass = interp.newclass "otherclass" + myclass = parser.newclass "myclass" + otherclass = parser.newclass "otherclass" function = Puppet::Parser::AST::Function.new( :name => "include", @@ -417,12 +413,12 @@ class TestScope < Test::Unit::TestCase end def test_definedfunction - interp = mkinterp + parser = mkparser %w{one two}.each do |name| - interp.newdefine name + parser.newdefine name end - scope = mkscope :interp => interp + scope = mkscope :parser => parser assert_nothing_raised { %w{one two file user}.each do |type| @@ -503,7 +499,7 @@ class TestScope < Test::Unit::TestCase # Verify that we recursively mark as exported the results of collectable # components. def test_exportedcomponents - interp, scope, source = mkclassframing + parser, scope, source = mkclassframing children = [] args = AST::ASTArray.new( @@ -513,7 +509,7 @@ class TestScope < Test::Unit::TestCase ) # Create a top-level component - interp.newdefine "one", :arguments => [%w{arg}], + parser.newdefine "one", :arguments => [%w{arg}], :code => AST::ASTArray.new( :children => [ resourcedef("file", "/tmp", {"owner" => varref("arg")}) @@ -521,7 +517,7 @@ class TestScope < Test::Unit::TestCase ) # And a component that calls it - interp.newdefine "two", :arguments => [%w{arg}], + parser.newdefine "two", :arguments => [%w{arg}], :code => AST::ASTArray.new( :children => [ resourcedef("one", "ptest", {"arg" => varref("arg")}) @@ -529,7 +525,7 @@ class TestScope < Test::Unit::TestCase ) # And then a third component that calls the second - interp.newdefine "three", :arguments => [%w{arg}], + parser.newdefine "three", :arguments => [%w{arg}], :code => AST::ASTArray.new( :children => [ resourcedef("two", "yay", {"arg" => varref("arg")}) @@ -545,7 +541,7 @@ class TestScope < Test::Unit::TestCase obj.evaluate :scope => scope # And then evaluate it - interp.evaliterate(scope) + parser.evaliterate(scope) %w{file}.each do |type| objects = scope.lookupexported(type) @@ -585,9 +581,11 @@ Host <<||>>" objects = nil # We run it twice because we want to make sure there's no conflict # if we pull it up from the database. + node = mknode + node.parameters = {"hostname" => node.name} 2.times { |i| assert_nothing_raised { - objects = interp.run("localhost", {"hostname" => "localhost"}) + objects = interp.compile(node) } flat = objects.flatten @@ -603,7 +601,7 @@ Host <<||>>" # Make sure tags behave appropriately. def test_tags - interp, scope, source = mkclassframing + parser, scope, source = mkclassframing # First make sure we can only set legal tags ["an invalid tag", "-anotherinvalid", "bad*tag"].each do |tag| @@ -637,58 +635,22 @@ Host <<||>>" assert_equal((ptags + %w{onemore subscope}).sort, newscope.tags.sort) end - # Make sure we successfully translate objects - def test_translate - interp, scope, source = mkclassframing - - # Create a define that we'll be using - interp.newdefine("wrapper", :code => AST::ASTArray.new(:children => [ - resourcedef("file", varref("name"), "owner" => "root") - ])) - - # Now create a resource that uses that define - define = mkresource(:type => "wrapper", :title => "/tmp/testing", - :scope => scope, :source => source, :params => :none) - - scope.setresource define - - # And a normal resource - scope.setresource mkresource(:type => "file", :title => "/tmp/rahness", - :scope => scope, :source => source, - :params => {:owner => "root"}) - - # Evaluate the the define thing. - define.evaluate - - # Now the scope should have a resource and a subscope. Translate the - # whole thing. - ret = nil - assert_nothing_raised do - ret = scope.translate - end - - assert_instance_of(Puppet::TransBucket, ret) - - ret.each do |obj| - assert(obj.is_a?(Puppet::TransBucket) || obj.is_a?(Puppet::TransObject), - "Got a non-transportable object %s" % obj.class) - end - - rahness = ret.find { |c| c.type == "file" and c.name == "/tmp/rahness" } - assert(rahness, "Could not find top-level file") - assert_equal("root", rahness["owner"]) - - bucket = ret.find { |c| c.class == Puppet::TransBucket and c.name == "/tmp/testing" } - assert(bucket, "Could not find define bucket") + # FIXME This isn't a great test, but I need to move on. + def test_to_trans + bucket = mock("transbucket") + Puppet::TransBucket.expects(:new).with([]).returns(bucket) + scope = mkscope + scope.type = "mytype" + scope.name = "myname" - testing = bucket.find { |c| c.type == "file" and c.name == "/tmp/testing" } - assert(testing, "Could not find define file") - assert_equal("root", testing["owner"]) + bucket.expects(:name=).with("myname") + bucket.expects(:type=).with("mytype") + scope.to_trans end def test_namespaces - interp, scope, source = mkclassframing + parser, scope, source = mkclassframing assert_equal([""], scope.namespaces, "Started out with incorrect namespaces") @@ -701,17 +663,17 @@ Host <<||>>" end def test_findclass_and_finddefine - interp = mkinterp + parser = mkparser - # Make sure our scope calls the interp findclass method with + # Make sure our scope calls the parser findclass method with # the right namespaces - scope = mkscope :interp => interp + scope = mkscope :parser => parser - interp.metaclass.send(:attr_accessor, :last) + parser.metaclass.send(:attr_accessor, :last) methods = [:findclass, :finddefine] methods.each do |m| - interp.meta_def(m) do |namespace, name| + parser.meta_def(m) do |namespace, name| @checked ||= [] @checked << [namespace, name] @@ -727,7 +689,7 @@ Host <<||>>" end test = proc do |should| - interp.last = scope.namespaces[-1] + parser.last = scope.namespaces[-1] methods.each do |method| result = scope.send(method, "testing") assert_equal(should, result, diff --git a/test/lib/puppettest/parsertesting.rb b/test/lib/puppettest/parsertesting.rb index d66367ada..368e112f9 100644 --- a/test/lib/puppettest/parsertesting.rb +++ b/test/lib/puppettest/parsertesting.rb @@ -5,6 +5,8 @@ module PuppetTest::ParserTesting include PuppetTest AST = Puppet::Parser::AST + Config = Puppet::Parser::Configuration + # A fake class that we can use for testing evaluation. class FakeAST attr_writer :evaluate @@ -39,6 +41,19 @@ module PuppetTest::ParserTesting ) end + def mkconfig(parser = nil) + require 'puppet/network/handler/node' + parser ||= mkparser + node = mknode + return Config.new(parser, node) + end + + def mknode(name = nil) + name ||= "nodename" + Puppet::Network::Handler.handler(:node) + Puppet::Network::Handler::Node::SimpleNode.new("nodename") + end + def mkinterp(args = {}) args[:Code] ||= "" unless args.include?(:Manifest) args[:Local] ||= true @@ -50,9 +65,9 @@ module PuppetTest::ParserTesting end def mkscope(hash = {}) - hash[:interp] ||= mkinterp - hash[:source] ||= (hash[:interp].findclass("", "") || - hash[:interp].newclass("")) + hash[:configuration] ||= mkconfig + hash[:parser] ||= mkparser + hash[:source] ||= (hash[:parser].findclass("", "") || hash[:parser].newclass("")) unless hash[:source] raise "Could not find source for scope" diff --git a/test/lib/puppettest/resourcetesting.rb b/test/lib/puppettest/resourcetesting.rb index 8cb59b83d..cbcfb0baf 100644 --- a/test/lib/puppettest/resourcetesting.rb +++ b/test/lib/puppettest/resourcetesting.rb @@ -1,25 +1,25 @@ module PuppetTest::ResourceTesting Parser = Puppet::Parser AST = Puppet::Parser::AST - def mkclassframing(interp = nil) - interp ||= mkinterp + def mkclassframing(parser = nil) + parser ||= mkparser - interp.newdefine("resource", :arguments => [%w{one}, %w{two value}, %w{three}]) - interp.newclass("") - source = interp.newclass("base") - interp.newclass("sub1", :parent => "base") - interp.newclass("sub2", :parent => "base") - interp.newclass("other") + parser.newdefine("resource", :arguments => [%w{one}, %w{two value}, %w{three}]) + parser.newclass("") + source = parser.newclass("base") + parser.newclass("sub1", :parent => "base") + parser.newclass("sub2", :parent => "base") + parser.newclass("other") - scope = Parser::Scope.new(:interp => interp) - scope.source = source + config = mkconfig(:parser => parser) + config.topscope.source = source - return interp, scope, source + return parser, config.topscope, source end - def mkevaltest(interp = nil) - interp ||= mkinterp - @interp.newdefine("evaltest", + def mkevaltest(parser = nil) + parser ||= mkparser + @parser.newdefine("evaltest", :arguments => [%w{one}, ["two", stringobj("755")]], :code => resourcedef("file", "/tmp", "owner" => varref("one"), "mode" => varref("two")) @@ -27,26 +27,14 @@ module PuppetTest::ResourceTesting end def mkresource(args = {}) - - if args[:scope] and ! args[:source] - args[:source] = args[:scope].source - end - - unless args[:scope] - unless defined? @scope - raise "Must set @scope to mkresource" - end - end + args[:source] ||= "source" + args[:scope] ||= "scope" {:type => "resource", :title => "testing", - :source => @source, :scope => @scope}.each do |param, value| + :source => "source", :scope => "scope"}.each do |param, value| args[param] ||= value end - unless args[:source].is_a?(Puppet::Parser::AST::HostClass) - args[:source] = args[:scope].findclass(args[:source]) - end - params = args[:params] || {:one => "yay", :three => "rah"} if args[:params] == :none args.delete(:params) diff --git a/test/network/handler/master.rb b/test/network/handler/master.rb index 08e17373b..9cf52b1cd 100755 --- a/test/network/handler/master.rb +++ b/test/network/handler/master.rb @@ -8,56 +8,6 @@ require 'puppet/network/handler/master' class TestMaster < Test::Unit::TestCase include PuppetTest::ServerTest - # run through all of the existing test files and make sure everything - # works - def test_files - count = 0 - textfiles { |file| - Puppet.debug("parsing %s" % file) - client = nil - master = nil - - # create our master - assert_nothing_raised() { - # this is the default server setup - master = Puppet::Network::Handler.master.new( - :Manifest => file, - :UseNodes => false, - :Local => true - ) - } - - # and our client - assert_nothing_raised() { - client = Puppet::Network::Client.master.new( - :Master => master - ) - } - - # pull our configuration a few times - assert_nothing_raised() { - client.getconfig - stopservices - Puppet::Type.allclear - } - assert_nothing_raised() { - client.getconfig - stopservices - Puppet::Type.allclear - } - assert_nothing_raised() { - client.getconfig - stopservices - Puppet::Type.allclear - } - # only test three files; that's plenty - if count > 3 - break - end - count += 1 - } - end - def test_defaultmanifest textfiles { |file| Puppet[:manifest] = file @@ -166,30 +116,6 @@ class TestMaster < Test::Unit::TestCase assert(FileTest.exists?(file2), "Second file %s does not exist" % file2) end - def test_addfacts - master = nil - file = mktestmanifest() - # create our master - assert_nothing_raised() { - # this is the default server setup - master = Puppet::Network::Handler.master.new( - :Manifest => file, - :UseNodes => false, - :Local => true - ) - } - - facts = {} - - assert_nothing_raised { - master.addfacts(facts) - } - - %w{serverversion servername serverip}.each do |fact| - assert(facts.include?(fact), "Fact %s was not set" % fact) - end - end - # Make sure we're using the hostname as configured with :node_name def test_hostname_in_getconfig master = nil |
