diff options
author | Luke Kanies <luke@puppetlabs.com> | 2011-07-15 11:54:33 -0700 |
---|---|---|
committer | Luke Kanies <luke@puppetlabs.com> | 2011-07-15 11:54:33 -0700 |
commit | d69bf48ecae71ff01679bb38cdeebc8f4a8b8b15 (patch) | |
tree | 6f6b25251f0a581c878b833a90e5b3bab0ac5d11 | |
parent | 4ad404ee7e7244d94ff4d87effc1a041d65b3f73 (diff) | |
parent | bdc0f8716ae8ccb2b2657dfab591afe9589d8902 (diff) | |
download | puppet-d69bf48ecae71ff01679bb38cdeebc8f4a8b8b15.tar.gz puppet-d69bf48ecae71ff01679bb38cdeebc8f4a8b8b15.tar.xz puppet-d69bf48ecae71ff01679bb38cdeebc8f4a8b8b15.zip |
Merge branch 'refactor/master/8232-array_indexers_on_scope'
27 files changed, 436 insertions, 313 deletions
diff --git a/lib/puppet/parser/ast/leaf.rb b/lib/puppet/parser/ast/leaf.rb index c8ebc9483..3efb52f63 100644 --- a/lib/puppet/parser/ast/leaf.rb +++ b/lib/puppet/parser/ast/leaf.rb @@ -124,10 +124,11 @@ class Puppet::Parser::AST # not include syntactical constructs, like '$' and '{}'). def evaluate(scope) parsewrap do - if (var = scope.lookupvar(@value, :file => file, :line => line)) == :undefined - var = :undef + if ! scope.include?(@value) + :undef + else + scope[@value, {:file => file, :line => line}] end - var end end @@ -141,7 +142,7 @@ class Puppet::Parser::AST def evaluate_container(scope) container = variable.respond_to?(:evaluate) ? variable.safeevaluate(scope) : variable - (container.is_a?(Hash) or container.is_a?(Array)) ? container : scope.lookupvar(container, :file => file, :line => line) + (container.is_a?(Hash) or container.is_a?(Array)) ? container : scope[container, {:file => file, :line => line}] end def evaluate_key(scope) diff --git a/lib/puppet/parser/compiler.rb b/lib/puppet/parser/compiler.rb index c1daade4c..06cd80a1e 100644 --- a/lib/puppet/parser/compiler.rb +++ b/lib/puppet/parser/compiler.rb @@ -139,19 +139,21 @@ class Puppet::Parser::Compiler # evaluated later in the process. def evaluate_classes(classes, scope, lazy_evaluate = true) raise Puppet::DevError, "No source for scope passed to evaluate_classes" unless scope.source - param_classes = nil + class_parameters = nil # if we are a param class, save the classes hash # and transform classes to be the keys if classes.class == Hash - param_classes = classes + class_parameters = classes classes = classes.keys end classes.each do |name| # If we can find the class, then make a resource that will evaluate it. if klass = scope.find_hostclass(name) - if param_classes - resource = klass.ensure_in_catalog(scope, param_classes[name] || {}) + # If parameters are passed, then attempt to create a duplicate resource + # so the appropriate error is thrown. + if class_parameters + resource = klass.ensure_in_catalog(scope, class_parameters[name] || {}) else next if scope.class_scope(klass) resource = klass.ensure_in_catalog(scope) @@ -450,7 +452,7 @@ class Puppet::Parser::Compiler # 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) + @topscope[param] = value end # These might be nil. @@ -473,7 +475,7 @@ class Puppet::Parser::Compiler Puppet.settings.each do |name, setting| next if name.to_s == "name" - scope.setvar name.to_s, environment[name] + scope[name.to_s] = environment[name] end end diff --git a/lib/puppet/parser/functions.rb b/lib/puppet/parser/functions.rb index e19ac127f..22eee70d7 100644 --- a/lib/puppet/parser/functions.rb +++ b/lib/puppet/parser/functions.rb @@ -29,8 +29,11 @@ module Puppet::Parser::Functions Environment = Puppet::Node::Environment def self.environment_module(env = nil) + if env and ! env.is_a?(Puppet::Node::Environment) + env = Puppet::Node::Environment.new(env) + end @modules.synchronize { - @modules[ env || Environment.current || Environment.root ] ||= Module.new + @modules[ (env || Environment.current || Environment.root).name ] ||= Module.new } end diff --git a/lib/puppet/parser/functions/extlookup.rb b/lib/puppet/parser/functions/extlookup.rb index 5fbf26cec..9ffca59a7 100644 --- a/lib/puppet/parser/functions/extlookup.rb +++ b/lib/puppet/parser/functions/extlookup.rb @@ -91,9 +91,9 @@ This is for back compatibility to interpolate variables with %. % interpolation raise Puppet::ParseError, ("extlookup(): wrong number of arguments (#{args.length}; must be <= 3)") if args.length > 3 - extlookup_datadir = undef_as('',lookupvar('::extlookup_datadir')) + extlookup_datadir = undef_as('',self['::extlookup_datadir']) - extlookup_precedence = undef_as([],lookupvar('::extlookup_precedence')).collect { |var| var.gsub(/%\{(.+?)\}/) { lookupvar("::#{$1}") } } + extlookup_precedence = undef_as([],self['::extlookup_precedence']).collect { |var| var.gsub(/%\{(.+?)\}/) { self["::#{$1}"] } } datafiles = Array.new @@ -121,9 +121,9 @@ This is for back compatibility to interpolate variables with %. % interpolation if result[0].length == 2 val = result[0][1].to_s - # parse %{}'s in the CSV into local variables using lookupvar() + # parse %{}'s in the CSV into local variables using the current scope while val =~ /%\{(.+?)\}/ - val.gsub!(/%\{#{$1}\}/, lookupvar($1)) + val.gsub!(/%\{#{$1}\}/, self[$1]) end desired = val @@ -134,9 +134,9 @@ This is for back compatibility to interpolate variables with %. % interpolation # Individual cells in a CSV result are a weird data type and throws # puppets yaml parsing, so just map it all to plain old strings desired = cells.map do |c| - # parse %{}'s in the CSV into local variables using lookupvar() + # parse %{}'s in the CSV into local variables using the current scope while c =~ /%\{(.+?)\}/ - c.gsub!(/%\{#{$1}\}/, lookupvar($1)) + c.gsub!(/%\{#{$1}\}/, self[$1]) end c.to_s diff --git a/lib/puppet/parser/functions/fqdn_rand.rb b/lib/puppet/parser/functions/fqdn_rand.rb index 93ab98bcd..668802e73 100644 --- a/lib/puppet/parser/functions/fqdn_rand.rb +++ b/lib/puppet/parser/functions/fqdn_rand.rb @@ -7,6 +7,6 @@ Puppet::Parser::Functions::newfunction(:fqdn_rand, :type => :rvalue, :doc => $random_number_seed = fqdn_rand(30,30)") do |args| require 'digest/md5' max = args.shift - srand(Digest::MD5.hexdigest([lookupvar('::fqdn'),args].join(':')).hex) + srand(Digest::MD5.hexdigest([self['::fqdn'],args].join(':')).hex) rand(max).to_s end diff --git a/lib/puppet/parser/functions/versioncmp.rb b/lib/puppet/parser/functions/versioncmp.rb index 6091e0923..e4edb151e 100644 --- a/lib/puppet/parser/functions/versioncmp.rb +++ b/lib/puppet/parser/functions/versioncmp.rb @@ -1,10 +1,8 @@ require 'puppet/util/package' - Puppet::Parser::Functions::newfunction( - :versioncmp, :type => :rvalue, - - :doc => "Compares two versions +Puppet::Parser::Functions::newfunction( :versioncmp, :type => :rvalue, +:doc => "Compares two versions Prototype: diff --git a/lib/puppet/parser/resource.rb b/lib/puppet/parser/resource.rb index 3bb5f8601..56887c357 100644 --- a/lib/puppet/parser/resource.rb +++ b/lib/puppet/parser/resource.rb @@ -173,7 +173,7 @@ class Puppet::Parser::Resource < Puppet::Resource :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" + raise ArgumentError, "Received incomplete information - no value provided for parameter #{param}" end tag(*param.value) if param.name == :tag @@ -258,7 +258,8 @@ class Puppet::Parser::Resource < Puppet::Resource def add_backward_compatible_relationship_param(name) # Skip metaparams for which we get no value. - return unless val = scope.lookupvar(name.to_s) and val != :undefined + return unless scope.include?(name.to_s) + val = scope[name.to_s] # The default case: just set the value set_parameter(name, val) and return unless @parameters[name] diff --git a/lib/puppet/parser/scope.rb b/lib/puppet/parser/scope.rb index ed67cd141..9d84c7e65 100644 --- a/lib/puppet/parser/scope.rb +++ b/lib/puppet/parser/scope.rb @@ -48,13 +48,42 @@ class Puppet::Parser::Scope end end + def [](name, options = {}) + table = ephemeral?(name) ? @ephemeral.last : @symtable + # If the variable is qualified, then find the specified scope and look the variable up there instead. + if name =~ /^(.*)::(.+)$/ + begin + qualified_scope($1)[$2,options] + rescue RuntimeError => e + location = (options[:file] && options[:line]) ? " at #{options[:file]}:#{options[:line]}" : '' + warning "Could not look up qualified variable '#{name}'; #{e.message}#{location}" + nil + end + elsif ephemeral_include?(name) or table.include?(name) + # We can't use "if table[name]" here because the value might be false + if options[:dynamic] and self != compiler.topscope + location = (options[:file] && options[:line]) ? " at #{options[:file]}:#{options[:line]}" : '' + Puppet.deprecation_warning "Dynamic lookup of $#{name}#{location} is deprecated. Support will be removed in Puppet 2.8. Use a fully-qualified variable name (e.g., $classname::variable) or parameterized classes." + end + table[name] + elsif parent + parent[name,options.merge(:dynamic => (dynamic || options[:dynamic]))] + else + nil + end + end + + def []=(var, value) + setvar(var, value) + end + # A demeterific shortcut to the catalog. def catalog compiler.catalog end - def environment - compiler.environment + def each + to_hash.each { |name, value| yield(name, value) } end # Proxy accessors @@ -62,6 +91,10 @@ class Puppet::Parser::Scope @compiler.node.name end + def include?(name) + ! self[name].nil? + end + # Is the value true? This allows us to control the definition of truth # in one place. def self.true?(value) @@ -101,7 +134,7 @@ class Puppet::Parser::Scope # Remove this when rebasing def environment - compiler ? compiler.environment : nil + compiler ? compiler.environment : Puppet::Node::Environment.new end def find_hostclass(name) @@ -211,7 +244,11 @@ class Puppet::Parser::Scope end def undef_as(x,v) - (v == :undefined) ? x : (v == :undef) ? x : v + if v.nil? or v == :undef + x + else + v + end end def qualified_scope(classname) @@ -223,29 +260,9 @@ class Puppet::Parser::Scope private :qualified_scope # Look up a variable. The simplest value search we do. + # This method is effectively deprecated - use self[] instead. def lookupvar(name, options = {}) - table = ephemeral?(name) ? @ephemeral.last : @symtable - # If the variable is qualified, then find the specified scope and look the variable up there instead. - if name =~ /^(.*)::(.+)$/ - begin - qualified_scope($1).lookupvar($2,options) - rescue RuntimeError => e - location = (options[:file] && options[:line]) ? " at #{options[:file]}:#{options[:line]}" : '' - warning "Could not look up qualified variable '#{name}'; #{e.message}#{location}" - :undefined - end - elsif ephemeral_include?(name) or table.include?(name) - # We can't use "if table[name]" here because the value might be false - if options[:dynamic] and self != compiler.topscope - location = (options[:file] && options[:line]) ? " at #{options[:file]}:#{options[:line]}" : '' - Puppet.deprecation_warning "Dynamic lookup of $#{name}#{location} is deprecated. Support will be removed in Puppet 2.8. Use a fully-qualified variable name (e.g., $classname::variable) or parameterized classes." - end - table[name] - elsif parent - parent.lookupvar(name,options.merge(:dynamic => (dynamic || options[:dynamic]))) - else - :undefined - end + self[name, options] end # Return a hash containing our variables and their values, optionally (and @@ -312,6 +329,8 @@ 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. + # It's preferred that you use self[]= instead of this; only use this + # when you need to set options. def setvar(name,value, options = {}) table = options[:ephemeral] ? @ephemeral.last : @symtable if table.include?(name) @@ -329,7 +348,7 @@ class Puppet::Parser::Scope table[name] = value else # append case # lookup the value in the scope if it exists and insert the var - table[name] = undef_as('',lookupvar(name)) + table[name] = undef_as('',self[name]) # concatenate if string, append if array, nothing for other types case value when Array @@ -443,6 +462,6 @@ class Puppet::Parser::Scope def extend_with_functions_module extend Puppet::Parser::Functions.environment_module(Puppet::Node::Environment.root) - extend Puppet::Parser::Functions.environment_module(environment) + extend Puppet::Parser::Functions.environment_module(environment) if environment != Puppet::Node::Environment.root end end diff --git a/lib/puppet/parser/templatewrapper.rb b/lib/puppet/parser/templatewrapper.rb index 27d75bf92..9336e704d 100644 --- a/lib/puppet/parser/templatewrapper.rb +++ b/lib/puppet/parser/templatewrapper.rb @@ -25,7 +25,7 @@ class Puppet::Parser::TemplateWrapper # Should return true if a variable is defined, false if it is not def has_variable?(name) - scope.lookupvar(name.to_s, :file => file, :line => script_line) != :undefined + scope.include?(name.to_s) end # Allow templates to access the defined classes @@ -56,9 +56,8 @@ class Puppet::Parser::TemplateWrapper # the missing_method definition here until we declare the syntax finally # dead. def method_missing(name, *args) - value = scope.lookupvar(name.to_s,:file => file,:line => script_line) - if value != :undefined - return value + if scope.include?(name.to_s) + return scope[name.to_s, {:file => file,:line => script_line}] else # Just throw an error immediately, instead of searching for # other missingmethod things or whatever. diff --git a/lib/puppet/resource.rb b/lib/puppet/resource.rb index 59e387d00..217eb11c8 100644 --- a/lib/puppet/resource.rb +++ b/lib/puppet/resource.rb @@ -343,6 +343,26 @@ class Puppet::Resource [ type, title ].join('/') end + def set_default_parameters(scope) + return [] unless resource_type and resource_type.respond_to?(:arguments) + + result = [] + + resource_type.arguments.each do |param, default| + param = param.to_sym + next if parameters.include?(param) + unless is_a?(Puppet::Parser::Resource) + fail Puppet::DevError, "Cannot evaluate default parameters for #{self} - not a parser resource" + end + + next if default.nil? + + self[param] = default.safeevaluate(scope) + result << param + end + result + end + def to_resource self end @@ -351,6 +371,19 @@ class Puppet::Resource resource_type.valid_parameter?(name) end + # Verify that all required arguments are either present or + # have been provided with defaults. + # Must be called after 'set_default_parameters'. We can't join the methods + # because Type#set_parameters needs specifically ordered behavior. + def validate_complete + return unless resource_type and resource_type.respond_to?(:arguments) + + resource_type.arguments.each do |param, default| + param = param.to_sym + fail Puppet::ParseError, "Must pass #{param} to #{self}" unless parameters.include?(param) + end + end + def validate_parameter(name) raise ArgumentError, "Invalid parameter #{name}" unless valid_parameter?(name) end diff --git a/lib/puppet/resource/type.rb b/lib/puppet/resource/type.rb index f8d820b77..8b154ce95 100644 --- a/lib/puppet/resource/type.rb +++ b/lib/puppet/resource/type.rb @@ -158,11 +158,7 @@ class Puppet::Resource::Type return resource end resource = Puppet::Parser::Resource.new(resource_type, name, :scope => scope, :source => self) - if parameters - parameters.each do |k,v| - resource.set_parameter(k,v) - end - end + assign_parameter_values(parameters, resource) instantiate_resource(scope, resource) scope.compiler.add_resource(scope, resource) resource @@ -188,6 +184,18 @@ class Puppet::Resource::Type @name.is_a?(Regexp) end + def assign_parameter_values(parameters, resource) + return unless parameters + scope = resource.scope || {} + + # It'd be nice to assign default parameter values here, + # but we can't because they often rely on local variables + # created during set_resource_parameters. + parameters.each do |name, value| + resource.set_parameter name, value + end + end + # MQR TODO: # # The change(s) introduced by the fix for #4270 are mostly silly & should be @@ -225,40 +233,32 @@ class Puppet::Resource::Type param = param.to_sym fail Puppet::ParseError, "#{resource.ref} does not accept attribute #{param}" unless valid_parameter?(param) - exceptwrap { scope.setvar(param.to_s, value) } + exceptwrap { scope[param.to_s] = value } set[param] = true end if @type == :hostclass - scope.setvar("title", resource.title.to_s.downcase) unless set.include? :title - scope.setvar("name", resource.name.to_s.downcase ) unless set.include? :name + scope["title"] = resource.title.to_s.downcase unless set.include? :title + scope["name"] = resource.name.to_s.downcase unless set.include? :name else - scope.setvar("title", resource.title ) unless set.include? :title - scope.setvar("name", resource.name ) unless set.include? :name + scope["title"] = resource.title unless set.include? :title + scope["name"] = resource.name unless set.include? :name end - scope.setvar("module_name", module_name) if module_name and ! set.include? :module_name + scope["module_name"] = module_name if module_name and ! set.include? :module_name if caller_name = scope.parent_module_name and ! set.include?(:caller_module_name) - scope.setvar("caller_module_name", caller_name) + scope["caller_module_name"] = caller_name end scope.class_set(self.name,scope) if hostclass? or node? - # Verify that all required arguments are either present or - # have been provided with defaults. - arguments.each do |param, default| - param = param.to_sym - next if set.include?(param) - - # Even if 'default' is a false value, it's an AST value, so this works fine - fail Puppet::ParseError, "Must pass #{param} to #{resource.ref}" unless default - value = default.safeevaluate(scope) - scope.setvar(param.to_s, value) - - # Set it in the resource, too, so the value makes it to the client. - resource[param] = value - end + # Evaluate the default parameters, now that all other variables are set + default_params = resource.set_default_parameters(scope) + default_params.each { |param| scope[param.to_s] = resource[param] } + # This has to come after the above parameters so that default values + # can use their values + resource.validate_complete end # Check whether a given argument is valid. diff --git a/spec/unit/parser/ast/casestatement_spec.rb b/spec/unit/parser/ast/casestatement_spec.rb index e21190706..a76a9ae1f 100755 --- a/spec/unit/parser/ast/casestatement_spec.rb +++ b/spec/unit/parser/ast/casestatement_spec.rb @@ -154,7 +154,7 @@ describe Puppet::Parser::AST::CaseStatement do tests.each do |should, values| values.each do |value| @scope = Puppet::Parser::Scope.new - @scope.setvar("testparam", value) + @scope['testparam'] = value result = ast.evaluate(@scope) result.should == should diff --git a/spec/unit/parser/ast/leaf_spec.rb b/spec/unit/parser/ast/leaf_spec.rb index ff3fed5e9..36c790a41 100755 --- a/spec/unit/parser/ast/leaf_spec.rb +++ b/spec/unit/parser/ast/leaf_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Puppet::Parser::AST::Leaf do before :each do - @scope = stub 'scope' + @scope = Puppet::Parser::Scope.new @value = stub 'value' @leaf = Puppet::Parser::AST::Leaf.new(:value => @value) end @@ -56,7 +56,7 @@ end describe Puppet::Parser::AST::Concat do describe "when evaluating" do before :each do - @scope = stub_everything 'scope' + @scope = Puppet::Parser::Scope.new end it "should interpolate variables and concatenate their values" do one = Puppet::Parser::AST::String.new(:value => "one") @@ -86,7 +86,7 @@ end describe Puppet::Parser::AST::Undef do before :each do - @scope = stub 'scope' + @scope = Puppet::Parser::Scope.new @undef = Puppet::Parser::AST::Undef.new(:value => :undef) end @@ -101,12 +101,12 @@ end describe Puppet::Parser::AST::HashOrArrayAccess do before :each do - @scope = stub 'scope' + @scope = Puppet::Parser::Scope.new end describe "when evaluating" do it "should evaluate the variable part if necessary" do - @scope.stubs(:lookupvar).with { |name,options| name == 'a'}.returns(["b"]) + @scope["a"] = ["b"] variable = stub 'variable', :evaluate => "a" access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => variable, :key => 0 ) @@ -117,7 +117,7 @@ describe Puppet::Parser::AST::HashOrArrayAccess do end it "should evaluate the access key part if necessary" do - @scope.stubs(:lookupvar).with { |name,options| name == 'a'}.returns(["b"]) + @scope["a"] = ["b"] index = stub 'index', :evaluate => 0 access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => index ) @@ -128,7 +128,7 @@ describe Puppet::Parser::AST::HashOrArrayAccess do end it "should be able to return an array member" do - @scope.stubs(:lookupvar).with { |name,options| name == 'a'}.returns(["val1", "val2", "val3"]) + @scope["a"] = %w{val1 val2 val3} access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => 1 ) @@ -136,7 +136,7 @@ describe Puppet::Parser::AST::HashOrArrayAccess do end it "should be able to return an array member when index is a stringified number" do - @scope.stubs(:lookupvar).with { |name,options| name == "a" }.returns(["val1", "val2", "val3"]) + @scope["a"] = %w{val1 val2 val3} access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "1" ) @@ -144,7 +144,7 @@ describe Puppet::Parser::AST::HashOrArrayAccess do end it "should raise an error when accessing an array with a key" do - @scope.stubs(:lookupvar).with { |name,options| name == "a"}.returns(["val1", "val2", "val3"]) + @scope["a"] = ["val1", "val2", "val3"] access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "get_me_the_second_element_please" ) @@ -152,7 +152,7 @@ describe Puppet::Parser::AST::HashOrArrayAccess do end it "should be able to return an hash value" do - @scope.stubs(:lookupvar).with { |name,options| name == 'a'}.returns({ "key1" => "val1", "key2" => "val2", "key3" => "val3" }) + @scope["a"] = { "key1" => "val1", "key2" => "val2", "key3" => "val3" } access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "key2" ) @@ -160,7 +160,7 @@ describe Puppet::Parser::AST::HashOrArrayAccess do end it "should be able to return an hash value with a numerical key" do - @scope.stubs(:lookupvar).with { |name,options| name == "a"}.returns({ "key1" => "val1", "key2" => "val2", "45" => "45", "key3" => "val3" }) + @scope["a"] = { "key1" => "val1", "key2" => "val2", "45" => "45", "key3" => "val3" } access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "45" ) @@ -168,7 +168,7 @@ describe Puppet::Parser::AST::HashOrArrayAccess do end it "should raise an error if the variable lookup didn't return an hash or an array" do - @scope.stubs(:lookupvar).with { |name,options| name == "a"}.returns("I'm a string") + @scope["a"] = "I'm a string" access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "key2" ) @@ -176,8 +176,6 @@ describe Puppet::Parser::AST::HashOrArrayAccess do end it "should raise an error if the variable wasn't in the scope" do - @scope.stubs(:lookupvar).with { |name,options| name == 'a'}.returns(nil) - access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "key2" ) lambda { access.evaluate(@scope) }.should raise_error @@ -189,7 +187,7 @@ describe Puppet::Parser::AST::HashOrArrayAccess do end it "should work with recursive hash access" do - @scope.stubs(:lookupvar).with { |name,options| name == 'a'}.returns({ "key" => { "subkey" => "b" }}) + @scope["a"] = { "key" => { "subkey" => "b" }} access1 = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "key") access2 = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => access1, :key => "subkey") @@ -198,7 +196,7 @@ describe Puppet::Parser::AST::HashOrArrayAccess do end it "should work with interleaved array and hash access" do - @scope.stubs(:lookupvar).with { |name,options| name == 'a'}.returns({ "key" => [ "a" , "b" ]}) + @scope['a'] = { "key" => [ "a" , "b" ]} access1 = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "key") access2 = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => access1, :key => 1) @@ -210,16 +208,16 @@ describe Puppet::Parser::AST::HashOrArrayAccess do describe "when assigning" do it "should add a new key and value" do scope = Puppet::Parser::Scope.new - scope.setvar("a", { 'a' => 'b' }) + scope['a'] = { 'a' => 'b' } access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "b") access.assign(scope, "c" ) - scope.lookupvar("a").should be_include("b") + scope['a'].should be_include("b") end it "should raise an error when assigning an array element with a key" do - @scope.stubs(:lookupvar).with { |name,options| name == "a"}.returns([]) + @scope['a'] = [] access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "get_me_the_second_element_please" ) @@ -228,16 +226,16 @@ describe Puppet::Parser::AST::HashOrArrayAccess do it "should be able to return an array member when index is a stringified number" do scope = Puppet::Parser::Scope.new - scope.setvar("a", []) + scope['a'] = [] access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "0" ) access.assign(scope, "val2") - scope.lookupvar("a").should == ["val2"] + scope['a'].should == ["val2"] end it "should raise an error when trying to overwrite an hash value" do - @scope.stubs(:lookupvar).with { |name,options| name == "a" }.returns({ "key" => [ "a" , "b" ]}) + @scope['a'] = { "key" => [ "a" , "b" ]} access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "key") lambda { access.assign(@scope, "test") }.should raise_error @@ -247,7 +245,7 @@ end describe Puppet::Parser::AST::Regex do before :each do - @scope = stub 'scope' + @scope = Puppet::Parser::Scope.new end describe "when initializing" do @@ -330,22 +328,21 @@ end describe Puppet::Parser::AST::Variable do before :each do - @scope = stub 'scope' + @scope = Puppet::Parser::Scope.new @var = Puppet::Parser::AST::Variable.new(:value => "myvar", :file => 'my.pp', :line => 222) end it "should lookup the variable in scope" do - @scope.expects(:lookupvar).with { |name,options| name == "myvar" }.returns(:myvalue) + @scope["myvar"] = :myvalue @var.safeevaluate(@scope).should == :myvalue end it "should pass the source location to lookupvar" do - @scope.expects(:lookupvar).with { |name,options| name == "myvar" and options[:file] == 'my.pp' and options[:line] == 222 }.returns(:myvalue) + @scope.setvar("myvar", :myvalue, :file => 'my.pp', :line => 222 ) @var.safeevaluate(@scope).should == :myvalue end it "should return undef if the variable wasn't set" do - @scope.expects(:lookupvar).with { |name,options| name == "myvar" }.returns(:undefined) @var.safeevaluate(@scope).should == :undef end @@ -359,7 +356,7 @@ end describe Puppet::Parser::AST::HostName do before :each do - @scope = stub 'scope' + @scope = Puppet::Parser::Scope.new @value = stub 'value', :=~ => false @value.stubs(:to_s).returns(@value) @value.stubs(:downcase).returns(@value) diff --git a/spec/unit/parser/ast/resource_reference_spec.rb b/spec/unit/parser/ast/resource_reference_spec.rb index 4d1c191cf..4e069cca0 100755 --- a/spec/unit/parser/ast/resource_reference_spec.rb +++ b/spec/unit/parser/ast/resource_reference_spec.rb @@ -36,7 +36,7 @@ describe Puppet::Parser::AST::ResourceReference do end it "should return an array of resources if given a variable containing an array of titles" do - @scope.setvar("my_files", ["foo", "bar"]) + @scope["my_files"] = ["foo", "bar"] titles = Puppet::Parser::AST::Variable.new(:value => "my_files") ref = newref('File', titles) ref.evaluate(@scope).should == [ diff --git a/spec/unit/parser/compiler_spec.rb b/spec/unit/parser/compiler_spec.rb index fcce9f6f4..e6f481114 100755 --- a/spec/unit/parser/compiler_spec.rb +++ b/spec/unit/parser/compiler_spec.rb @@ -177,8 +177,8 @@ describe Puppet::Parser::Compiler do @node.stubs(:parameters).returns(params) compile_stub(:set_node_parameters) @compiler.compile - @compiler.topscope.lookupvar("a").should == "b" - @compiler.topscope.lookupvar("c").should == "d" + @compiler.topscope['a'].should == "b" + @compiler.topscope['c'].should == "d" end it "should set the client and server versions on the catalog" do @@ -571,42 +571,62 @@ describe Puppet::Parser::Compiler do @compiler.evaluate_classes(%w{myclass}, @scope) end - it "should ensure each node class hash is in catalog and have appropriate parameters", :'fails_on_ruby_1.9.2' => true do - klasses = {'foo'=>{'1'=>'one'}, 'bar::foo'=>{'2'=>'two'}, 'bar'=>{'1'=> [1,2,3], '2'=>{'foo'=>'bar'}}} - @node.classes = klasses - ast_obj = Puppet::Parser::AST::String.new(:value => 'foo') - klasses.each do |name, params| - klass = Puppet::Resource::Type.new(:hostclass, name, :arguments => {'1' => ast_obj, '2' => ast_obj}) + describe "and the classes are specified as a hash with parameters" do + before do + @node.classes = {} + @ast_obj = Puppet::Parser::AST::String.new(:value => 'foo') + end + + # Define the given class with default parameters + def define_class(name, parameters) + @node.classes[name] = parameters + klass = Puppet::Resource::Type.new(:hostclass, name, :arguments => {'1' => @ast_obj, '2' => @ast_obj}) @compiler.topscope.known_resource_types.add klass end - catalog = @compiler.compile - catalog.classes.should =~ ['foo', 'bar::foo', 'settings', 'bar'] - r1 = catalog.resources.detect {|r| r.title == 'Foo' } - r1.to_hash.should == {:'1' => 'one', :'2' => 'foo'} - r1.tags. should =~ ['class', 'foo'] + def compile + @catalog = @compiler.compile + end - r2 = catalog.resources.detect {|r| r.title == 'Bar::Foo' } - r2.to_hash.should == {:'1' => 'foo', :'2' => 'two'} - r2.tags.should =~ ['bar::foo', 'class', 'bar', 'foo'] + it "should record which classes are evaluated" do + classes = {'foo'=>{}, 'bar::foo'=>{}, 'bar'=>{}} + classes.each { |c, params| define_class(c, params) } + compile() + classes.each { |name, p| @catalog.classes.should include(name) } + end - r2 = catalog.resources.detect {|r| r.title == 'Bar' } - r2.to_hash.should == {:'1' => [1,2,3], :'2' => {'foo'=>'bar'}} - r2.tags.should =~ ['class', 'bar'] - end + it "should provide default values for parameters that have no values specified" do + define_class('foo', {}) + compile() + @catalog.resource(:class, 'foo')['1'].should == "foo" + end - it "should ensure each node class is in catalog and has appropriate tags", :'fails_on_ruby_1.9.2' => true do - klasses = ['bar::foo'] - @node.classes = klasses - ast_obj = Puppet::Parser::AST::String.new(:value => 'foo') - klasses.each do |name| - klass = Puppet::Resource::Type.new(:hostclass, name, :arguments => {'1' => ast_obj, '2' => ast_obj}) - @compiler.topscope.known_resource_types.add klass + it "should use any provided values" do + define_class('foo', {'1' => 'real_value'}) + compile() + @catalog.resource(:class, 'foo')['1'].should == "real_value" + end + + it "should support providing some but not all values" do + define_class('foo', {'1' => 'real_value'}) + compile() + @catalog.resource(:class, 'Foo')['1'].should == "real_value" + @catalog.resource(:class, 'Foo')['2'].should == "foo" end - catalog = @compiler.compile - r2 = catalog.resources.detect {|r| r.title == 'Bar::Foo' } - r2.tags.should =~ ['bar::foo', 'class', 'bar', 'foo'] + it "should ensure each node class is in catalog and has appropriate tags", :'fails_on_ruby_1.9.2' => true do + klasses = ['bar::foo'] + @node.classes = klasses + ast_obj = Puppet::Parser::AST::String.new(:value => 'foo') + klasses.each do |name| + klass = Puppet::Resource::Type.new(:hostclass, name, :arguments => {'1' => ast_obj, '2' => ast_obj}) + @compiler.topscope.known_resource_types.add klass + end + catalog = @compiler.compile + + r2 = catalog.resources.detect {|r| r.title == 'Bar::Foo' } + r2.tags.should =~ ['bar::foo', 'class', 'bar', 'foo'] + end end it "should fail if required parameters are missing" do @@ -614,15 +634,15 @@ describe Puppet::Parser::Compiler do @node.classes = klass klass = Puppet::Resource::Type.new(:hostclass, 'foo', :arguments => {'1' => nil, '2' => nil}) @compiler.topscope.known_resource_types.add klass - lambda { @compiler.compile }.should raise_error Puppet::ParseError, "Must pass 2 to Class[Foo]" + lambda { @compiler.compile }.should raise_error(Puppet::ParseError, "Must pass 2 to Class[Foo]") end it "should fail if invalid parameters are passed" do klass = {'foo'=>{'3'=>'one'}} @node.classes = klass - klass = Puppet::Resource::Type.new(:hostclass, 'foo', :arguments => {'1' => nil, '2' => nil}) + klass = Puppet::Resource::Type.new(:hostclass, 'foo', :arguments => {}) @compiler.topscope.known_resource_types.add klass - lambda { @compiler.compile }.should raise_error Puppet::ParseError, "Invalid parameter 3" + lambda { @compiler.compile }.should raise_error(Puppet::ParseError, "Invalid parameter 3") end it "should ensure class is in catalog without params" do diff --git a/spec/unit/parser/functions/create_resources_spec.rb b/spec/unit/parser/functions/create_resources_spec.rb index da76e75d0..94b1e7c68 100755 --- a/spec/unit/parser/functions/create_resources_spec.rb +++ b/spec/unit/parser/functions/create_resources_spec.rb @@ -78,7 +78,7 @@ notify{test:} end it 'should fail if defines are missing params' do @scope.function_create_resources(['foo', {'blah'=>{}}]) - lambda { @scope.compiler.compile }.should raise_error(Puppet::ParseError, 'Must pass one to Foo[blah] at line 1') + lambda { @scope.compiler.compile }.should raise_error(Puppet::ParseError, /Must pass one to Foo\[blah\]/) end it 'should be able to add multiple defines' do hash = {} diff --git a/spec/unit/parser/functions/extlookup_spec.rb b/spec/unit/parser/functions/extlookup_spec.rb index f68daaf3f..30962e137 100755 --- a/spec/unit/parser/functions/extlookup_spec.rb +++ b/spec/unit/parser/functions/extlookup_spec.rb @@ -64,7 +64,7 @@ describe "the extlookup function" do describe "should look in $extlookup_datadir for data files listed by $extlookup_precedence" do before do - @scope.stubs(:lookupvar).with('::extlookup_datadir').returns("/tmp") + @scope.stubs(:[]).with('::extlookup_datadir').returns("/tmp") File.open("/tmp/one.csv","w"){|one| one.puts "key,value1" } File.open("/tmp/two.csv","w") do |two| two.puts "key,value2" @@ -73,21 +73,21 @@ describe "the extlookup function" do end it "when the key is in the first file" do - @scope.stubs(:lookupvar).with('::extlookup_precedence').returns(["one","two"]) + @scope.stubs(:[]).with('::extlookup_precedence').returns(["one","two"]) result = @scope.function_extlookup([ "key" ]) result.should == "value1" end it "when the key is in the second file" do - @scope.stubs(:lookupvar).with('::extlookup_precedence').returns(["one","two"]) + @scope.stubs(:[]).with('::extlookup_precedence').returns(["one","two"]) result = @scope.function_extlookup([ "key2" ]) result.should == "value_two" end it "should not modify extlookup_precedence data" do variable = '%{fqdn}' - @scope.stubs(:lookupvar).with('::extlookup_precedence').returns([variable,"one"]) - @scope.stubs(:lookupvar).with('::fqdn').returns('myfqdn') + @scope.stubs(:[]).with('::extlookup_precedence').returns([variable,"one"]) + @scope.stubs(:[]).with('::fqdn').returns('myfqdn') result = @scope.function_extlookup([ "key" ]) variable.should == '%{fqdn}' end diff --git a/spec/unit/parser/functions/fqdn_rand_spec.rb b/spec/unit/parser/functions/fqdn_rand_spec.rb index 90fc0ef41..53c498453 100755 --- a/spec/unit/parser/functions/fqdn_rand_spec.rb +++ b/spec/unit/parser/functions/fqdn_rand_spec.rb @@ -8,6 +8,7 @@ describe "the fqdn_rand function" do before :each do @scope = Puppet::Parser::Scope.new + @scope[:fqdn] = "127.0.0.1" end it "should exist" do @@ -15,49 +16,40 @@ describe "the fqdn_rand function" do end it "should handle 0 arguments" do - @scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1") lambda { @scope.function_fqdn_rand([]) }.should_not raise_error(Puppet::ParseError) end it "should handle 1 argument'}" do - @scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1") lambda { @scope.function_fqdn_rand([3]) }.should_not raise_error(Puppet::ParseError) end (1..10).each { |n| it "should handle #{n} additional arguments" do - @scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1") lambda { @scope.function_fqdn_rand([3,1,2,3,4,5,6,7,8,9,10][0..n]) }.should_not raise_error(Puppet::ParseError) end it "should handle #{n} additional string arguments" do - @scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1") lambda { @scope.function_fqdn_rand([3,%w{ 1 2 3 4 5 6 7 8 9 10}].flatten[0..n]) }.should_not raise_error(Puppet::ParseError) end } it "should return a value less than max" do - @scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1") @scope.function_fqdn_rand([3]).should satisfy {|n| n.to_i < 3 } end it "should return the same values on subsequent invocations for the same host" do - @scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1").twice @scope.function_fqdn_rand([3,4]).should eql(@scope.function_fqdn_rand([3, 4])) end it "should return different sequences of value for different hosts" do - @scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1") val1 = @scope.function_fqdn_rand([10000000,4]) - @scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.2") + @scope.expects(:[]).with("::fqdn").returns("127.0.0.2") val2 = @scope.function_fqdn_rand([10000000,4]) val1.should_not eql(val2) end it "should return different values for the same hosts with different seeds" do - @scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1") val1 = @scope.function_fqdn_rand([10000000,4]) - @scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1") val2 = @scope.function_fqdn_rand([10000000,42]) val1.should_not eql(val2) end diff --git a/spec/unit/parser/functions_spec.rb b/spec/unit/parser/functions_spec.rb index 8240a184c..7eb6f299b 100755 --- a/spec/unit/parser/functions_spec.rb +++ b/spec/unit/parser/functions_spec.rb @@ -20,13 +20,17 @@ describe Puppet::Parser::Functions do end it "should have a method for returning an environment-specific module" do - Puppet::Parser::Functions.environment_module("myenv").should be_instance_of(Module) + Puppet::Parser::Functions.environment_module(Puppet::Node::Environment.new("myenv")).should be_instance_of(Module) end it "should use the current default environment if no environment is provided" do Puppet::Parser::Functions.environment_module.should be_instance_of(Module) end + it "should be able to retrieve environment modules asked for by name rather than instance" do + Puppet::Parser::Functions.environment_module(Puppet::Node::Environment.new("myenv")).should equal(Puppet::Parser::Functions.environment_module("myenv")) + end + describe "when calling newfunction" do before do @module = Module.new diff --git a/spec/unit/parser/resource_spec.rb b/spec/unit/parser/resource_spec.rb index 1190716d7..8513b8997 100755 --- a/spec/unit/parser/resource_spec.rb +++ b/spec/unit/parser/resource_spec.rb @@ -271,7 +271,7 @@ describe Puppet::Parser::Resource do end it "should not copy relationship metaparams when not in metaparam compatibility mode" do - @scope.setvar("require", "bar") + @scope['require'] = "bar" @resource.stubs(:metaparam_compatibility_mode?).returns false @resource.class.publicize_methods(:add_metaparams) { @resource.add_metaparams } @@ -280,7 +280,7 @@ describe Puppet::Parser::Resource do end it "should copy relationship metaparams when in metaparam compatibility mode" do - @scope.setvar("require", "bar") + @scope['require'] = "bar" @resource.stubs(:metaparam_compatibility_mode?).returns true @resource.class.publicize_methods(:add_metaparams) { @resource.add_metaparams } @@ -290,7 +290,7 @@ describe Puppet::Parser::Resource do it "should stack relationship metaparams when in metaparam compatibility mode" do @resource.set_parameter("require", "foo") - @scope.setvar("require", "bar") + @scope['require'] = "bar" @resource.stubs(:metaparam_compatibility_mode?).returns true @resource.class.publicize_methods(:add_metaparams) { @resource.add_metaparams } diff --git a/spec/unit/parser/scope_spec.rb b/spec/unit/parser/scope_spec.rb index 5308856ed..3c0d15cd7 100755 --- a/spec/unit/parser/scope_spec.rb +++ b/spec/unit/parser/scope_spec.rb @@ -42,12 +42,16 @@ describe Puppet::Parser::Scope do end it "should get its environment from its compiler" do - env = stub 'environment' + env = Puppet::Node::Environment.new compiler = stub 'compiler', :environment => env scope = Puppet::Parser::Scope.new :compiler => compiler scope.environment.should equal(env) end + it "should use the default environment if none is available" do + Puppet::Parser::Scope.new.environment.should equal(Puppet::Node::Environment.new) + end + it "should use the resource type collection helper to find its known resource types" do Puppet::Parser::Scope.ancestors.should include(Puppet::Resource::TypeCollectionHelper) end @@ -55,22 +59,18 @@ describe Puppet::Parser::Scope do describe "when initializing" do it "should extend itself with its environment's Functions module as well as the default" do env = Puppet::Node::Environment.new("myenv") + root = Puppet::Node::Environment.root compiler = stub 'compiler', :environment => env - mod = Module.new - root_mod = Module.new - Puppet::Parser::Functions.expects(:environment_module).with(Puppet::Node::Environment.root).returns root_mod - Puppet::Parser::Functions.expects(:environment_module).with(env).returns mod - Puppet::Parser::Scope.new(:compiler => compiler).singleton_class.ancestors.should be_include(mod) + scope = Puppet::Parser::Scope.new(:compiler => compiler) + scope.singleton_class.ancestors.should be_include(Puppet::Parser::Functions.environment_module(env)) + scope.singleton_class.ancestors.should be_include(Puppet::Parser::Functions.environment_module(root)) end - it "should extend itself with the default Functions module if it has no environment" do - mod = Module.new - Puppet::Parser::Functions.expects(:environment_module).with(Puppet::Node::Environment.root).returns(mod) - - Puppet::Parser::Functions.expects(:environment_module).with(nil).returns mod - - Puppet::Parser::Scope.new.singleton_class.ancestors.should be_include(mod) + it "should extend itself with the default Functions module if its environment is the default" do + root = Puppet::Node::Environment.root + scope = Puppet::Parser::Scope.new + scope.singleton_class.ancestors.should be_include(Puppet::Parser::Functions.environment_module(root)) end it "should remember if it is dynamic" do @@ -83,29 +83,55 @@ describe Puppet::Parser::Scope do end describe "when looking up a variable" do - it "should return ':undefined' for unset variables" do - @scope.lookupvar("var").should == :undefined + it "should support :lookupvar and :setvar for backward compatibility" do + @scope.setvar("var", "yep") + @scope.lookupvar("var").should == "yep" + end + + it "should return nil for unset variables" do + @scope["var"].should be_nil end it "should be able to look up values" do - @scope.setvar("var", "yep") - @scope.lookupvar("var").should == "yep" + @scope["var"] = "yep" + @scope["var"].should == "yep" end it "should be able to look up hashes" do - @scope.setvar("var", {"a" => "b"}) - @scope.lookupvar("var").should == {"a" => "b"} + @scope["var"] = {"a" => "b"} + @scope["var"].should == {"a" => "b"} end it "should be able to look up variables in parent scopes" do - @topscope.setvar("var", "parentval") - @scope.lookupvar("var").should == "parentval" + @topscope["var"] = "parentval" + @scope["var"].should == "parentval" end it "should prefer its own values to parent values" do - @topscope.setvar("var", "parentval") - @scope.setvar("var", "childval") - @scope.lookupvar("var").should == "childval" + @topscope["var"] = "parentval" + @scope["var"] = "childval" + @scope["var"].should == "childval" + end + + it "should be able to detect when variables are set" do + @scope["var"] = "childval" + @scope.should be_include("var") + end + + it "should be able to detect when variables are not set" do + @scope.should_not be_include("var") + end + + it "should support iteration over its variables" do + @scope["one"] = "two" + @scope["three"] = "four" + hash = {} + @scope.each { |name, value| hash[name] = value } + hash.should == {"one" => "two", "three" => "four" } + end + + it "should include Enumerable" do + @scope.singleton_class.ancestors.should be_include(Enumerable) end describe "and the variable is qualified" do @@ -133,84 +159,84 @@ describe Puppet::Parser::Scope do it "should be able to look up explicitly fully qualified variables from main" do other_scope = create_class_scope("") - other_scope.setvar("othervar", "otherval") + other_scope["othervar"] = "otherval" - @scope.lookupvar("::othervar").should == "otherval" + @scope["::othervar"].should == "otherval" end it "should be able to look up explicitly fully qualified variables from other scopes" do other_scope = create_class_scope("other") - other_scope.setvar("var", "otherval") + other_scope["var"] = "otherval" - @scope.lookupvar("::other::var").should == "otherval" + @scope["::other::var"].should == "otherval" end it "should be able to look up deeply qualified variables" do other_scope = create_class_scope("other::deep::klass") - other_scope.setvar("var", "otherval") + other_scope["var"] = "otherval" - @scope.lookupvar("other::deep::klass::var").should == "otherval" + @scope["other::deep::klass::var"].should == "otherval" end - it "should return ':undefined' for qualified variables that cannot be found in other classes" do + it "should return nil for qualified variables that cannot be found in other classes" do other_scope = create_class_scope("other::deep::klass") - @scope.lookupvar("other::deep::klass::var").should == :undefined + @scope["other::deep::klass::var"].should be_nil end - it "should warn and return ':undefined' for qualified variables whose classes have not been evaluated" do + it "should warn and return nil for qualified variables whose classes have not been evaluated" do klass = newclass("other::deep::klass") @scope.expects(:warning) - @scope.lookupvar("other::deep::klass::var").should == :undefined + @scope["other::deep::klass::var"].should be_nil end - it "should warn and return ':undefined' for qualified variables whose classes do not exist" do + it "should warn and return nil for qualified variables whose classes do not exist" do @scope.expects(:warning) - @scope.lookupvar("other::deep::klass::var").should == :undefined + @scope["other::deep::klass::var"].should be_nil end - it "should return ':undefined' when asked for a non-string qualified variable from a class that does not exist" do + it "should return nil when asked for a non-string qualified variable from a class that does not exist" do @scope.stubs(:warning) - @scope.lookupvar("other::deep::klass::var").should == :undefined + @scope["other::deep::klass::var"].should be_nil end - it "should return ':undefined' when asked for a non-string qualified variable from a class that has not been evaluated" do + it "should return nil when asked for a non-string qualified variable from a class that has not been evaluated" do @scope.stubs(:warning) klass = newclass("other::deep::klass") - @scope.lookupvar("other::deep::klass::var").should == :undefined + @scope["other::deep::klass::var"].should be_nil end end end - describe "when setvar is called with append=true" do - it "should raise error if the variable is already defined in this scope" do + describe "when variables are set with append=true" do + it "should raise an error if the variable is already defined in this scope" do @scope.setvar("var","1", :append => false) lambda { @scope.setvar("var","1", :append => true) }.should raise_error(Puppet::ParseError) end it "should lookup current variable value" do - @scope.expects(:lookupvar).with("var").returns("2") + @scope.expects(:[]).with("var").returns("2") @scope.setvar("var","1", :append => true) end it "should store the concatenated string '42'" do @topscope.setvar("var","4", :append => false) @scope.setvar("var","2", :append => true) - @scope.lookupvar("var").should == "42" + @scope["var"].should == "42" end it "should store the concatenated array [4,2]" do @topscope.setvar("var",[4], :append => false) @scope.setvar("var",[2], :append => true) - @scope.lookupvar("var").should == [4,2] + @scope["var"].should == [4,2] end it "should store the merged hash {a => b, c => d}" do @topscope.setvar("var",{"a" => "b"}, :append => false) @scope.setvar("var",{"c" => "d"}, :append => true) - @scope.lookupvar("var").should == {"a" => "b", "c" => "d"} + @scope["var"].should == {"a" => "b", "c" => "d"} end it "should raise an error when appending a hash with something other than another hash" do @@ -285,7 +311,7 @@ describe Puppet::Parser::Scope do it "should store the variable value" do @scope.setvar("1", :value, :ephemeral => true) - @scope.lookupvar("1").should == :value + @scope["1"].should == :value end it "should remove the variable value when unset_ephemeral_var is called" do @@ -294,17 +320,17 @@ describe Puppet::Parser::Scope do @scope.unset_ephemeral_var - @scope.lookupvar("1").should == :undefined + @scope["1"].should be_nil end it "should not remove classic variables when unset_ephemeral_var is called" do - @scope.setvar("myvar", :value1) + @scope['myvar'] = :value1 @scope.setvar("1", :value2, :ephemeral => true) @scope.stubs(:parent).returns(nil) @scope.unset_ephemeral_var - @scope.lookupvar("myvar").should == :value1 + @scope["myvar"].should == :value1 end it "should raise an error when setting it again" do @@ -325,7 +351,7 @@ describe Puppet::Parser::Scope do @scope.setvar("0", :earliest, :ephemeral => true) @scope.new_ephemeral @scope.setvar("0", :latest, :ephemeral => true) - @scope.lookupvar("0").should == :latest + @scope["0"].should == :latest end it "should be able to report the current level" do @@ -356,7 +382,7 @@ describe Puppet::Parser::Scope do @scope.setvar("1", :value1, :ephemeral => true) @scope.new_ephemeral @scope.setvar("0", :value2, :ephemeral => true) - @scope.lookupvar("1").should == :value1 + @scope["1"].should == :value1 end describe "when calling unset_ephemeral_var without a level" do @@ -367,7 +393,7 @@ describe Puppet::Parser::Scope do @scope.unset_ephemeral_var - @scope.lookupvar("1").should == :undefined + @scope["1"].should be_nil end end @@ -381,7 +407,7 @@ describe Puppet::Parser::Scope do @scope.unset_ephemeral_var(2) - @scope.lookupvar("1").should == :value2 + @scope["1"].should == :value2 end end end @@ -421,22 +447,22 @@ describe Puppet::Parser::Scope do describe "when unsetting variables" do it "should be able to unset normal variables" do - @scope.setvar("foo", "bar") + @scope["foo"] = "bar" @scope.unsetvar("foo") - @scope.lookupvar("foo").should == :undefined + @scope["foo"].should be_nil end it "should be able to unset ephemeral variables" do @scope.setvar("0", "bar", :ephemeral => true) @scope.unsetvar("0") - @scope.lookupvar("0").should == :undefined + @scope["0"].should be_nil end it "should not unset ephemeral variables in previous ephemeral scope" do @scope.setvar("0", "bar", :ephemeral => true) @scope.new_ephemeral @scope.unsetvar("0") - @scope.lookupvar("0").should == "bar" + @scope["0"].should == "bar" end end diff --git a/spec/unit/parser/templatewrapper_spec.rb b/spec/unit/parser/templatewrapper_spec.rb index 600293bbf..6080346fb 100755 --- a/spec/unit/parser/templatewrapper_spec.rb +++ b/spec/unit/parser/templatewrapper_spec.rb @@ -72,25 +72,23 @@ describe Puppet::Parser::TemplateWrapper do end it "should return the contents of a variable if called via method_missing" do - @scope.expects(:lookupvar).with { |name,options| name == "chicken"}.returns("is good") + @scope["chicken"] = "is good" tw = Puppet::Parser::TemplateWrapper.new(@scope) tw.chicken.should eql("is good") end it "should throw an exception if a variable is called via method_missing and it does not exist" do - @scope.expects(:lookupvar).with { |name,options| name == "chicken"}.returns(:undefined) tw = Puppet::Parser::TemplateWrapper.new(@scope) lambda { tw.chicken }.should raise_error(Puppet::ParseError) end it "should allow you to check whether a variable is defined with has_variable?" do - @scope.expects(:lookupvar).with { |name,options| name == "chicken"}.returns("is good") + @scope["chicken"] = "is good" tw = Puppet::Parser::TemplateWrapper.new(@scope) tw.has_variable?("chicken").should eql(true) end it "should allow you to check whether a variable is not defined with has_variable?" do - @scope.expects(:lookupvar).with { |name,options| name == "chicken"}.returns(:undefined) tw = Puppet::Parser::TemplateWrapper.new(@scope) tw.has_variable?("chicken").should eql(false) end diff --git a/spec/unit/resource/type_spec.rb b/spec/unit/resource/type_spec.rb index 352f767e4..416fbac42 100755 --- a/spec/unit/resource/type_spec.rb +++ b/spec/unit/resource/type_spec.rb @@ -238,9 +238,10 @@ describe Puppet::Resource::Type do describe "when setting its parameters in the scope" do before do - @scope = Puppet::Parser::Scope.new(:compiler => stub("compiler", :environment => Puppet::Node::Environment.new), :source => stub("source")) + @scope = Puppet::Parser::Scope.new @resource = Puppet::Parser::Resource.new(:foo, "bar", :scope => @scope) - @type = Puppet::Resource::Type.new(:hostclass, "foo") + @type = Puppet::Resource::Type.new(:definition, "foo") + @resource.environment.known_resource_types.add @type end ['module_name', 'name', 'title'].each do |variable| @@ -249,20 +250,20 @@ describe Puppet::Resource::Type do var = Puppet::Parser::AST::Variable.new({'value' => variable}) @type.set_arguments :foo => var @type.set_resource_parameters(@resource, @scope) - @scope.lookupvar('foo').should == 'bar' + @scope['foo'].should == 'bar' end end # this test is to clarify a crazy edge case # if you specify these special names as params, the resource # will override the special variables - it "resource should override defaults" do + it "should allow the resource to override defaults" do @type.set_arguments :name => nil @resource[:name] = 'foobar' var = Puppet::Parser::AST::Variable.new({'value' => 'name'}) @type.set_arguments :foo => var @type.set_resource_parameters(@resource, @scope) - @scope.lookupvar('foo').should == 'foobar' + @scope['foo'].should == 'foobar' end it "should set each of the resource's parameters as variables in the scope" do @@ -272,8 +273,8 @@ describe Puppet::Resource::Type do @type.set_resource_parameters(@resource, @scope) - @scope.lookupvar("foo").should == "bar" - @scope.lookupvar("boo").should == "baz" + @scope['foo'].should == "bar" + @scope['boo'].should == "baz" end it "should set the variables as strings" do @@ -282,7 +283,7 @@ describe Puppet::Resource::Type do @type.set_resource_parameters(@resource, @scope) - @scope.lookupvar("foo").should == "bar" + @scope['foo'].should == "bar" end it "should fail if any of the resource's parameters are not valid attributes" do @@ -293,13 +294,13 @@ describe Puppet::Resource::Type do end it "should evaluate and set its default values as variables for parameters not provided by the resource" do - @type.set_arguments :foo => stub("value", :safeevaluate => "something") + @type.set_arguments :foo => Puppet::Parser::AST::String.new(:value => "something") @type.set_resource_parameters(@resource, @scope) - @scope.lookupvar("foo").should == "something" + @scope['foo'].should == "something" end it "should set all default values as parameters in the resource" do - @type.set_arguments :foo => stub("value", :safeevaluate => "something") + @type.set_arguments :foo => Puppet::Parser::AST::String.new(:value => "something") @type.set_resource_parameters(@resource, @scope) @@ -308,7 +309,6 @@ describe Puppet::Resource::Type do it "should fail if the resource does not provide a value for a required argument" do @type.set_arguments :foo => nil - @resource.expects(:to_hash).returns({}) lambda { @type.set_resource_parameters(@resource, @scope) }.should raise_error(Puppet::ParseError) end @@ -316,13 +316,13 @@ describe Puppet::Resource::Type do it "should set the resource's title as a variable if not otherwise provided" do @type.set_resource_parameters(@resource, @scope) - @scope.lookupvar("title").should == "bar" + @scope['title'].should == "bar" end it "should set the resource's name as a variable if not otherwise provided" do @type.set_resource_parameters(@resource, @scope) - @scope.lookupvar("name").should == "bar" + @scope['name'].should == "bar" end it "should set its module name in the scope if available" do @@ -330,7 +330,7 @@ describe Puppet::Resource::Type do @type.set_resource_parameters(@resource, @scope) - @scope.lookupvar("module_name").should == "mymod" + @scope["module_name"].should == "mymod" end it "should set its caller module name in the scope if available" do @@ -338,21 +338,20 @@ describe Puppet::Resource::Type do @type.set_resource_parameters(@resource, @scope) - @scope.lookupvar("caller_module_name").should == "mycaller" + @scope["caller_module_name"].should == "mycaller" end end describe "when describing and managing parent classes" do before do - @code = Puppet::Resource::TypeCollection.new("env") + @krt = Puppet::Node::Environment.new.known_resource_types @parent = Puppet::Resource::Type.new(:hostclass, "bar") - @code.add @parent + @krt.add @parent @child = Puppet::Resource::Type.new(:hostclass, "foo", :parent => "bar") - @code.add @child + @krt.add @child - @env = stub "environment", :known_resource_types => @code - @scope = stub "scope", :environment => @env, :namespaces => [""] + @scope = Puppet::Parser::Scope.new end it "should be able to define a parent" do @@ -365,16 +364,16 @@ describe Puppet::Resource::Type do it "should be able to find parent nodes" do parent = Puppet::Resource::Type.new(:node, "bar") - @code.add parent + @krt.add parent child = Puppet::Resource::Type.new(:node, "foo", :parent => "bar") - @code.add child + @krt.add child child.parent_type(@scope).should equal(parent) end it "should cache a reference to the parent type" do - @code.stubs(:hostclass).with("foo::bar").returns nil - @code.expects(:hostclass).with("bar").once.returns @parent + @krt.stubs(:hostclass).with("foo::bar").returns nil + @krt.expects(:hostclass).with("bar").once.returns @parent @child.parent_type(@scope) @child.parent_type end @@ -386,7 +385,7 @@ describe Puppet::Resource::Type do it "should be considered the child of a parent's parent" do @grandchild = Puppet::Resource::Type.new(:hostclass, "baz", :parent => "foo") - @code.add @grandchild + @krt.add @grandchild @child.parent_type(@scope) @grandchild.parent_type(@scope) @@ -396,7 +395,7 @@ describe Puppet::Resource::Type do it "should correctly state when it is not another type's child" do @notchild = Puppet::Resource::Type.new(:hostclass, "baz") - @code.add @notchild + @krt.add @notchild @notchild.should_not be_child_of(@parent) end @@ -406,14 +405,13 @@ describe Puppet::Resource::Type do before do @compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("mynode")) @scope = Puppet::Parser::Scope.new :compiler => @compiler - @resource = Puppet::Parser::Resource.new(:foo, "yay", :scope => @scope) + @resource = Puppet::Parser::Resource.new(:class, "foo", :scope => @scope) # This is so the internal resource lookup works, yo. @compiler.catalog.add_resource @resource - @known_resource_types = stub 'known_resource_types' - @resource.stubs(:known_resource_types).returns @known_resource_types @type = Puppet::Resource::Type.new(:hostclass, "foo") + @resource.environment.known_resource_types.add @type end it "should add hostclass names to the classes list" do diff --git a/spec/unit/resource_spec.rb b/spec/unit/resource_spec.rb index 5c8e8dcf9..0485bc7aa 100755 --- a/spec/unit/resource_spec.rb +++ b/spec/unit/resource_spec.rb @@ -272,6 +272,67 @@ describe Puppet::Resource do Puppet::Resource.new("file", "/foo").should_not == Puppet::Resource.new("file", "/f") end + describe "when setting default parameters" do + before do + @scope = Puppet::Parser::Scope.new + end + + it "should fail when asked to set default values and it is not a parser resource" do + Puppet::Node::Environment.new.known_resource_types.add( + Puppet::Resource::Type.new(:definition, "default_param", :arguments => {"a" => Puppet::Parser::AST::String.new(:value => "default")}) + ) + resource = Puppet::Resource.new("default_param", "name") + lambda { resource.set_default_parameters(@scope) }.should raise_error(Puppet::DevError) + end + + it "should evaluate and set any default values when no value is provided" do + Puppet::Node::Environment.new.known_resource_types.add( + Puppet::Resource::Type.new(:definition, "default_param", :arguments => {"a" => Puppet::Parser::AST::String.new(:value => "a_default_value")}) + ) + resource = Puppet::Parser::Resource.new("default_param", "name", :scope => Puppet::Parser::Scope.new) + resource.set_default_parameters(@scope) + resource["a"].should == "a_default_value" + end + + it "should skip attributes with no default value" do + Puppet::Node::Environment.new.known_resource_types.add( + Puppet::Resource::Type.new(:definition, "no_default_param", :arguments => {"a" => Puppet::Parser::AST::String.new(:value => "a_default_value")}) + ) + resource = Puppet::Parser::Resource.new("no_default_param", "name", :scope => Puppet::Parser::Scope.new) + lambda { resource.set_default_parameters(@scope) }.should_not raise_error + end + + it "should return the list of default parameters set" do + Puppet::Node::Environment.new.known_resource_types.add( + Puppet::Resource::Type.new(:definition, "default_param", :arguments => {"a" => Puppet::Parser::AST::String.new(:value => "a_default_value")}) + ) + resource = Puppet::Parser::Resource.new("default_param", "name", :scope => Puppet::Parser::Scope.new) + resource.set_default_parameters(@scope).should == [:a] + end + end + + describe "when validating all required parameters are present" do + it "should be able to validate that all required parameters are present" do + Puppet::Node::Environment.new.known_resource_types.add( + Puppet::Resource::Type.new(:definition, "required_param", :arguments => {"a" => nil}) + ) + lambda { Puppet::Resource.new("required_param", "name").validate_complete }.should raise_error(Puppet::ParseError) + end + + it "should not fail when all required parameters are present" do + Puppet::Node::Environment.new.known_resource_types.add( + Puppet::Resource::Type.new(:definition, "no_required_param") + ) + resource = Puppet::Resource.new("no_required_param", "name") + resource["a"] = "meh" + lambda { resource.validate_complete }.should_not raise_error + end + + it "should not validate against builtin types" do + lambda { Puppet::Resource.new("file", "/bar").validate_complete }.should_not raise_error + end + end + describe "when referring to a resource with name canonicalization" do it "should canonicalize its own name" do res = Puppet::Resource.new("file", "/path/") diff --git a/test/language/ast/variable.rb b/test/language/ast/variable.rb deleted file mode 100755 index 968d1b7c3..000000000 --- a/test/language/ast/variable.rb +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env ruby -# -# Created by Luke A. Kanies on 2007-0419. -# Copyright (c) 2006. All rights reserved. - -require File.expand_path(File.dirname(__FILE__) + '/../../lib/puppettest') - -require 'puppettest' -require 'puppettest/parsertesting' - -class TestVariable < Test::Unit::TestCase - include PuppetTest - include PuppetTest::ParserTesting - AST = Puppet::Parser::AST - - def setup - super - @scope = mkscope - @name = "myvar" - @var = AST::Variable.new(:value => @name) - end - - def test_evaluate - assert_equal(:undef, @var.evaluate(@scope), "did not return :undef on unset var") - @scope.setvar(@name, "something") - assert_equal("something", @var.evaluate(@scope), "incorrect variable value") - end -end - diff --git a/test/language/functions.rb b/test/language/functions.rb index 84b1b3861..44d86f0f9 100755 --- a/test/language/functions.rb +++ b/test/language/functions.rb @@ -148,17 +148,17 @@ class TestLangFunctions < Test::Unit::TestCase # Test that our use of an undefined instance variable does not throw # an exception, but only safely continues. - scope.setvar("one", "One") + scope['one'] = "One" assert_nothing_raised do ast.evaluate(scope) end # Ensure that we got the output we expected from that evaluation. - assert_equal("template One\ntemplate \n", scope.lookupvar("output"), "Undefined template variables do not raise exceptions") + assert_equal("template One\ntemplate \n", scope['output'], "Undefined template variables do not raise exceptions") # Now, fill in the last variable and make sure the whole thing # evaluates correctly. - scope.setvar("two", "Two") + scope['two'] = "Two" scope.unsetvar("output") assert_nothing_raised do ast.evaluate(scope) @@ -166,7 +166,7 @@ class TestLangFunctions < Test::Unit::TestCase assert_equal( - "template One\ntemplate Two\n", scope.lookupvar("output"), + "template One\ntemplate Two\n", scope['output'], "Templates were not handled correctly") end @@ -199,7 +199,7 @@ class TestLangFunctions < Test::Unit::TestCase ast.evaluate(scope) end - scope.setvar("yay", "this is yay") + scope['yay'] = "this is yay" assert_nothing_raised do ast.evaluate(scope) @@ -207,7 +207,7 @@ class TestLangFunctions < Test::Unit::TestCase assert_equal( - "template this is yay\n", scope.lookupvar("output"), + "template this is yay\n", scope['output'], "Templates were not handled correctly") @@ -243,14 +243,14 @@ class TestLangFunctions < Test::Unit::TestCase end # Verify that we evaluate and return their value correctly. - scope.setvar("deprecated", "deprecated value") + scope["deprecated"] = "deprecated value" assert_nothing_raised do ast.evaluate(scope) end assert_equal( - "template deprecated value\n", scope.lookupvar("output"), + "template deprecated value\n", scope['output'], "Deprecated template variables were not handled correctly") end @@ -305,7 +305,7 @@ class TestLangFunctions < Test::Unit::TestCase ast = varobj("output", func) scope = mkscope - scope.setvar("myvar", "this is yayness") + scope['myvar'] = "this is yayness" assert_raise(Puppet::ParseError) do ast.evaluate(scope) end @@ -381,15 +381,15 @@ class TestLangFunctions < Test::Unit::TestCase false => "false", }.each do |string, value| scope = mkscope - scope.setvar("yayness", string) - assert_equal(string, scope.lookupvar("yayness")) + scope['yayness'] = string + assert_equal(scope['yayness'], string, "did not correctly evaluate '#{string}'") assert_nothing_raised("An empty string was not a valid variable value") do ast.evaluate(scope) end assert_equal( - "template #{value}\n", scope.lookupvar("output"), + "template #{value}\n", scope['output'], "#{string.inspect} did not get evaluated correctly") end end diff --git a/test/language/scope.rb b/test/language/scope.rb index ccc359651..c80178e7b 100755 --- a/test/language/scope.rb +++ b/test/language/scope.rb @@ -40,24 +40,24 @@ class TestScope < Test::Unit::TestCase scopes = {:top => topscope, :mid => midscope, :bot => botscope} # Set a variable in the top and make sure all three can get it - topscope.setvar("first", "topval") + topscope['first'] = 'topval' scopes.each do |name, scope| - assert_equal("topval", scope.lookupvar("first"), "Could not find var in #{name}") + assert_equal("topval", scope['first'], "Could not find var in #{name}") end # Now set a var in the midscope and make sure the mid and bottom can see it but not the top - midscope.setvar("second", "midval") - assert_equal(:undefined, scopes[:top].lookupvar("second"), "Found child var in top scope") + midscope['second'] = "midval" + assert_nil(scopes[:top]['second'], "Found child var in top scope") [:mid, :bot].each do |name| - assert_equal("midval", scopes[name].lookupvar("second"), "Could not find var in #{name}") + assert_equal("midval", scopes[name]['second'], "Could not find var in #{name}") end # And set something in the bottom, and make sure we only find it there. - botscope.setvar("third", "botval") + botscope['third'] = "botval" [:top, :mid].each do |name| - assert_equal(:undefined, scopes[name].lookupvar("third"), "Found child var in top scope") + assert_nil(scopes[name]['third'], "Found child var in top scope") end - assert_equal("botval", scopes[:bot].lookupvar("third"), "Could not find var in bottom scope") + assert_equal("botval", scopes[:bot]['third'], "Could not find var in bottom scope") # Test that the scopes convert to hash structures correctly. @@ -84,7 +84,7 @@ class TestScope < Test::Unit::TestCase # Finally, check the ability to shadow symbols by adding a shadow to # bottomscope, then checking that we see the right stuff. - botscope.setvar("first", "shadowval") + botscope['first'] = "shadowval" assert_equal( {"third" => "botval", "first" => "shadowval"}, @@ -105,16 +105,16 @@ class TestScope < Test::Unit::TestCase sub = mkscope(:parent => top) assert_nothing_raised { - top.setvar("test","value") + top['test'] = "value" } assert_raise(Puppet::ParseError) { - top.setvar("test","other") + top['test'] = 'other' } assert_nothing_raised { - sub.setvar("test","later") + top['other'] = 'later' } assert_raise(Puppet::ParseError) { - top.setvar("test","yeehaw") + top['other'] = 'yeehaw' } end @@ -259,8 +259,8 @@ Host <<||>>" def test_lookupvar_with_undef scope = mkscope - scope.setvar("testing", :undef) - assert_equal(:undef, scope.lookupvar("testing"), "undef was not returned as :undef") + scope['testing'] = :undef + assert_equal(:undef, scope['testing'], "undef was not returned as :undef") end end |