From dd7caa76e160ed51c8b0e123c18f7526b575bfec Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Mon, 12 Nov 2007 11:00:54 -0600 Subject: Moving some compile tests to the spec/ directory, and switching the node scope to no longer be lazy evaluation, just like I switched 'main'. When I made all of these classes and nodes lazy evaluated, I should have decoupled my real goal (using resources to evaluate them) from the idea of lazy-evaluating them, and this basically does that. I also changed the scope heirarchy slightly so that scopes will tend to be below the node scope, altho this was already generally the case. --- CHANGELOG | 5 +++ lib/puppet/parser/compile.rb | 19 +++++--- spec/unit/parser/compile.rb | 100 +++++++++++++++++++++++++++++++++++++++++++ test/language/compile.rb | 73 ------------------------------- 4 files changed, 119 insertions(+), 78 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 5a7103403..bbe621742 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,8 @@ + The node scope is now above all other scopes besides + the 'main' scope, which should help make its variables + visible to other classes, assuming those classes were + not included in the node's parent. + Replaced GRATR::Digraph with Puppet::SimpleGraph as the base class for Puppet's graphing. Functionality should be equivalent but with dramatically better diff --git a/lib/puppet/parser/compile.rb b/lib/puppet/parser/compile.rb index 3083f4849..45d60a58c 100644 --- a/lib/puppet/parser/compile.rb +++ b/lib/puppet/parser/compile.rb @@ -14,7 +14,7 @@ require 'puppet/util/errors' class Puppet::Parser::Compile include Puppet::Util include Puppet::Util::Errors - attr_reader :topscope, :parser, :node, :facts, :collections, :configuration + attr_reader :parser, :node, :facts, :collections, :configuration, :node_scope # Add a collection to the global list. def add_collection(coll) @@ -229,6 +229,12 @@ class Puppet::Parser::Compile @configuration.add_edge!(scope.resource, resource) end + # The top scope is usually the top-level scope, but if we're using AST nodes, + # then it is instead the node's scope. + def topscope + node_scope || @topscope + end + private # If ast nodes are enabled, then see if we can find and evaluate one. @@ -241,10 +247,7 @@ class Puppet::Parser::Compile break if astnode = @parser.nodes[name.to_s.downcase] end - unless astnode - astnode = @parser.nodes["default"] - end - unless astnode + unless (astnode ||= @parser.nodes["default"]) raise Puppet::ParseError, "Could not find default node or by name with '%s'" % node.names.join(", ") end @@ -253,6 +256,12 @@ class Puppet::Parser::Compile resource = Puppet::Parser::Resource.new(:type => "node", :title => astnode.classname, :scope => topscope, :source => topscope.source) store_resource(topscope, resource) @configuration.tag(astnode.classname) + + resource.evaluate + + # Now set the node scope appropriately, so that :topscope can + # behave differently. + @node_scope = class_scope(astnode) end # Evaluate our collections and return true if anything returned an object. diff --git a/spec/unit/parser/compile.rb b/spec/unit/parser/compile.rb index 93c440417..5f239636b 100755 --- a/spec/unit/parser/compile.rb +++ b/spec/unit/parser/compile.rb @@ -141,3 +141,103 @@ describe Puppet::Parser::Compile, " when evaluating found classes" do @compile.evaluate_classes(%w{myclass notfound}, @scope).should == %w{myclass} end end + +describe Puppet::Parser::Compile, " when evaluating AST nodes with no AST nodes present" do + before do + @node = stub 'node', :name => "foo" + @parser = stub 'parser', :version => "1.0", :nodes => {} + @compile = Puppet::Parser::Compile.new(@node, @parser) + end + + it "should do nothing" do + @compile.expects(:ast_nodes?).returns(false) + @compile.parser.expects(:nodes).never + Puppet::Parser::Resource.expects(:new).never + + @compile.send(:evaluate_ast_node) + end +end + +describe Puppet::Parser::Compile, " when evaluating AST nodes with AST nodes present" do + before do + @node = stub 'node', :name => "foo" + @parser = stub 'parser', :version => "1.0", :nodes => {} + @compile = Puppet::Parser::Compile.new(@node, @parser) + + @nodes = mock 'node_hash' + @compile.stubs(:ast_nodes?).returns(true) + @compile.parser.stubs(:nodes).returns(@nodes) + + # Set some names for our test + @node.stubs(:names).returns(%w{a b c}) + @nodes.stubs(:[]).with("a").returns(nil) + @nodes.stubs(:[]).with("b").returns(nil) + @nodes.stubs(:[]).with("c").returns(nil) + + # It should check this last, of course. + @nodes.stubs(:[]).with("default").returns(nil) + end + + it "should fail if the named node cannot be found" do + proc { @compile.send(:evaluate_ast_node) }.should raise_error(Puppet::ParseError) + end + + it "should create a resource for the first node class matching the node name" do + node_class = stub 'node', :classname => "c" + @nodes.stubs(:[]).with("c").returns(node_class) + + node_resource = stub 'node resource', :ref => "Node[c]", :evaluate => nil + Puppet::Parser::Resource.expects(:new).with { |args| args[:title] == "c" and args[:type] == "node" }.returns(node_resource) + + @compile.send(:evaluate_ast_node) + end + + it "should match the default node if no matching node can be found" do + node_class = stub 'node', :classname => "default" + @nodes.stubs(:[]).with("default").returns(node_class) + + node_resource = stub 'node resource', :ref => "Node[default]", :evaluate => nil + Puppet::Parser::Resource.expects(:new).with { |args| args[:title] == "default" and args[:type] == "node" }.returns(node_resource) + + @compile.send(:evaluate_ast_node) + end + + it "should tag the configuration with the found node name" do + node_class = stub 'node', :classname => "c" + @nodes.stubs(:[]).with("c").returns(node_class) + + node_resource = stub 'node resource', :ref => "Node[c]", :evaluate => nil + Puppet::Parser::Resource.stubs(:new).returns(node_resource) + + @compile.configuration.expects(:tag).with("c") + @compile.send(:evaluate_ast_node) + end + + it "should evaluate the node resource immediately rather than using lazy evaluation" do + node_class = stub 'node', :classname => "c" + @nodes.stubs(:[]).with("c").returns(node_class) + + node_resource = stub 'node resource', :ref => "Node[c]" + Puppet::Parser::Resource.stubs(:new).returns(node_resource) + + node_resource.expects(:evaluate) + + @compile.send(:evaluate_ast_node) + end + + it "should set the node's scope as the top scope" do + node_class = stub 'node', :classname => "c" + @nodes.stubs(:[]).with("c").returns(node_class) + + node_resource = stub 'node resource', :ref => "Node[c]" + Puppet::Parser::Resource.stubs(:new).returns(node_resource) + + # The #evaluate method normally does this. + @compile.class_set(node_class.classname, :my_node_scope) + node_resource.stubs(:evaluate) + + @compile.send(:evaluate_ast_node) + + @compile.topscope.should == :my_node_scope + end +end diff --git a/test/language/compile.rb b/test/language/compile.rb index f5d9cb7d9..50b16a24d 100755 --- a/test/language/compile.rb +++ b/test/language/compile.rb @@ -188,79 +188,6 @@ class TestCompile < Test::Unit::TestCase end end - # Make sure we either don't look for nodes, or that we find and evaluate the right object. - def test_evaluate_ast_node - # First try it with ast_nodes disabled - compile = mkcompile - name = compile.node.name - compile.expects(:ast_nodes?).returns(false) - compile.parser.expects(:nodes).never - - assert_nothing_raised("Could not call evaluate_ast_node when ast nodes are disabled") do - compile.send(:evaluate_ast_node) - end - - assert_nil(compile.resources.find { |r| r.to_s == "Node[#{name}]" }, "Created node object when ast_nodes was false") - - # Now try it with them enabled, but no node found. - nodes = mock 'node_hash' - compile = mkcompile - name = compile.node.name - compile.expects(:ast_nodes?).returns(true) - compile.parser.stubs(:nodes).returns(nodes) - - # Set some names for our test - @node.names = %w{a b c} - nodes.expects(:[]).with("a").returns(nil) - nodes.expects(:[]).with("b").returns(nil) - nodes.expects(:[]).with("c").returns(nil) - - # It should check this last, of course. - nodes.expects(:[]).with("default").returns(nil) - - # And make sure the lack of a node throws an exception - assert_raise(Puppet::ParseError, "Did not fail when we couldn't find an ast node") do - compile.send(:evaluate_ast_node) - end - - # Finally, make sure it works dandily when we have a node - compile = mkcompile - compile.expects(:ast_nodes?).returns(true) - - node = stub 'node', :classname => "c" - nodes = {"c" => node} - compile.parser.stubs(:nodes).returns(nodes) - - # Set some names for our test - @node.names = %w{a b c} - - # And make sure we throw no exceptions. - assert_nothing_raised("Failed when a node was found") do - compile.send(:evaluate_ast_node) - end - - assert_instance_of(Puppet::Parser::Resource, compile.resources.find { |r| r.to_s == "Node[c]" }, - "Did not create node resource") - - # Lastly, check when we actually find the default. - compile = mkcompile - compile.expects(:ast_nodes?).returns(true) - - node = stub 'node', :classname => "default" - nodes = {"default" => node} - compile.parser.stubs(:nodes).returns(nodes) - - # Set some names for our test - @node.names = %w{a b c} - - # And make sure the lack of a node throws an exception - assert_nothing_raised("Failed when a node was found") do - compile.send(:evaluate_ast_node) - end - assert_instance_of(Puppet::Parser::Resource, compile.resources.find { |r| r.to_s == "Node[default]" }, - "Did not create default node resource") - end - def test_evaluate_node_classes compile = mkcompile @node.classes = %w{one two three four} -- cgit