From f98be4a7198326b26f1072c401b3e337f340db40 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Sat, 19 Jan 2008 13:40:40 -0800 Subject: Fixing #976 -- both the full name of qualified classes and the class parts are now added as tags. I've also created a Tagging module that we should push throughout the rest of the system that uses tags. --- spec/unit/parser/resource.rb | 60 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) (limited to 'spec/unit/parser') diff --git a/spec/unit/parser/resource.rb b/spec/unit/parser/resource.rb index 3d048f7e6..319d8f7d8 100755 --- a/spec/unit/parser/resource.rb +++ b/spec/unit/parser/resource.rb @@ -4,6 +4,7 @@ require File.dirname(__FILE__) + '/../../spec_helper' # LAK: FIXME This is just new tests for resources; I have # not moved all tests over yet. + describe Puppet::Parser::Resource, " when evaluating" do before do @type = Puppet::Parser::Resource @@ -86,4 +87,63 @@ describe Puppet::Parser::Resource, " when finishing" do @resource["require"].sort.should == %w{container1 container2 resource1 resource2} end + + it "should add any tags from the scope resource" do + scope_resource = stub 'scope_resource', :tags => %w{one two} + @scope.stubs(:resource).returns(scope_resource) + + @resource.class.publicize_methods(:add_scope_tags) { @resource.add_scope_tags } + + @resource.tags.should be_include("one") + @resource.tags.should be_include("two") + end +end + +describe Puppet::Parser::Resource, "when being tagged" do + before do + @scope_resource = stub 'scope_resource', :tags => %w{srone srtwo} + @scope = stub 'scope', :resource => @scope_resource + @resource = Puppet::Parser::Resource.new(:type => "file", :title => "yay", :scope => @scope, :source => mock('source')) + end + + it "should get tagged with the resource type" do + @resource.tags.should be_include("file") + end + + it "should get tagged with the title" do + @resource.tags.should be_include("yay") + end + + it "should get tagged with each name in the title if the title is a qualified class name" do + resource = Puppet::Parser::Resource.new(:type => "file", :title => "one::two", :scope => @scope, :source => mock('source')) + resource.tags.should be_include("one") + resource.tags.should be_include("two") + end + + it "should get tagged with each name in the type if the type is a qualified class name" do + resource = Puppet::Parser::Resource.new(:type => "one::two", :title => "whatever", :scope => @scope, :source => mock('source')) + resource.tags.should be_include("one") + resource.tags.should be_include("two") + end + + it "should not get tagged with non-alphanumeric titles" do + resource = Puppet::Parser::Resource.new(:type => "file", :title => "this is a test", :scope => @scope, :source => mock('source')) + resource.tags.should_not be_include("this is a test") + end + + it "should fail on tags containing '*' characters" do + lambda { @resource.tag("bad*tag") }.should raise_error(Puppet::ParseError) + end + + it "should fail on tags starting with '-' characters" do + lambda { @resource.tag("-badtag") }.should raise_error(Puppet::ParseError) + end + + it "should fail on tags containing ' ' characters" do + lambda { @resource.tag("bad tag") }.should raise_error(Puppet::ParseError) + end + + it "should allow alpha tags" do + lambda { @resource.tag("good_tag") }.should_not raise_error(Puppet::ParseError) + end end -- cgit From 6ff9423c7ebaf759fcee28a3009cd59bed3ea886 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Wed, 30 Jan 2008 23:28:07 +1100 Subject: Significantly refactoring the lexer, including adding Token and TokenList classes for managing how the tokens work. I also moved they tests to RSpec, but I didn't rewrite all of them. --- spec/unit/parser/lexer.rb | 465 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 465 insertions(+) create mode 100755 spec/unit/parser/lexer.rb (limited to 'spec/unit/parser') diff --git a/spec/unit/parser/lexer.rb b/spec/unit/parser/lexer.rb new file mode 100755 index 000000000..cddbef1ed --- /dev/null +++ b/spec/unit/parser/lexer.rb @@ -0,0 +1,465 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../spec_helper' + +require 'puppet/parser/lexer' + +describe Puppet::Parser::Lexer::Token do + before do + @token = Puppet::Parser::Lexer::Token.new(%r{something}, :NAME) + end + + [:regex, :name, :string, :skip, :incr_line, :skip_text].each do |param| + it "should have a #{param.to_s} reader" do + @token.should respond_to?(param) + end + + it "should have a #{param.to_s} writer" do + @token.should respond_to?(param.to_s + "=") + end + end +end + +describe Puppet::Parser::Lexer::Token, "when initializing" do + it "should create a regex if the first argument is a string" do + Puppet::Parser::Lexer::Token.new("something", :NAME).regex.should == %r{something} + end + + it "should set the string if the first argument is one" do + Puppet::Parser::Lexer::Token.new("something", :NAME).string.should == "something" + end + + it "should set the regex if the first argument is one" do + Puppet::Parser::Lexer::Token.new(%r{something}, :NAME).regex.should == %r{something} + end +end + +describe Puppet::Parser::Lexer::TokenList do + before do + @list = Puppet::Parser::Lexer::TokenList.new + end + + it "should have a method for retrieving tokens by the name" do + token = @list.add_token :name, "whatever" + @list[:name].should equal(token) + end + + it "should have a method for retrieving string tokens by the string" do + token = @list.add_token :name, "whatever" + @list.lookup("whatever").should equal(token) + end + + it "should add tokens to the list when directed" do + token = @list.add_token :name, "whatever" + @list[:name].should equal(token) + end + + it "should have a method for adding multiple tokens at once" do + @list.add_tokens "whatever" => :name, "foo" => :bar + @list[:name].should_not be_nil + @list[:bar].should_not be_nil + end + + it "should fail to add tokens sharing a name with an existing token" do + @list.add_token :name, "whatever" + lambda { @list.add_token :name, "whatever" }.should raise_error(ArgumentError) + end + + it "should set provided options on tokens being added" do + token = @list.add_token :name, "whatever", :skip_text => true + token.skip_text.should == true + end + + it "should define any provided blocks as a :convert method" do + token = @list.add_token(:name, "whatever") do "foo" end + token.convert.should == "foo" + end + + it "should store all string tokens in the :string_tokens list" do + one = @list.add_token(:name, "1") + @list.string_tokens.should be_include(one) + end + + it "should store all regex tokens in the :regex_tokens list" do + one = @list.add_token(:name, %r{one}) + @list.regex_tokens.should be_include(one) + end + + it "should not store string tokens in the :regex_tokens list" do + one = @list.add_token(:name, "1") + @list.regex_tokens.should_not be_include(one) + end + + it "should not store regex tokens in the :string_tokens list" do + one = @list.add_token(:name, %r{one}) + @list.string_tokens.should_not be_include(one) + end + + it "should sort the string tokens inversely by length when asked" do + one = @list.add_token(:name, "1") + two = @list.add_token(:other, "12") + @list.sort_tokens + @list.string_tokens.should == [two, one] + end +end + +describe Puppet::Parser::Lexer::TOKENS do + before do + @lexer = Puppet::Parser::Lexer.new() + end + + { + :LBRACK => '[', + :RBRACK => ']', + :LBRACE => '{', + :RBRACE => '}', + :LPAREN => '(', + :RPAREN => ')', + :EQUALS => '=', + :ISEQUAL => '==', + :GREATEREQUAL => '>=', + :GREATERTHAN => '>', + :LESSTHAN => '<', + :LESSEQUAL => '<=', + :NOTEQUAL => '!=', + :NOT => '!', + :COMMA => ',', + :DOT => '.', + :COLON => ':', + :AT => '@', + :LLCOLLECT => '<<|', + :RRCOLLECT => '|>>', + :LCOLLECT => '<|', + :RCOLLECT => '|>', + :SEMIC => ';', + :QMARK => '?', + :BACKSLASH => '\\', + :FARROW => '=>', + :PARROW => '+>' + }.each do |name, string| + it "should have a token named #{name.to_s}" do + Puppet::Parser::Lexer::TOKENS[name].should_not be_nil + end + + it "should match '#{string}' for the token #{name.to_s}" do + Puppet::Parser::Lexer::TOKENS[name].string.should == string + end + end + + { + "case" => :CASE, + "class" => :CLASS, + "default" => :DEFAULT, + "define" => :DEFINE, + "import" => :IMPORT, + "if" => :IF, + "elsif" => :ELSIF, + "else" => :ELSE, + "inherits" => :INHERITS, + "node" => :NODE, + "and" => :AND, + "or" => :OR, + "undef" => :UNDEF, + "false" => :FALSE, + "true" => :TRUE + }.each do |string, name| + it "should have a keyword named #{name.to_s}" do + Puppet::Parser::Lexer::KEYWORDS[name].should_not be_nil + end + + it "should have the keyword for #{name.to_s} set to #{string}" do + Puppet::Parser::Lexer::KEYWORDS[name].string.should == string + end + end + + # These tokens' strings don't matter, just that the tokens exist. + [:DQTEXT, :SQTEXT, :BOOLEAN, :NAME, :NUMBER, :COMMENT, :RETURN, :SQUOTE, :DQUOTE, :VARIABLE].each do |name| + it "should have a token named #{name.to_s}" do + Puppet::Parser::Lexer::TOKENS[name].should_not be_nil + end + end +end + +describe Puppet::Parser::Lexer::TOKENS[:NAME] do + before { @token = Puppet::Parser::Lexer::TOKENS[:NAME] } + + it "should match against lower-case alpha-numeric terms" do + @token.regex.should =~ "one-two" + end + + it "should return itself and the value if the matched term is not a keyword" do + Puppet::Parser::Lexer::KEYWORDS.expects(:lookup).returns(nil) + @token.convert(stub("lexer"), "myval").should == [Puppet::Parser::Lexer::TOKENS[:NAME], "myval"] + end + + it "should return the keyword token and the value if the matched term is a keyword" do + keyword = stub 'keyword', :name => :testing + Puppet::Parser::Lexer::KEYWORDS.expects(:lookup).returns(keyword) + @token.convert(stub("lexer"), "myval").should == [keyword, "myval"] + end + + it "should return the BOOLEAN token and 'true' if the matched term is the string 'true'" do + keyword = stub 'keyword', :name => :TRUE + Puppet::Parser::Lexer::KEYWORDS.expects(:lookup).returns(keyword) + @token.convert(stub('lexer'), "true").should == [Puppet::Parser::Lexer::TOKENS[:BOOLEAN], true] + end + + it "should return the BOOLEAN token and 'false' if the matched term is the string 'false'" do + keyword = stub 'keyword', :name => :FALSE + Puppet::Parser::Lexer::KEYWORDS.expects(:lookup).returns(keyword) + @token.convert(stub('lexer'), "false").should == [Puppet::Parser::Lexer::TOKENS[:BOOLEAN], false] + end +end + +describe Puppet::Parser::Lexer::TOKENS[:NUMBER] do + before { @token = Puppet::Parser::Lexer::TOKENS[:NUMBER] } + + it "should match against numeric terms" do + @token.regex.should =~ "2982383139" + end + + it "should return the NAME token and the value" do + @token.convert(stub("lexer"), "myval").should == [Puppet::Parser::Lexer::TOKENS[:NAME], "myval"] + end +end + +describe Puppet::Parser::Lexer::TOKENS[:COMMENT] do + before { @token = Puppet::Parser::Lexer::TOKENS[:COMMENT] } + + it "should match against lines starting with '#'" do + @token.regex.should =~ "# this is a comment" + end + + it "should be marked to get skipped" do + @token.skip?.should be_true + end +end + +describe Puppet::Parser::Lexer::TOKENS[:RETURN] do + before { @token = Puppet::Parser::Lexer::TOKENS[:RETURN] } + + it "should match against carriage returns" do + @token.regex.should =~ "\n" + end + + it "should be marked to initiate text skipping" do + @token.skip_text.should be_true + end + + it "should be marked to increment the line" do + @token.incr_line.should be_true + end +end + +describe Puppet::Parser::Lexer::TOKENS[:SQUOTE] do + before { @token = Puppet::Parser::Lexer::TOKENS[:SQUOTE] } + + it "should match against single quotes" do + @token.regex.should =~ "'" + end + + it "should slurp the rest of the quoted string" do + lexer = stub("lexer") + lexer.expects(:slurpstring).with("myval").returns("otherval") + @token.convert(lexer, "myval") + end + + it "should return the SQTEXT token with the slurped string" do + lexer = stub("lexer") + lexer.stubs(:slurpstring).with("myval").returns("otherval") + @token.convert(lexer, "myval").should == [Puppet::Parser::Lexer::TOKENS[:SQTEXT], "otherval"] + end +end + +describe Puppet::Parser::Lexer::TOKENS[:DQUOTE] do + before { @token = Puppet::Parser::Lexer::TOKENS[:DQUOTE] } + + it "should match against single quotes" do + @token.regex.should =~ '"' + end + + it "should slurp the rest of the quoted string" do + lexer = stub("lexer") + lexer.expects(:slurpstring).with("myval").returns("otherval") + @token.convert(lexer, "myval") + end + + it "should return the DQTEXT token with the slurped string" do + lexer = stub("lexer") + lexer.stubs(:slurpstring).with("myval").returns("otherval") + @token.convert(lexer, "myval").should == [Puppet::Parser::Lexer::TOKENS[:DQTEXT], "otherval"] + end +end + +describe Puppet::Parser::Lexer::TOKENS[:VARIABLE] do + before { @token = Puppet::Parser::Lexer::TOKENS[:VARIABLE] } + + it "should match against alpha words prefixed with '$'" do + @token.regex.should =~ '$this_var' + end + + it "should return the VARIABLE token and the variable name stripped of the '$'" do + @token.convert(stub("lexer"), "$myval").should == [Puppet::Parser::Lexer::TOKENS[:VARIABLE], "myval"] + end +end + +# FIXME: We need to rewrite all of these tests, but I just don't want to take the time right now. +describe "Puppet::Parser::Lexer in the old tests" do + before { @lexer = Puppet::Parser::Lexer.new } + + it "should do simple lexing" do + strings = { +%q{\\} => [[:BACKSLASH,"\\"],[false,false]], +%q{simplest scanner test} => [[:NAME,"simplest"],[:NAME,"scanner"],[:NAME,"test"],[false,false]], +%q{returned scanner test +} => [[:NAME,"returned"],[:NAME,"scanner"],[:NAME,"test"],[false,false]] + } + strings.each { |str,ary| + @lexer.string = str + @lexer.fullscan().should == ary + } + end + + it "should correctly lex quoted strings" do + strings = { +%q{a simple "scanner" test +} => [[:NAME,"a"],[:NAME,"simple"],[:DQTEXT,"scanner"],[:NAME,"test"],[false,false]], +%q{a simple 'single quote scanner' test +} => [[:NAME,"a"],[:NAME,"simple"],[:SQTEXT,"single quote scanner"],[:NAME,"test"],[false,false]], +%q{a harder 'a $b \c"' +} => [[:NAME,"a"],[:NAME,"harder"],[:SQTEXT,'a $b \c"'],[false,false]], +%q{a harder "scanner test" +} => [[:NAME,"a"],[:NAME,"harder"],[:DQTEXT,"scanner test"],[false,false]], +%q{a hardest "scanner \"test\"" +} => [[:NAME,"a"],[:NAME,"hardest"],[:DQTEXT,'scanner "test"'],[false,false]], +%q{a hardestest "scanner \"test\" +" +} => [[:NAME,"a"],[:NAME,"hardestest"],[:DQTEXT,'scanner "test" +'],[false,false]], +%q{function("call")} => [[:NAME,"function"],[:LPAREN,"("],[:DQTEXT,'call'],[:RPAREN,")"],[false,false]] +} + strings.each { |str,array| + @lexer.string = str + @lexer.fullscan().should == array + } + end + + it "should fail usefully" do + strings = %w{ + ^ + } + strings.each { |str| + @lexer.string = str + lambda { @lexer.fullscan() }.should raise_error(RuntimeError) + } + end + + it "should fail if the string is not set" do + lambda { @lexer.fullscan() }.should raise_error(Puppet::LexError) + end + + it "should correctly identify keywords" do + @lexer.string = "case" + @lexer.fullscan.should == [[:CASE, "case"], [false, false]] + end + + it "should correctly match strings" do + names = %w{this is a bunch of names} + types = %w{Many Different Words A Word} + words = %w{differently Cased words A a} + + names.each { |t| + @lexer.string = t + @lexer.fullscan.should == [[:NAME,t],[false,false]] + } + types.each { |t| + @lexer.string = t + @lexer.fullscan.should == [[:CLASSREF,t],[false,false]] + } + end + + it "should correctly parse empty strings" do + bit = '$var = ""' + + @lexer.string = bit + + lambda { @lexer.fullscan }.should_not raise_error + end + + it "should correctly parse virtual resources" do + string = "@type {" + + @lexer.string = string + + @lexer.fullscan.should == [[:AT, "@"], [:NAME, "type"], [:LBRACE, "{"], [false,false]] + end + + it "should correctly deal with namespaces" do + @lexer.string = %{class myclass} + + @lexer.fullscan + + @lexer.namespace.should == "myclass" + + @lexer.namepop + + @lexer.namespace.should == "" + + @lexer.string = "class base { class sub { class more" + + @lexer.fullscan + + @lexer.namespace.should == "base::sub::more" + + @lexer.namepop + + @lexer.namespace.should == "base::sub" + end + + it "should correctly handle fully qualified names" do + @lexer.string = "class base { class sub::more {" + + @lexer.fullscan + + @lexer.namespace.should == "base::sub::more" + + @lexer.namepop + + @lexer.namespace.should == "base" + end + + it "should correctly lex variables" do + ["$variable", "$::variable", "$qualified::variable", "$further::qualified::variable"].each do |string| + @lexer.string = string + + @lexer.scan do |t, s| + t.should == :VARIABLE + string.sub(/^\$/, '').should == s + break + end + end + end + + # #774 + it "should correctly parse the CLASSREF token" do + string = ["Foo", "::Foo","Foo::Bar","::Foo::Bar"] + + string.each do |foo| + @lexer.string = foo + @lexer.fullscan[0].should == [:CLASSREF, foo] + end + end +end + +require 'puppettest/support/utils' +describe "Puppet::Parser::Lexer in the old tests when lexing example files" do + extend PuppetTest + extend PuppetTest::Support::Utils + textfiles() do |file| + it "should correctly lex #{file}" do + lexer = Puppet::Parser::Lexer.new() + lexer.file = file + lambda { lexer.fullscan() }.should_not raise_error + end + end +end -- cgit From 5a0e34b4f8da22e1830ec7d0a730c3686665bceb Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Fri, 8 Feb 2008 14:25:52 -0600 Subject: Refactoring the AST classes just a bit. I realized that all of the evaluate() methods only ever accepted a scope, and sometimes one other option, so I switched them all to use named arguments instead of a hash. --- spec/unit/parser/ast/definition.rb | 6 +++--- spec/unit/parser/resource.rb | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'spec/unit/parser') diff --git a/spec/unit/parser/ast/definition.rb b/spec/unit/parser/ast/definition.rb index a27fb4721..1c84f5c5f 100755 --- a/spec/unit/parser/ast/definition.rb +++ b/spec/unit/parser/ast/definition.rb @@ -21,12 +21,12 @@ describe Puppet::Parser::AST::Definition, "when evaluating" do it "should create a new scope" do scope = nil code = mock 'code' - code.expects(:safeevaluate).with do |options| - options[:scope].object_id.should_not == @scope.object_id + code.expects(:safeevaluate).with do |scope| + scope.object_id.should_not == @scope.object_id true end @definition.stubs(:code).returns(code) - @definition.evaluate(:scope => @scope, :resource => @resource) + @definition.evaluate(@scope, @resource) end # it "should copy its namespace to the scope" diff --git a/spec/unit/parser/resource.rb b/spec/unit/parser/resource.rb index 319d8f7d8..36e104fb1 100755 --- a/spec/unit/parser/resource.rb +++ b/spec/unit/parser/resource.rb @@ -21,20 +21,20 @@ describe Puppet::Parser::Resource, " when evaluating" do it "should evaluate the associated AST definition" do res = @type.new(:type => "mydefine", :title => "whatever", :scope => @scope, :source => @source) - @definition.expects(:evaluate).with(:scope => @scope, :resource => res) + @definition.expects(:evaluate).with(@scope, res) res.evaluate end it "should evaluate the associated AST class" do res = @type.new(:type => "class", :title => "myclass", :scope => @scope, :source => @source) - @class.expects(:evaluate).with(:scope => @scope, :resource => res) + @class.expects(:evaluate).with(@scope, res) res.evaluate end it "should evaluate the associated AST node" do res = @type.new(:type => "node", :title => "mynode", :scope => @scope, :source => @source) - @nodedef.expects(:evaluate).with(:scope => @scope, :resource => res) + @nodedef.expects(:evaluate).with(@scope, res) res.evaluate end end -- cgit From fb4bdc0b02bba1291cb78ccd5c2a3198d3929d69 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Fri, 8 Feb 2008 13:54:53 -0800 Subject: More AST refactoring -- each of the code wrapping classes just returns a resource from its evaluate() method, and all of the work is done in the evaluate_code method. This makes the code cleaner, because it means 1) evaluate() has the same prototype as all of the other AST classes, 2) evaluate() is no longer called indirectly through the Parser Resource class, and 3) the classes themselves are responsible for creating the resources, rather than it being done in the Compile class. --- spec/unit/parser/ast/definition.rb | 2 +- spec/unit/parser/resource.rb | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'spec/unit/parser') diff --git a/spec/unit/parser/ast/definition.rb b/spec/unit/parser/ast/definition.rb index 1c84f5c5f..fae2851e3 100755 --- a/spec/unit/parser/ast/definition.rb +++ b/spec/unit/parser/ast/definition.rb @@ -26,7 +26,7 @@ describe Puppet::Parser::AST::Definition, "when evaluating" do true end @definition.stubs(:code).returns(code) - @definition.evaluate(@scope, @resource) + @definition.evaluate_code(@resource) end # it "should copy its namespace to the scope" diff --git a/spec/unit/parser/resource.rb b/spec/unit/parser/resource.rb index 36e104fb1..099cfd05e 100755 --- a/spec/unit/parser/resource.rb +++ b/spec/unit/parser/resource.rb @@ -21,20 +21,20 @@ describe Puppet::Parser::Resource, " when evaluating" do it "should evaluate the associated AST definition" do res = @type.new(:type => "mydefine", :title => "whatever", :scope => @scope, :source => @source) - @definition.expects(:evaluate).with(@scope, res) + @definition.expects(:evaluate_code).with(res) res.evaluate end it "should evaluate the associated AST class" do res = @type.new(:type => "class", :title => "myclass", :scope => @scope, :source => @source) - @class.expects(:evaluate).with(@scope, res) + @class.expects(:evaluate_code).with(res) res.evaluate end it "should evaluate the associated AST node" do res = @type.new(:type => "node", :title => "mynode", :scope => @scope, :source => @source) - @nodedef.expects(:evaluate).with(@scope, res) + @nodedef.expects(:evaluate_code).with(res) res.evaluate end end -- cgit From 194e7309c9c481f7e67bd63b13e2fc80fe0a4f00 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Mon, 11 Feb 2008 12:37:00 -0800 Subject: Moving all of the tests for Puppet::Parser::Compile to rspec, so I can refactor the class to more heavily rely on a Node::Catalog instead of doing its own resource container management. --- spec/unit/parser/compile.rb | 364 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 333 insertions(+), 31 deletions(-) (limited to 'spec/unit/parser') diff --git a/spec/unit/parser/compile.rb b/spec/unit/parser/compile.rb index 092bece0c..a72713360 100755 --- a/spec/unit/parser/compile.rb +++ b/spec/unit/parser/compile.rb @@ -2,12 +2,18 @@ require File.dirname(__FILE__) + '/../../spec_helper' -describe Puppet::Parser::Compile, " when compiling" do - before do - @node = stub 'node', :name => 'mynode' - @parser = stub 'parser', :version => "1.0" +module CompileTesting + def setup + @node = Puppet::Node.new "testnode" + @parser = Puppet::Parser::Parser.new :environment => "development" + + @scope = stub 'scope', :resource => stub("scope_resource"), :source => mock("source") @compile = Puppet::Parser::Compile.new(@node, @parser) end +end + +describe Puppet::Parser::Compile, " when compiling" do + include CompileTesting def compile_methods [:set_node_parameters, :evaluate_main, :evaluate_ast_node, :evaluate_node_classes, :evaluate_generators, :fail_on_unevaluated, @@ -37,7 +43,7 @@ describe Puppet::Parser::Compile, " when compiling" do @node.stubs(:classes).returns(classes) @compile.expects(:evaluate_classes).with(classes, @compile.topscope) - @compile.send :evaluate_node_classes + @compile.class.publicize_methods(:evaluate_node_classes) { @compile.evaluate_node_classes } end it "should enable ast_nodes if the parser has any nodes" do @@ -49,15 +55,143 @@ describe Puppet::Parser::Compile, " when compiling" do @parser.expects(:nodes).returns({}) @compile.ast_nodes?.should be_false end + + it "should evaluate the main class if it exists" do + compile_stub(:evaluate_main) + main_class = mock 'main_class' + main_class.expects(:evaluate_code).with { |r| r.is_a?(Puppet::Parser::Resource) } + @compile.topscope.expects(:source=).with(main_class) + @parser.stubs(:findclass).with("", "").returns(main_class) + + @compile.compile + end + + it "should evaluate any node classes" do + @node.stubs(:classes).returns(%w{one two three four}) + @compile.expects(:evaluate_classes).with(%w{one two three four}, @compile.topscope) + @compile.send(:evaluate_node_classes) + end + + it "should evaluate all added collections" do + colls = [] + # And when the collections fail to evaluate. + colls << mock("coll1-false") + colls << mock("coll2-false") + colls.each { |c| c.expects(:evaluate).returns(false) } + + @compile.add_collection(colls[0]) + @compile.add_collection(colls[1]) + + compile_stub(:evaluate_generators) + @compile.compile + end + + it "should ignore builtin resources" do + resource = stub 'builtin', :ref => "File[testing]", :builtin? => true + + scope = stub 'scope', :resource => stub("scope_resource") + @compile.store_resource(scope, resource) + resource.expects(:evaluate).never + + @compile.compile + end + + it "should evaluate unevaluated resources" do + resource = stub 'notevaluated', :ref => "File[testing]", :builtin? => false, :evaluated? => false + scope = stub 'scope', :resource => stub("scope_resource") + @compile.store_resource(scope, resource) + + # We have to now mark the resource as evaluated + resource.expects(:evaluate).with { |*whatever| resource.stubs(:evaluated?).returns true } + + @compile.compile + end + + it "should not evaluate already-evaluated resources" do + resource = stub 'already_evaluated', :ref => "File[testing]", :builtin? => false, :evaluated? => true + scope = stub 'scope', :resource => stub("scope_resource") + @compile.store_resource(scope, resource) + resource.expects(:evaluate).never + + @compile.compile + end + + it "should evaluate unevaluated resources created by evaluating other resources" do + resource = stub 'notevaluated', :ref => "File[testing]", :builtin? => false, :evaluated? => false + scope = stub 'scope', :resource => stub("scope_resource") + @compile.store_resource(scope, resource) + + resource2 = stub 'created', :ref => "File[other]", :builtin? => false, :evaluated? => false + + # We have to now mark the resource as evaluated + resource.expects(:evaluate).with { |*whatever| resource.stubs(:evaluated?).returns(true); @compile.store_resource(scope, resource2) } + resource2.expects(:evaluate).with { |*whatever| resource2.stubs(:evaluated?).returns(true) } + + + @compile.compile + end + + it "should call finish() on all resources" do + # Add a resource that does respond to :finish + yep = stub "finisher", :ref => "File[finish]" + yep.expects(:respond_to?).with(:finish).returns(true) + yep.expects(:finish) + + @compile.store_resource(@scope, yep) + + # And one that does not + dnf = stub "dnf", :ref => "File[dnf]" + dnf.expects(:respond_to?).with(:finish).returns(false) + + @compile.store_resource(@scope, dnf) + + @compile.send(:finish) + end + + it "should add resources that do not conflict with existing resources" do + resource = stub "noconflict", :ref => "File[yay]" + @compile.store_resource(@scope, resource) + + @compile.catalog.should be_vertex(resource) + end + + it "should not fail when conflicting resources are non-isormphic" do + type = stub 'faketype', :isomorphic? => false, :name => "mytype" + Puppet::Type.stubs(:type).with("mytype").returns(type) + + resource1 = stub "iso1conflict", :ref => "Mytype[yay]", :type => "mytype" + resource2 = stub "iso2conflict", :ref => "Mytype[yay]", :type => "mytype" + + @compile.store_resource(@scope, resource1) + lambda { @compile.store_resource(@scope, resource2) }.should_not raise_error + end + + it "should fail to add resources that conflict with existing resources" do + type = stub 'faketype', :isomorphic? => true, :name => "mytype" + Puppet::Type.stubs(:type).with("mytype").returns(type) + + resource1 = stub "iso1conflict", :ref => "Mytype[yay]", :type => "mytype", :file => "eh", :line => 0 + resource2 = stub "iso2conflict", :ref => "Mytype[yay]", :type => "mytype", :file => "eh", :line => 0 + + @compile.store_resource(@scope, resource1) + lambda { @compile.store_resource(@scope, resource2) }.should raise_error(Puppet::ParseError) + end + + it "should have a method for looking up resources" do + resource = stub 'resource', :ref => "Yay[foo]" + @compile.store_resource(@scope, resource) + @compile.findresource("Yay[foo]").should equal(resource) + end + + it "should be able to look resources up by type and title" do + resource = stub 'resource', :ref => "Yay[foo]" + @compile.store_resource(@scope, resource) + @compile.findresource("Yay", "foo").should equal(resource) + end end describe Puppet::Parser::Compile, " when evaluating classes" do - before do - @node = stub 'node', :name => 'mynode' - @parser = stub 'parser', :version => "1.0" - @scope = stub 'scope', :source => mock("source") - @compile = Puppet::Parser::Compile.new(@node, @parser) - end + include CompileTesting it "should fail if there's no source listed for the scope" do scope = stub 'scope', :source => nil @@ -72,12 +206,7 @@ describe Puppet::Parser::Compile, " when evaluating classes" do end describe Puppet::Parser::Compile, " when evaluating collections" do - before do - @node = stub 'node', :name => 'mynode' - @parser = stub 'parser', :version => "1.0" - @scope = stub 'scope', :source => mock("source") - @compile = Puppet::Parser::Compile.new(@node, @parser) - end + include CompileTesting it "should evaluate each collection" do 2.times { |i| @@ -93,16 +222,40 @@ describe Puppet::Parser::Compile, " when evaluating collections" do @compile.class.publicize_methods(:evaluate_collections) { @compile.evaluate_collections } end + + it "should not fail when there are unevaluated resource collections that do not refer to specific resources" do + coll = stub 'coll', :evaluate => false + coll.expects(:resources).returns(nil) + + @compile.add_collection(coll) + + lambda { @compile.compile }.should_not raise_error + end + + it "should fail when there are unevaluated resource collections that refer to a specific resource" do + coll = stub 'coll', :evaluate => false + coll.expects(:resources).returns(:something) + + @compile.add_collection(coll) + + lambda { @compile.compile }.should raise_error(Puppet::ParseError) + end + + it "should fail when there are unevaluated resource collections that refer to multiple specific resources" do + coll = stub 'coll', :evaluate => false + coll.expects(:resources).returns([:one, :two]) + + @compile.add_collection(coll) + + lambda { @compile.compile }.should raise_error(Puppet::ParseError) + end end describe Puppet::Parser::Compile, " when evaluating found classes" do - before do - @node = stub 'node', :name => 'mynode' - @parser = stub 'parser', :version => "1.0" - @scope = stub 'scope', :source => mock("source") - @compile = Puppet::Parser::Compile.new(@node, @parser) + include CompileTesting + before do @class = stub 'class', :classname => "my::class" @scope.stubs(:findclass).with("myclass").returns(@class) @@ -181,11 +334,7 @@ describe Puppet::Parser::Compile, " when evaluating found classes" do 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 + include CompileTesting it "should do nothing" do @compile.expects(:ast_nodes?).returns(false) @@ -197,11 +346,9 @@ describe Puppet::Parser::Compile, " when evaluating AST nodes with no AST nodes 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) + include CompileTesting + before do @nodes = mock 'node_hash' @compile.stubs(:ast_nodes?).returns(true) @compile.parser.stubs(:nodes).returns(@nodes) @@ -279,3 +426,158 @@ describe Puppet::Parser::Compile, " when evaluating AST nodes with AST nodes pre @compile.topscope.should == :my_node_scope end end + +describe Puppet::Parser::Compile, " when initializing" do + include CompileTesting + + it "should set its node attribute" do + @compile.node.should equal(@node) + end + + it "should set its parser attribute" do + @compile.parser.should equal(@parser) + end + + it "should detect when ast nodes are absent" do + @compile.ast_nodes?.should be_false + end + + it "should detect when ast nodes are present" do + @parser.nodes["testing"] = "yay" + @compile.ast_nodes?.should be_true + end +end + +describe Puppet::Parser::Compile do + include CompileTesting + + it "should be able to store references to class scopes" do + lambda { @compile.class_set "myname", "myscope" }.should_not raise_error + end + + it "should be able to retrieve class scopes by name" do + @compile.class_set "myname", "myscope" + @compile.class_scope("myname").should == "myscope" + end + + it "should be able to retrieve class scopes by object" do + klass = mock 'ast_class' + klass.expects(:classname).returns("myname") + @compile.class_set "myname", "myscope" + @compile.class_scope(klass).should == "myscope" + end + + it "should be able to return a class list containing all set classes" do + @compile.class_set "", "empty" + @compile.class_set "one", "yep" + @compile.class_set "two", "nope" + + @compile.classlist.sort.should == %w{one two}.sort + end +end + +describe Puppet::Parser::Compile, "when managing scopes" do + include CompileTesting + + it "should create a top scope" do + @compile.topscope.should be_instance_of(Puppet::Parser::Scope) + end + + it "should be able to create new scopes" do + @compile.newscope(@compile.topscope).should be_instance_of(Puppet::Parser::Scope) + end + + it "should correctly set the level of newly created scopes" do + @compile.newscope(@compile.topscope, :level => 5).level.should == 5 + end + + it "should set the parent scope of the new scope to be the passed-in parent" do + scope = mock 'scope' + newscope = @compile.newscope(scope) + + @compile.parent(newscope).should equal(scope) + end +end + +describe Puppet::Parser::Compile, "when storing compiled resources" do + include CompileTesting + + it "should store the resources" do + Puppet.features.expects(:rails?).returns(true) + Puppet::Rails.expects(:connect) + + resource_table = mock 'resources' + resource_table.expects(:values).returns(:resources) + @compile.instance_variable_set("@resource_table", resource_table) + @compile.expects(:store_to_active_record).with(@node, :resources) + @compile.send(:store) + end + + it "should store to active_record" do + @node.expects(:name).returns("myname") + Puppet::Rails::Host.stubs(:transaction).yields + Puppet::Rails::Host.expects(:store).with(@node, :resources) + @compile.send(:store_to_active_record, @node, :resources) + end +end + +describe Puppet::Parser::Compile, "when managing resource overrides" do + include CompileTesting + + before do + @override = stub 'override', :ref => "My[ref]" + @resource = stub 'resource', :ref => "My[ref]", :builtin? => true + end + + it "should be able to store overrides" do + lambda { @compile.store_override(@override) }.should_not raise_error + end + + it "should apply overrides to the appropriate resources" do + @compile.store_resource(@scope, @resource) + @resource.expects(:merge).with(@override) + + @compile.store_override(@override) + + @compile.compile + end + + it "should accept overrides before the related resource has been created" do + @resource.expects(:merge).with(@override) + + # First store the override + @compile.store_override(@override) + + # Then the resource + @compile.store_resource(@scope, @resource) + + # And compile, so they get resolved + @compile.compile + end + + it "should fail if the compile is finished and resource overrides have not been applied" do + @compile.store_override(@override) + + lambda { @compile.compile }.should raise_error(Puppet::ParseError) + end +end + +# #620 - Nodes and classes should conflict, else classes don't get evaluated +describe Puppet::Parser::Compile, "when evaluating nodes and classes with the same name (#620)" do + include CompileTesting + + before do + @node = stub :nodescope? => true + @class = stub :nodescope? => false + end + + it "should fail if a node already exists with the same name as the class being evaluated" do + @compile.class_set("one", @node) + lambda { @compile.class_set("one", @class) }.should raise_error(Puppet::ParseError) + end + + it "should fail if a class already exists with the same name as the node being evaluated" do + @compile.class_set("one", @class) + lambda { @compile.class_set("one", @node) }.should raise_error(Puppet::ParseError) + end +end -- cgit From 3b740ff7a6ab7127ec5e4935782c33245687c429 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Mon, 11 Feb 2008 13:59:25 -0800 Subject: Converting the Compile class to use a Node::Catalog instance as its resource container, instead of having its own behaviour around resource uniqueness. --- spec/unit/parser/compile.rb | 43 +++++++++++++------------------------------ 1 file changed, 13 insertions(+), 30 deletions(-) (limited to 'spec/unit/parser') diff --git a/spec/unit/parser/compile.rb b/spec/unit/parser/compile.rb index a72713360..d495ac343 100755 --- a/spec/unit/parser/compile.rb +++ b/spec/unit/parser/compile.rb @@ -7,7 +7,8 @@ module CompileTesting @node = Puppet::Node.new "testnode" @parser = Puppet::Parser::Parser.new :environment => "development" - @scope = stub 'scope', :resource => stub("scope_resource"), :source => mock("source") + @scope_resource = stub 'scope_resource', :builtin? => true + @scope = stub 'scope', :resource => @scope_resource, :source => mock("source") @compile = Puppet::Parser::Compile.new(@node, @parser) end end @@ -89,8 +90,7 @@ describe Puppet::Parser::Compile, " when compiling" do it "should ignore builtin resources" do resource = stub 'builtin', :ref => "File[testing]", :builtin? => true - scope = stub 'scope', :resource => stub("scope_resource") - @compile.store_resource(scope, resource) + @compile.store_resource(@scope, resource) resource.expects(:evaluate).never @compile.compile @@ -98,8 +98,7 @@ describe Puppet::Parser::Compile, " when compiling" do it "should evaluate unevaluated resources" do resource = stub 'notevaluated', :ref => "File[testing]", :builtin? => false, :evaluated? => false - scope = stub 'scope', :resource => stub("scope_resource") - @compile.store_resource(scope, resource) + @compile.store_resource(@scope, resource) # We have to now mark the resource as evaluated resource.expects(:evaluate).with { |*whatever| resource.stubs(:evaluated?).returns true } @@ -109,8 +108,7 @@ describe Puppet::Parser::Compile, " when compiling" do it "should not evaluate already-evaluated resources" do resource = stub 'already_evaluated', :ref => "File[testing]", :builtin? => false, :evaluated? => true - scope = stub 'scope', :resource => stub("scope_resource") - @compile.store_resource(scope, resource) + @compile.store_resource(@scope, resource) resource.expects(:evaluate).never @compile.compile @@ -118,13 +116,12 @@ describe Puppet::Parser::Compile, " when compiling" do it "should evaluate unevaluated resources created by evaluating other resources" do resource = stub 'notevaluated', :ref => "File[testing]", :builtin? => false, :evaluated? => false - scope = stub 'scope', :resource => stub("scope_resource") - @compile.store_resource(scope, resource) + @compile.store_resource(@scope, resource) resource2 = stub 'created', :ref => "File[other]", :builtin? => false, :evaluated? => false # We have to now mark the resource as evaluated - resource.expects(:evaluate).with { |*whatever| resource.stubs(:evaluated?).returns(true); @compile.store_resource(scope, resource2) } + resource.expects(:evaluate).with { |*whatever| resource.stubs(:evaluated?).returns(true); @compile.store_resource(@scope, resource2) } resource2.expects(:evaluate).with { |*whatever| resource2.stubs(:evaluated?).returns(true) } @@ -133,15 +130,13 @@ describe Puppet::Parser::Compile, " when compiling" do it "should call finish() on all resources" do # Add a resource that does respond to :finish - yep = stub "finisher", :ref => "File[finish]" - yep.expects(:respond_to?).with(:finish).returns(true) - yep.expects(:finish) + resource = Puppet::Parser::Resource.new :scope => @scope, :type => "file", :title => "finish" + resource.expects(:finish) - @compile.store_resource(@scope, yep) + @compile.store_resource(@scope, resource) # And one that does not dnf = stub "dnf", :ref => "File[dnf]" - dnf.expects(:respond_to?).with(:finish).returns(false) @compile.store_resource(@scope, dnf) @@ -155,17 +150,6 @@ describe Puppet::Parser::Compile, " when compiling" do @compile.catalog.should be_vertex(resource) end - it "should not fail when conflicting resources are non-isormphic" do - type = stub 'faketype', :isomorphic? => false, :name => "mytype" - Puppet::Type.stubs(:type).with("mytype").returns(type) - - resource1 = stub "iso1conflict", :ref => "Mytype[yay]", :type => "mytype" - resource2 = stub "iso2conflict", :ref => "Mytype[yay]", :type => "mytype" - - @compile.store_resource(@scope, resource1) - lambda { @compile.store_resource(@scope, resource2) }.should_not raise_error - end - it "should fail to add resources that conflict with existing resources" do type = stub 'faketype', :isomorphic? => true, :name => "mytype" Puppet::Type.stubs(:type).with("mytype").returns(type) @@ -174,7 +158,7 @@ describe Puppet::Parser::Compile, " when compiling" do resource2 = stub "iso2conflict", :ref => "Mytype[yay]", :type => "mytype", :file => "eh", :line => 0 @compile.store_resource(@scope, resource1) - lambda { @compile.store_resource(@scope, resource2) }.should raise_error(Puppet::ParseError) + lambda { @compile.store_resource(@scope, resource2) }.should raise_error(ArgumentError) end it "should have a method for looking up resources" do @@ -506,9 +490,8 @@ describe Puppet::Parser::Compile, "when storing compiled resources" do Puppet.features.expects(:rails?).returns(true) Puppet::Rails.expects(:connect) - resource_table = mock 'resources' - resource_table.expects(:values).returns(:resources) - @compile.instance_variable_set("@resource_table", resource_table) + @compile.catalog.expects(:vertices).returns(:resources) + @compile.expects(:store_to_active_record).with(@node, :resources) @compile.send(:store) end -- cgit From 6a4cf6c978e8c8aebba4ed0f16d3de7bb31a0ce0 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Mon, 11 Feb 2008 17:24:02 -0600 Subject: Fixed #1030 - class and definition evaluation has been significantly refactored, fixing this problem and making the whole interplay between the classes, definitions, and nodes, and the Compile class much cleaner. --- spec/unit/parser/ast/hostclass.rb | 131 ++++++++++++++++++++++++ spec/unit/parser/compile.rb | 206 +++++++++++++++++--------------------- 2 files changed, 224 insertions(+), 113 deletions(-) create mode 100755 spec/unit/parser/ast/hostclass.rb (limited to 'spec/unit/parser') diff --git a/spec/unit/parser/ast/hostclass.rb b/spec/unit/parser/ast/hostclass.rb new file mode 100755 index 000000000..b1e8a48ea --- /dev/null +++ b/spec/unit/parser/ast/hostclass.rb @@ -0,0 +1,131 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../../spec_helper' + +module HostClassTesting + def setup + @node = Puppet::Node.new "testnode" + @parser = Puppet::Parser::Parser.new :environment => "development" + @scope_resource = stub 'scope_resource', :builtin? => true + @compile = Puppet::Parser::Compile.new(@node, @parser) + + @scope = @compile.topscope + end +end + +describe Puppet::Parser::AST::HostClass, "when evaluating" do + include HostClassTesting + + before do + @top = @parser.newclass "top" + @middle = @parser.newclass "middle", :parent => "top" + end + + it "should create a resource that references itself" do + @top.evaluate(@scope) + + @compile.catalog.resource(:class, "top").should be_instance_of(Puppet::Parser::Resource) + end + + it "should evaluate the parent class if one exists" do + @middle.evaluate(@scope) + + @compile.catalog.resource(:class, "top").should be_instance_of(Puppet::Parser::Resource) + end + + it "should fail to evaluate if a parent class is defined but cannot be found" do + othertop = @parser.newclass "something", :parent => "yay" + lambda { othertop.evaluate(@scope) }.should raise_error(Puppet::ParseError) + end + + it "should not create a new resource if one already exists" do + @compile.catalog.expects(:resource).with(:class, "top").returns("something") + @compile.catalog.expects(:add_resource).never + @top.evaluate(@scope) + end + + it "should not create a new parent resource if one already exists and it has a parent class" do + @top.evaluate(@scope) + + top_resource = @compile.catalog.resource(:class, "top") + + @middle.evaluate(@scope) + + @compile.catalog.resource(:class, "top").should equal(top_resource) + end + + # #795 - tag before evaluation. + it "should tag the catalog with the resource tags when it is evaluated" do + @middle.evaluate(@scope) + + @compile.catalog.should be_tagged("middle") + end + + it "should tag the catalog with the parent class tags when it is evaluated" do + @middle.evaluate(@scope) + + @compile.catalog.should be_tagged("top") + end +end + +describe Puppet::Parser::AST::HostClass, "when evaluating code" do + include HostClassTesting + + before do + @top_resource = stub "top_resource" + @top = @parser.newclass "top", :code => @top_resource + + @middle_resource = stub "middle_resource" + @middle = @parser.newclass "top::middle", :parent => "top", :code => @middle_resource + end + + it "should set its namespace to its fully qualified name" do + @middle.namespace.should == "top::middle" + end + + it "should evaluate the code referred to by the class" do + @top_resource.expects(:safeevaluate) + + resource = @top.evaluate(@scope) + + @top.evaluate_code(resource) + end + + it "should evaluate the parent class's code if it has a parent" do + @top_resource.expects(:safeevaluate) + @middle_resource.expects(:safeevaluate) + + resource = @middle.evaluate(@scope) + + @middle.evaluate_code(resource) + end + + it "should not evaluate the parent class's code if the parent has already been evaluated" do + @top_resource.stubs(:safeevaluate) + resource = @top.evaluate(@scope) + @top.evaluate_code(resource) + + @top_resource.expects(:safeevaluate).never + @middle_resource.stubs(:safeevaluate) + resource = @middle.evaluate(@scope) + @middle.evaluate_code(resource) + end + + it "should use the parent class's scope as its parent scope" do + @top_resource.stubs(:safeevaluate) + @middle_resource.stubs(:safeevaluate) + resource = @middle.evaluate(@scope) + @middle.evaluate_code(resource) + + @compile.class_scope(@middle).parent.should equal(@compile.class_scope(@top)) + end + + it "should add the parent class's namespace to its namespace search path" do + @top_resource.stubs(:safeevaluate) + @middle_resource.stubs(:safeevaluate) + resource = @middle.evaluate(@scope) + @middle.evaluate_code(resource) + + @compile.class_scope(@middle).namespaces.should be_include(@top.namespace) + end +end diff --git a/spec/unit/parser/compile.rb b/spec/unit/parser/compile.rb index d495ac343..ff205f7a5 100755 --- a/spec/unit/parser/compile.rb +++ b/spec/unit/parser/compile.rb @@ -13,6 +13,78 @@ module CompileTesting end end +describe Puppet::Parser::Compile do + include CompileTesting + + it "should be able to store references to class scopes" do + lambda { @compile.class_set "myname", "myscope" }.should_not raise_error + end + + it "should be able to retrieve class scopes by name" do + @compile.class_set "myname", "myscope" + @compile.class_scope("myname").should == "myscope" + end + + it "should be able to retrieve class scopes by object" do + klass = mock 'ast_class' + klass.expects(:classname).returns("myname") + @compile.class_set "myname", "myscope" + @compile.class_scope(klass).should == "myscope" + end + + it "should be able to return a class list containing all set classes" do + @compile.class_set "", "empty" + @compile.class_set "one", "yep" + @compile.class_set "two", "nope" + + @compile.classlist.sort.should == %w{one two}.sort + end +end + +describe Puppet::Parser::Compile, " when initializing" do + include CompileTesting + + it "should set its node attribute" do + @compile.node.should equal(@node) + end + + it "should set its parser attribute" do + @compile.parser.should equal(@parser) + end + + it "should detect when ast nodes are absent" do + @compile.ast_nodes?.should be_false + end + + it "should detect when ast nodes are present" do + @parser.nodes["testing"] = "yay" + @compile.ast_nodes?.should be_true + end +end + +describe Puppet::Parser::Compile, "when managing scopes" do + include CompileTesting + + it "should create a top scope" do + @compile.topscope.should be_instance_of(Puppet::Parser::Scope) + end + + it "should be able to create new scopes" do + @compile.newscope(@compile.topscope).should be_instance_of(Puppet::Parser::Scope) + end + + it "should correctly set the level of newly created scopes" do + @compile.newscope(@compile.topscope, :level => 5).level.should == 5 + end + + it "should set the parent scope of the new scope to be the passed-in parent" do + scope = mock 'scope' + newscope = @compile.newscope(scope) + + @compile.parent(newscope).should equal(scope) + end +end + describe Puppet::Parser::Compile, " when compiling" do include CompileTesting @@ -174,21 +246,6 @@ describe Puppet::Parser::Compile, " when compiling" do end end -describe Puppet::Parser::Compile, " when evaluating classes" do - include CompileTesting - - it "should fail if there's no source listed for the scope" do - scope = stub 'scope', :source => nil - proc { @compile.evaluate_classes(%w{one two}, scope) }.should raise_error(Puppet::DevError) - end - - it "should tag the catalog with the name of each not-found class" do - @compile.catalog.expects(:tag).with("notfound") - @scope.expects(:findclass).with("notfound").returns(nil) - @compile.evaluate_classes(%w{notfound}, @scope) - end -end - describe Puppet::Parser::Compile, " when evaluating collections" do include CompileTesting @@ -235,6 +292,20 @@ describe Puppet::Parser::Compile, " when evaluating collections" do end end +describe Puppet::Parser::Compile, "when told to evaluate missing classes" do + include CompileTesting + + it "should fail if there's no source listed for the scope" do + scope = stub 'scope', :source => nil + proc { @compile.evaluate_classes(%w{one two}, scope) }.should raise_error(Puppet::DevError) + end + + it "should tag the catalog with the name of each not-found class" do + @compile.catalog.expects(:tag).with("notfound") + @scope.expects(:findclass).with("notfound").returns(nil) + @compile.evaluate_classes(%w{notfound}, @scope) + end +end describe Puppet::Parser::Compile, " when evaluating found classes" do include CompileTesting @@ -243,53 +314,33 @@ describe Puppet::Parser::Compile, " when evaluating found classes" do @class = stub 'class', :classname => "my::class" @scope.stubs(:findclass).with("myclass").returns(@class) - @resource = stub 'resource', :ref => 'Class[myclass]' - end - - it "should create a resource for each found class" do - @compile.catalog.stubs(:tag) - - @compile.stubs :store_resource - - Puppet::Parser::Resource.expects(:new).with(:scope => @scope, :source => @scope.source, :title => "my::class", :type => "class").returns(@resource) - @compile.evaluate_classes(%w{myclass}, @scope) + @resource = stub 'resource', :ref => "Class[myclass]" end - it "should store each created resource in the compile" do + it "should evaluate each class" do @compile.catalog.stubs(:tag) - @compile.expects(:store_resource).with(@scope, @resource) - - Puppet::Parser::Resource.stubs(:new).returns(@resource) - @compile.evaluate_classes(%w{myclass}, @scope) - end - - it "should tag the catalog with the fully-qualified name of each found class" do - @compile.catalog.expects(:tag).with("my::class") + @class.expects(:evaluate).with(@scope) - @compile.stubs(:store_resource) - - Puppet::Parser::Resource.stubs(:new).returns(@resource) @compile.evaluate_classes(%w{myclass}, @scope) end it "should not evaluate the resources created for found classes unless asked" do @compile.catalog.stubs(:tag) - @compile.stubs(:store_resource) @resource.expects(:evaluate).never - Puppet::Parser::Resource.stubs(:new).returns(@resource) + @class.expects(:evaluate).returns(@resource) + @compile.evaluate_classes(%w{myclass}, @scope) end it "should immediately evaluate the resources created for found classes when asked" do @compile.catalog.stubs(:tag) - @compile.stubs(:store_resource) @resource.expects(:evaluate) + @class.expects(:evaluate).returns(@resource) - Puppet::Parser::Resource.stubs(:new).returns(@resource) @compile.evaluate_classes(%w{myclass}, @scope, false) end @@ -313,6 +364,7 @@ describe Puppet::Parser::Compile, " when evaluating found classes" do @scope.stubs(:findclass).with("notfound").returns(nil) Puppet::Parser::Resource.stubs(:new).returns(@resource) + @class.stubs :evaluate @compile.evaluate_classes(%w{myclass notfound}, @scope).should == %w{myclass} end end @@ -411,78 +463,6 @@ describe Puppet::Parser::Compile, " when evaluating AST nodes with AST nodes pre end end -describe Puppet::Parser::Compile, " when initializing" do - include CompileTesting - - it "should set its node attribute" do - @compile.node.should equal(@node) - end - - it "should set its parser attribute" do - @compile.parser.should equal(@parser) - end - - it "should detect when ast nodes are absent" do - @compile.ast_nodes?.should be_false - end - - it "should detect when ast nodes are present" do - @parser.nodes["testing"] = "yay" - @compile.ast_nodes?.should be_true - end -end - -describe Puppet::Parser::Compile do - include CompileTesting - - it "should be able to store references to class scopes" do - lambda { @compile.class_set "myname", "myscope" }.should_not raise_error - end - - it "should be able to retrieve class scopes by name" do - @compile.class_set "myname", "myscope" - @compile.class_scope("myname").should == "myscope" - end - - it "should be able to retrieve class scopes by object" do - klass = mock 'ast_class' - klass.expects(:classname).returns("myname") - @compile.class_set "myname", "myscope" - @compile.class_scope(klass).should == "myscope" - end - - it "should be able to return a class list containing all set classes" do - @compile.class_set "", "empty" - @compile.class_set "one", "yep" - @compile.class_set "two", "nope" - - @compile.classlist.sort.should == %w{one two}.sort - end -end - -describe Puppet::Parser::Compile, "when managing scopes" do - include CompileTesting - - it "should create a top scope" do - @compile.topscope.should be_instance_of(Puppet::Parser::Scope) - end - - it "should be able to create new scopes" do - @compile.newscope(@compile.topscope).should be_instance_of(Puppet::Parser::Scope) - end - - it "should correctly set the level of newly created scopes" do - @compile.newscope(@compile.topscope, :level => 5).level.should == 5 - end - - it "should set the parent scope of the new scope to be the passed-in parent" do - scope = mock 'scope' - newscope = @compile.newscope(scope) - - @compile.parent(newscope).should equal(scope) - end -end - describe Puppet::Parser::Compile, "when storing compiled resources" do include CompileTesting -- cgit From e247b56d9941b4a636d3a3d9935d6b9cd9b199ea Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Mon, 11 Feb 2008 17:33:12 -0600 Subject: Changing some methods in the Compile class to be more internally consistent (switched store_resource to add_resource, and store_override to add_override). --- spec/unit/parser/collector.rb | 10 +++++----- spec/unit/parser/compile.rb | 40 ++++++++++++++++++++-------------------- 2 files changed, 25 insertions(+), 25 deletions(-) (limited to 'spec/unit/parser') diff --git a/spec/unit/parser/collector.rb b/spec/unit/parser/collector.rb index 9b5eab1f4..aedbe1b9a 100755 --- a/spec/unit/parser/collector.rb +++ b/spec/unit/parser/collector.rb @@ -271,7 +271,7 @@ describe Puppet::Parser::Collector, "when collecting exported resources" do @compile.stubs(:resources).returns([]) @scope.stubs(:findresource).returns(nil) - @compile.stubs(:store_resource) + @compile.stubs(:add_resource) @collector.evaluate.should == [resource] end @@ -291,7 +291,7 @@ describe Puppet::Parser::Collector, "when collecting exported resources" do @compile.stubs(:resources).returns([]) @scope.stubs(:findresource).returns(nil) - @compile.expects(:store_resource).with(@scope, resource) + @compile.expects(:add_resource).with(@scope, resource) @collector.evaluate.should == [resource] end @@ -312,7 +312,7 @@ describe Puppet::Parser::Collector, "when collecting exported resources" do @compile.stubs(:resources).returns([]) @scope.stubs(:findresource).returns(nil) - @compile.stubs(:store_resource) + @compile.stubs(:add_resource) @collector.evaluate end @@ -331,7 +331,7 @@ describe Puppet::Parser::Collector, "when collecting exported resources" do @compile.stubs(:resources).returns([]) @scope.stubs(:findresource).returns(inmemory) - @compile.stubs(:store_resource) + @compile.stubs(:add_resource) proc { @collector.evaluate }.should raise_error(Puppet::ParseError) end @@ -350,7 +350,7 @@ describe Puppet::Parser::Collector, "when collecting exported resources" do @compile.stubs(:resources).returns([]) @scope.stubs(:findresource).returns(inmemory) - @compile.stubs(:store_resource) + @compile.stubs(:add_resource) proc { @collector.evaluate }.should_not raise_error(Puppet::ParseError) end diff --git a/spec/unit/parser/compile.rb b/spec/unit/parser/compile.rb index ff205f7a5..65e7befca 100755 --- a/spec/unit/parser/compile.rb +++ b/spec/unit/parser/compile.rb @@ -162,7 +162,7 @@ describe Puppet::Parser::Compile, " when compiling" do it "should ignore builtin resources" do resource = stub 'builtin', :ref => "File[testing]", :builtin? => true - @compile.store_resource(@scope, resource) + @compile.add_resource(@scope, resource) resource.expects(:evaluate).never @compile.compile @@ -170,7 +170,7 @@ describe Puppet::Parser::Compile, " when compiling" do it "should evaluate unevaluated resources" do resource = stub 'notevaluated', :ref => "File[testing]", :builtin? => false, :evaluated? => false - @compile.store_resource(@scope, resource) + @compile.add_resource(@scope, resource) # We have to now mark the resource as evaluated resource.expects(:evaluate).with { |*whatever| resource.stubs(:evaluated?).returns true } @@ -180,7 +180,7 @@ describe Puppet::Parser::Compile, " when compiling" do it "should not evaluate already-evaluated resources" do resource = stub 'already_evaluated', :ref => "File[testing]", :builtin? => false, :evaluated? => true - @compile.store_resource(@scope, resource) + @compile.add_resource(@scope, resource) resource.expects(:evaluate).never @compile.compile @@ -188,12 +188,12 @@ describe Puppet::Parser::Compile, " when compiling" do it "should evaluate unevaluated resources created by evaluating other resources" do resource = stub 'notevaluated', :ref => "File[testing]", :builtin? => false, :evaluated? => false - @compile.store_resource(@scope, resource) + @compile.add_resource(@scope, resource) resource2 = stub 'created', :ref => "File[other]", :builtin? => false, :evaluated? => false # We have to now mark the resource as evaluated - resource.expects(:evaluate).with { |*whatever| resource.stubs(:evaluated?).returns(true); @compile.store_resource(@scope, resource2) } + resource.expects(:evaluate).with { |*whatever| resource.stubs(:evaluated?).returns(true); @compile.add_resource(@scope, resource2) } resource2.expects(:evaluate).with { |*whatever| resource2.stubs(:evaluated?).returns(true) } @@ -205,19 +205,19 @@ describe Puppet::Parser::Compile, " when compiling" do resource = Puppet::Parser::Resource.new :scope => @scope, :type => "file", :title => "finish" resource.expects(:finish) - @compile.store_resource(@scope, resource) + @compile.add_resource(@scope, resource) # And one that does not dnf = stub "dnf", :ref => "File[dnf]" - @compile.store_resource(@scope, dnf) + @compile.add_resource(@scope, dnf) @compile.send(:finish) end it "should add resources that do not conflict with existing resources" do resource = stub "noconflict", :ref => "File[yay]" - @compile.store_resource(@scope, resource) + @compile.add_resource(@scope, resource) @compile.catalog.should be_vertex(resource) end @@ -229,19 +229,19 @@ describe Puppet::Parser::Compile, " when compiling" do resource1 = stub "iso1conflict", :ref => "Mytype[yay]", :type => "mytype", :file => "eh", :line => 0 resource2 = stub "iso2conflict", :ref => "Mytype[yay]", :type => "mytype", :file => "eh", :line => 0 - @compile.store_resource(@scope, resource1) - lambda { @compile.store_resource(@scope, resource2) }.should raise_error(ArgumentError) + @compile.add_resource(@scope, resource1) + lambda { @compile.add_resource(@scope, resource2) }.should raise_error(ArgumentError) end it "should have a method for looking up resources" do resource = stub 'resource', :ref => "Yay[foo]" - @compile.store_resource(@scope, resource) + @compile.add_resource(@scope, resource) @compile.findresource("Yay[foo]").should equal(resource) end it "should be able to look resources up by type and title" do resource = stub 'resource', :ref => "Yay[foo]" - @compile.store_resource(@scope, resource) + @compile.add_resource(@scope, resource) @compile.findresource("Yay", "foo").should equal(resource) end end @@ -349,7 +349,7 @@ describe Puppet::Parser::Compile, " when evaluating found classes" do @compile.expects(:class_scope).with(@class).returns("something") - @compile.expects(:store_resource).never + @compile.expects(:add_resource).never @resource.expects(:evaluate).never @@ -360,7 +360,7 @@ describe Puppet::Parser::Compile, " when evaluating found classes" do it "should return the list of found classes" do @compile.catalog.stubs(:tag) - @compile.stubs(:store_resource) + @compile.stubs(:add_resource) @scope.stubs(:findclass).with("notfound").returns(nil) Puppet::Parser::Resource.stubs(:new).returns(@resource) @@ -493,14 +493,14 @@ describe Puppet::Parser::Compile, "when managing resource overrides" do end it "should be able to store overrides" do - lambda { @compile.store_override(@override) }.should_not raise_error + lambda { @compile.add_override(@override) }.should_not raise_error end it "should apply overrides to the appropriate resources" do - @compile.store_resource(@scope, @resource) + @compile.add_resource(@scope, @resource) @resource.expects(:merge).with(@override) - @compile.store_override(@override) + @compile.add_override(@override) @compile.compile end @@ -509,17 +509,17 @@ describe Puppet::Parser::Compile, "when managing resource overrides" do @resource.expects(:merge).with(@override) # First store the override - @compile.store_override(@override) + @compile.add_override(@override) # Then the resource - @compile.store_resource(@scope, @resource) + @compile.add_resource(@scope, @resource) # And compile, so they get resolved @compile.compile end it "should fail if the compile is finished and resource overrides have not been applied" do - @compile.store_override(@override) + @compile.add_override(@override) lambda { @compile.compile }.should raise_error(Puppet::ParseError) end -- cgit From 5ebaa8953155d091ed5b5c68c3862c9f695f03c0 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Mon, 11 Feb 2008 17:41:19 -0600 Subject: Refactoring the interface between the Compile class and the AST::Node class to match that to the definitions and AST classes. --- spec/unit/parser/compile.rb | 41 +++++++++++++++-------------------------- 1 file changed, 15 insertions(+), 26 deletions(-) (limited to 'spec/unit/parser') diff --git a/spec/unit/parser/compile.rb b/spec/unit/parser/compile.rb index 65e7befca..3903f6879 100755 --- a/spec/unit/parser/compile.rb +++ b/spec/unit/parser/compile.rb @@ -403,35 +403,24 @@ describe Puppet::Parser::Compile, " when evaluating AST nodes with AST nodes pre 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" + it "should evaluate the first node class matching the node name" do + node_class = stub 'node', :classname => "c", :evaluate_code => nil @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) + node_class.expects(:evaluate).returns(node_resource) - @compile.send(:evaluate_ast_node) + @compile.compile end it "should match the default node if no matching node can be found" do - node_class = stub 'node', :classname => "default" + node_class = stub 'node', :classname => "default", :evaluate_code => nil @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 catalog 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) + node_class.expects(:evaluate).returns(node_resource) - @compile.catalog.expects(:tag).with("c") - @compile.send(:evaluate_ast_node) + @compile.compile end it "should evaluate the node resource immediately rather than using lazy evaluation" do @@ -439,7 +428,7 @@ describe Puppet::Parser::Compile, " when evaluating AST nodes with AST nodes pre @nodes.stubs(:[]).with("c").returns(node_class) node_resource = stub 'node resource', :ref => "Node[c]" - Puppet::Parser::Resource.stubs(:new).returns(node_resource) + node_class.expects(:evaluate).returns(node_resource) node_resource.expects(:evaluate) @@ -447,19 +436,19 @@ describe Puppet::Parser::Compile, " when evaluating AST nodes with AST nodes pre 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]", :evaluate => nil + node_class = stub 'node', :classname => "c", :evaluate => node_resource - node_resource = stub 'node resource', :ref => "Node[c]" - Puppet::Parser::Resource.stubs(:new).returns(node_resource) + @nodes.stubs(:[]).with("c").returns(node_class) # The #evaluate method normally does this. - @compile.class_set(node_class.classname, :my_node_scope) + scope = stub 'scope', :source => "mysource" + @compile.class_set(node_class.classname, scope) node_resource.stubs(:evaluate) - @compile.send(:evaluate_ast_node) + @compile.compile - @compile.topscope.should == :my_node_scope + @compile.topscope.should equal(scope) end end -- cgit From fd0c5cbddec8dc53196a3b84e33e1000c3c0720f Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Mon, 11 Feb 2008 17:59:34 -0600 Subject: Changing the name of the Compile class to Compiler, since it's stupid to have a class named after a verb. --- spec/unit/parser/ast/definition.rb | 4 +- spec/unit/parser/ast/hostclass.rb | 24 +- spec/unit/parser/collector.rb | 60 ++-- spec/unit/parser/compile.rb | 535 --------------------------------- spec/unit/parser/compiler.rb | 535 +++++++++++++++++++++++++++++++++ spec/unit/parser/interpreter.rb | 6 +- spec/unit/parser/resource.rb | 8 +- spec/unit/parser/resource/reference.rb | 8 +- 8 files changed, 590 insertions(+), 590 deletions(-) delete mode 100755 spec/unit/parser/compile.rb create mode 100755 spec/unit/parser/compiler.rb (limited to 'spec/unit/parser') diff --git a/spec/unit/parser/ast/definition.rb b/spec/unit/parser/ast/definition.rb index fae2851e3..ba80894e8 100755 --- a/spec/unit/parser/ast/definition.rb +++ b/spec/unit/parser/ast/definition.rb @@ -12,8 +12,8 @@ describe Puppet::Parser::AST::Definition, "when evaluating" do @source = @parser.newclass "" @definition = @parser.newdefine "mydefine" @node = Puppet::Node.new("yaynode") - @compile = Puppet::Parser::Compile.new(@node, @parser) - @scope = @compile.topscope + @compiler = Puppet::Parser::Compiler.new(@node, @parser) + @scope = @compiler.topscope @resource = Puppet::Parser::Resource.new(:type => "mydefine", :title => "myresource", :scope => @scope, :source => @source) end diff --git a/spec/unit/parser/ast/hostclass.rb b/spec/unit/parser/ast/hostclass.rb index b1e8a48ea..422861857 100755 --- a/spec/unit/parser/ast/hostclass.rb +++ b/spec/unit/parser/ast/hostclass.rb @@ -7,9 +7,9 @@ module HostClassTesting @node = Puppet::Node.new "testnode" @parser = Puppet::Parser::Parser.new :environment => "development" @scope_resource = stub 'scope_resource', :builtin? => true - @compile = Puppet::Parser::Compile.new(@node, @parser) + @compiler = Puppet::Parser::Compiler.new(@node, @parser) - @scope = @compile.topscope + @scope = @compiler.topscope end end @@ -24,13 +24,13 @@ describe Puppet::Parser::AST::HostClass, "when evaluating" do it "should create a resource that references itself" do @top.evaluate(@scope) - @compile.catalog.resource(:class, "top").should be_instance_of(Puppet::Parser::Resource) + @compiler.catalog.resource(:class, "top").should be_instance_of(Puppet::Parser::Resource) end it "should evaluate the parent class if one exists" do @middle.evaluate(@scope) - @compile.catalog.resource(:class, "top").should be_instance_of(Puppet::Parser::Resource) + @compiler.catalog.resource(:class, "top").should be_instance_of(Puppet::Parser::Resource) end it "should fail to evaluate if a parent class is defined but cannot be found" do @@ -39,32 +39,32 @@ describe Puppet::Parser::AST::HostClass, "when evaluating" do end it "should not create a new resource if one already exists" do - @compile.catalog.expects(:resource).with(:class, "top").returns("something") - @compile.catalog.expects(:add_resource).never + @compiler.catalog.expects(:resource).with(:class, "top").returns("something") + @compiler.catalog.expects(:add_resource).never @top.evaluate(@scope) end it "should not create a new parent resource if one already exists and it has a parent class" do @top.evaluate(@scope) - top_resource = @compile.catalog.resource(:class, "top") + top_resource = @compiler.catalog.resource(:class, "top") @middle.evaluate(@scope) - @compile.catalog.resource(:class, "top").should equal(top_resource) + @compiler.catalog.resource(:class, "top").should equal(top_resource) end # #795 - tag before evaluation. it "should tag the catalog with the resource tags when it is evaluated" do @middle.evaluate(@scope) - @compile.catalog.should be_tagged("middle") + @compiler.catalog.should be_tagged("middle") end it "should tag the catalog with the parent class tags when it is evaluated" do @middle.evaluate(@scope) - @compile.catalog.should be_tagged("top") + @compiler.catalog.should be_tagged("top") end end @@ -117,7 +117,7 @@ describe Puppet::Parser::AST::HostClass, "when evaluating code" do resource = @middle.evaluate(@scope) @middle.evaluate_code(resource) - @compile.class_scope(@middle).parent.should equal(@compile.class_scope(@top)) + @compiler.class_scope(@middle).parent.should equal(@compiler.class_scope(@top)) end it "should add the parent class's namespace to its namespace search path" do @@ -126,6 +126,6 @@ describe Puppet::Parser::AST::HostClass, "when evaluating code" do resource = @middle.evaluate(@scope) @middle.evaluate_code(resource) - @compile.class_scope(@middle).namespaces.should be_include(@top.namespace) + @compiler.class_scope(@middle).namespaces.should be_include(@top.namespace) end end diff --git a/spec/unit/parser/collector.rb b/spec/unit/parser/collector.rb index aedbe1b9a..e1ceb23ed 100755 --- a/spec/unit/parser/collector.rb +++ b/spec/unit/parser/collector.rb @@ -79,8 +79,8 @@ describe Puppet::Parser::Collector, "when collecting specific virtual resources" @collector.resources = ["File[virtual1]"] one = mock 'one' one.stubs(:virtual=) - @compile.expects(:delete_collection).with(@collector) - @scope.expects(:compile).returns(@compile) + @compiler.expects(:delete_collection).with(@collector) + @scope.expects(:compiler).returns(@compiler) @scope.stubs(:findresource).with("File[virtual1]").returns(one) @collector.evaluate end @@ -89,7 +89,7 @@ describe Puppet::Parser::Collector, "when collecting specific virtual resources" @collector.resources = ["File[virtual1]"] one = mock 'one' one.stubs(:virtual=) - @compile.expects(:delete_collection).never + @compiler.expects(:delete_collection).never @scope.stubs(:findresource).with("File[virtual1]").returns(nil) @collector.evaluate end @@ -98,8 +98,8 @@ end describe Puppet::Parser::Collector, "when collecting virtual resources" do before do @scope = mock 'scope' - @compile = mock 'compile' - @scope.stubs(:compile).returns(@compile) + @compiler = mock 'compile' + @scope.stubs(:compiler).returns(@compiler) @resource_type = "Mytype" @vquery = proc { |res| true } @@ -113,7 +113,7 @@ describe Puppet::Parser::Collector, "when collecting virtual resources" do one.stubs(:virtual=) two.stubs(:virtual=) - @compile.expects(:resources).returns([one, two]) + @compiler.expects(:resources).returns([one, two]) @collector.evaluate.should == [one, two] end @@ -123,7 +123,7 @@ describe Puppet::Parser::Collector, "when collecting virtual resources" do one.expects(:virtual=).with(false) - @compile.expects(:resources).returns([one]) + @compiler.expects(:resources).returns([one]) @collector.evaluate end @@ -135,7 +135,7 @@ describe Puppet::Parser::Collector, "when collecting virtual resources" do one.stubs(:virtual=) two.stubs(:virtual=) - @compile.expects(:resources).returns([one, two]) + @compiler.expects(:resources).returns([one, two]) @collector.evaluate.should == [one, two] end @@ -147,7 +147,7 @@ describe Puppet::Parser::Collector, "when collecting virtual resources" do one.expects(:virtual=).with(false) two.expects(:virtual=).with(false) - @compile.expects(:resources).returns([one, two]) + @compiler.expects(:resources).returns([one, two]) @collector = Puppet::Parser::Collector.new(@scope, @resource_type, nil, nil, :virtual) @@ -161,7 +161,7 @@ describe Puppet::Parser::Collector, "when collecting virtual resources" do one.expects(:virtual=).with(false) two.expects(:virtual=).never - @compile.expects(:resources).returns([one, two]) + @compiler.expects(:resources).returns([one, two]) @collector.evaluate.should == [one] end @@ -173,7 +173,7 @@ describe Puppet::Parser::Collector, "when collecting virtual resources" do one.expects(:virtual=).never two.expects(:virtual=).never - @compile.expects(:resources).returns([one, two]) + @compiler.expects(:resources).returns([one, two]) @collector.evaluate.should be_false end @@ -187,7 +187,7 @@ describe Puppet::Parser::Collector, "when collecting virtual resources" do one.expects(:virtual=).with(false) two.expects(:virtual=).never - @compile.expects(:resources).returns([one, two]) + @compiler.expects(:resources).returns([one, two]) @collector.evaluate.should == [one] end @@ -198,8 +198,8 @@ describe Puppet::Parser::Collector, "when collecting exported resources" do before do @scope = stub 'scope', :host => "myhost", :debug => nil - @compile = mock 'compile' - @scope.stubs(:compile).returns(@compile) + @compiler = mock 'compile' + @scope.stubs(:compiler).returns(@compiler) @resource_type = "Mytype" @equery = "test = true" @vquery = proc { |r| true } @@ -218,7 +218,7 @@ describe Puppet::Parser::Collector, "when collecting exported resources" do end it "should use initialize the Rails support if ActiveRecord is not connected" do - @compile.stubs(:resources).returns([]) + @compiler.stubs(:resources).returns([]) ActiveRecord::Base.expects(:connected?).returns(false) Puppet::Rails.expects(:init) Puppet::Rails::Host.stubs(:find_by_name).returns(nil) @@ -238,7 +238,7 @@ describe Puppet::Parser::Collector, "when collecting exported resources" do two.stubs(:exported=) two.stubs(:virtual=) - @compile.expects(:resources).returns([one, two]) + @compiler.expects(:resources).returns([one, two]) @collector.evaluate.should == [one, two] end @@ -251,7 +251,7 @@ describe Puppet::Parser::Collector, "when collecting exported resources" do one.stubs(:exported=) one.expects(:virtual=).with(false) - @compile.expects(:resources).returns([one]) + @compiler.expects(:resources).returns([one]) @collector.evaluate.should == [one] end @@ -268,10 +268,10 @@ describe Puppet::Parser::Collector, "when collecting exported resources" do resource.stubs(:exported=) resource.stubs(:virtual=) - @compile.stubs(:resources).returns([]) + @compiler.stubs(:resources).returns([]) @scope.stubs(:findresource).returns(nil) - @compile.stubs(:add_resource) + @compiler.stubs(:add_resource) @collector.evaluate.should == [resource] end @@ -288,10 +288,10 @@ describe Puppet::Parser::Collector, "when collecting exported resources" do resource.stubs(:exported=) resource.stubs(:virtual=) - @compile.stubs(:resources).returns([]) + @compiler.stubs(:resources).returns([]) @scope.stubs(:findresource).returns(nil) - @compile.expects(:add_resource).with(@scope, resource) + @compiler.expects(:add_resource).with(@scope, resource) @collector.evaluate.should == [resource] end @@ -309,10 +309,10 @@ describe Puppet::Parser::Collector, "when collecting exported resources" do resource.expects(:exported=).with(false) resource.stubs(:virtual=) - @compile.stubs(:resources).returns([]) + @compiler.stubs(:resources).returns([]) @scope.stubs(:findresource).returns(nil) - @compile.stubs(:add_resource) + @compiler.stubs(:add_resource) @collector.evaluate end @@ -328,10 +328,10 @@ describe Puppet::Parser::Collector, "when collecting exported resources" do resource = mock 'resource' - @compile.stubs(:resources).returns([]) + @compiler.stubs(:resources).returns([]) @scope.stubs(:findresource).returns(inmemory) - @compile.stubs(:add_resource) + @compiler.stubs(:add_resource) proc { @collector.evaluate }.should raise_error(Puppet::ParseError) end @@ -347,10 +347,10 @@ describe Puppet::Parser::Collector, "when collecting exported resources" do resource = mock 'resource' - @compile.stubs(:resources).returns([]) + @compiler.stubs(:resources).returns([]) @scope.stubs(:findresource).returns(inmemory) - @compile.stubs(:add_resource) + @compiler.stubs(:add_resource) proc { @collector.evaluate }.should_not raise_error(Puppet::ParseError) end @@ -361,14 +361,14 @@ describe Puppet::Parser::Collector, "when building its ActiveRecord query for co before do @scope = stub 'scope', :host => "myhost", :debug => nil - @compile = mock 'compile' - @scope.stubs(:compile).returns(@compile) + @compiler = mock 'compile' + @scope.stubs(:compiler).returns(@compiler) @resource_type = "Mytype" @equery = nil @vquery = proc { |r| true } @collector = Puppet::Parser::Collector.new(@scope, @resource_type, @equery, @vquery, :exported) - @compile.stubs(:resources).returns([]) + @compiler.stubs(:resources).returns([]) ActiveRecord::Base.stubs(:connected?).returns(false) diff --git a/spec/unit/parser/compile.rb b/spec/unit/parser/compile.rb deleted file mode 100755 index 3903f6879..000000000 --- a/spec/unit/parser/compile.rb +++ /dev/null @@ -1,535 +0,0 @@ -#!/usr/bin/env ruby - -require File.dirname(__FILE__) + '/../../spec_helper' - -module CompileTesting - def setup - @node = Puppet::Node.new "testnode" - @parser = Puppet::Parser::Parser.new :environment => "development" - - @scope_resource = stub 'scope_resource', :builtin? => true - @scope = stub 'scope', :resource => @scope_resource, :source => mock("source") - @compile = Puppet::Parser::Compile.new(@node, @parser) - end -end - -describe Puppet::Parser::Compile do - include CompileTesting - - it "should be able to store references to class scopes" do - lambda { @compile.class_set "myname", "myscope" }.should_not raise_error - end - - it "should be able to retrieve class scopes by name" do - @compile.class_set "myname", "myscope" - @compile.class_scope("myname").should == "myscope" - end - - it "should be able to retrieve class scopes by object" do - klass = mock 'ast_class' - klass.expects(:classname).returns("myname") - @compile.class_set "myname", "myscope" - @compile.class_scope(klass).should == "myscope" - end - - it "should be able to return a class list containing all set classes" do - @compile.class_set "", "empty" - @compile.class_set "one", "yep" - @compile.class_set "two", "nope" - - @compile.classlist.sort.should == %w{one two}.sort - end -end - -describe Puppet::Parser::Compile, " when initializing" do - include CompileTesting - - it "should set its node attribute" do - @compile.node.should equal(@node) - end - - it "should set its parser attribute" do - @compile.parser.should equal(@parser) - end - - it "should detect when ast nodes are absent" do - @compile.ast_nodes?.should be_false - end - - it "should detect when ast nodes are present" do - @parser.nodes["testing"] = "yay" - @compile.ast_nodes?.should be_true - end -end - -describe Puppet::Parser::Compile, "when managing scopes" do - include CompileTesting - - it "should create a top scope" do - @compile.topscope.should be_instance_of(Puppet::Parser::Scope) - end - - it "should be able to create new scopes" do - @compile.newscope(@compile.topscope).should be_instance_of(Puppet::Parser::Scope) - end - - it "should correctly set the level of newly created scopes" do - @compile.newscope(@compile.topscope, :level => 5).level.should == 5 - end - - it "should set the parent scope of the new scope to be the passed-in parent" do - scope = mock 'scope' - newscope = @compile.newscope(scope) - - @compile.parent(newscope).should equal(scope) - end -end - -describe Puppet::Parser::Compile, " when compiling" do - include CompileTesting - - def compile_methods - [:set_node_parameters, :evaluate_main, :evaluate_ast_node, :evaluate_node_classes, :evaluate_generators, :fail_on_unevaluated, - :finish, :store, :extract] - end - - # Stub all of the main compile methods except the ones we're specifically interested in. - def compile_stub(*except) - (compile_methods - except).each { |m| @compile.stubs(m) } - end - - it "should set node parameters as variables in the top scope" do - params = {"a" => "b", "c" => "d"} - @node.stubs(:parameters).returns(params) - compile_stub(:set_node_parameters) - @compile.compile - @compile.topscope.lookupvar("a").should == "b" - @compile.topscope.lookupvar("c").should == "d" - end - - it "should evaluate any existing classes named in the node" do - classes = %w{one two three four} - main = stub 'main' - one = stub 'one', :classname => "one" - three = stub 'three', :classname => "three" - @node.stubs(:name).returns("whatever") - @node.stubs(:classes).returns(classes) - - @compile.expects(:evaluate_classes).with(classes, @compile.topscope) - @compile.class.publicize_methods(:evaluate_node_classes) { @compile.evaluate_node_classes } - end - - it "should enable ast_nodes if the parser has any nodes" do - @parser.expects(:nodes).returns(:one => :yay) - @compile.ast_nodes?.should be_true - end - - it "should disable ast_nodes if the parser has no nodes" do - @parser.expects(:nodes).returns({}) - @compile.ast_nodes?.should be_false - end - - it "should evaluate the main class if it exists" do - compile_stub(:evaluate_main) - main_class = mock 'main_class' - main_class.expects(:evaluate_code).with { |r| r.is_a?(Puppet::Parser::Resource) } - @compile.topscope.expects(:source=).with(main_class) - @parser.stubs(:findclass).with("", "").returns(main_class) - - @compile.compile - end - - it "should evaluate any node classes" do - @node.stubs(:classes).returns(%w{one two three four}) - @compile.expects(:evaluate_classes).with(%w{one two three four}, @compile.topscope) - @compile.send(:evaluate_node_classes) - end - - it "should evaluate all added collections" do - colls = [] - # And when the collections fail to evaluate. - colls << mock("coll1-false") - colls << mock("coll2-false") - colls.each { |c| c.expects(:evaluate).returns(false) } - - @compile.add_collection(colls[0]) - @compile.add_collection(colls[1]) - - compile_stub(:evaluate_generators) - @compile.compile - end - - it "should ignore builtin resources" do - resource = stub 'builtin', :ref => "File[testing]", :builtin? => true - - @compile.add_resource(@scope, resource) - resource.expects(:evaluate).never - - @compile.compile - end - - it "should evaluate unevaluated resources" do - resource = stub 'notevaluated', :ref => "File[testing]", :builtin? => false, :evaluated? => false - @compile.add_resource(@scope, resource) - - # We have to now mark the resource as evaluated - resource.expects(:evaluate).with { |*whatever| resource.stubs(:evaluated?).returns true } - - @compile.compile - end - - it "should not evaluate already-evaluated resources" do - resource = stub 'already_evaluated', :ref => "File[testing]", :builtin? => false, :evaluated? => true - @compile.add_resource(@scope, resource) - resource.expects(:evaluate).never - - @compile.compile - end - - it "should evaluate unevaluated resources created by evaluating other resources" do - resource = stub 'notevaluated', :ref => "File[testing]", :builtin? => false, :evaluated? => false - @compile.add_resource(@scope, resource) - - resource2 = stub 'created', :ref => "File[other]", :builtin? => false, :evaluated? => false - - # We have to now mark the resource as evaluated - resource.expects(:evaluate).with { |*whatever| resource.stubs(:evaluated?).returns(true); @compile.add_resource(@scope, resource2) } - resource2.expects(:evaluate).with { |*whatever| resource2.stubs(:evaluated?).returns(true) } - - - @compile.compile - end - - it "should call finish() on all resources" do - # Add a resource that does respond to :finish - resource = Puppet::Parser::Resource.new :scope => @scope, :type => "file", :title => "finish" - resource.expects(:finish) - - @compile.add_resource(@scope, resource) - - # And one that does not - dnf = stub "dnf", :ref => "File[dnf]" - - @compile.add_resource(@scope, dnf) - - @compile.send(:finish) - end - - it "should add resources that do not conflict with existing resources" do - resource = stub "noconflict", :ref => "File[yay]" - @compile.add_resource(@scope, resource) - - @compile.catalog.should be_vertex(resource) - end - - it "should fail to add resources that conflict with existing resources" do - type = stub 'faketype', :isomorphic? => true, :name => "mytype" - Puppet::Type.stubs(:type).with("mytype").returns(type) - - resource1 = stub "iso1conflict", :ref => "Mytype[yay]", :type => "mytype", :file => "eh", :line => 0 - resource2 = stub "iso2conflict", :ref => "Mytype[yay]", :type => "mytype", :file => "eh", :line => 0 - - @compile.add_resource(@scope, resource1) - lambda { @compile.add_resource(@scope, resource2) }.should raise_error(ArgumentError) - end - - it "should have a method for looking up resources" do - resource = stub 'resource', :ref => "Yay[foo]" - @compile.add_resource(@scope, resource) - @compile.findresource("Yay[foo]").should equal(resource) - end - - it "should be able to look resources up by type and title" do - resource = stub 'resource', :ref => "Yay[foo]" - @compile.add_resource(@scope, resource) - @compile.findresource("Yay", "foo").should equal(resource) - end -end - -describe Puppet::Parser::Compile, " when evaluating collections" do - include CompileTesting - - it "should evaluate each collection" do - 2.times { |i| - coll = mock 'coll%s' % i - @compile.add_collection(coll) - - # This is the hard part -- we have to emulate the fact that - # collections delete themselves if they are done evaluating. - coll.expects(:evaluate).with do - @compile.delete_collection(coll) - end - } - - @compile.class.publicize_methods(:evaluate_collections) { @compile.evaluate_collections } - end - - it "should not fail when there are unevaluated resource collections that do not refer to specific resources" do - coll = stub 'coll', :evaluate => false - coll.expects(:resources).returns(nil) - - @compile.add_collection(coll) - - lambda { @compile.compile }.should_not raise_error - end - - it "should fail when there are unevaluated resource collections that refer to a specific resource" do - coll = stub 'coll', :evaluate => false - coll.expects(:resources).returns(:something) - - @compile.add_collection(coll) - - lambda { @compile.compile }.should raise_error(Puppet::ParseError) - end - - it "should fail when there are unevaluated resource collections that refer to multiple specific resources" do - coll = stub 'coll', :evaluate => false - coll.expects(:resources).returns([:one, :two]) - - @compile.add_collection(coll) - - lambda { @compile.compile }.should raise_error(Puppet::ParseError) - end -end - -describe Puppet::Parser::Compile, "when told to evaluate missing classes" do - include CompileTesting - - it "should fail if there's no source listed for the scope" do - scope = stub 'scope', :source => nil - proc { @compile.evaluate_classes(%w{one two}, scope) }.should raise_error(Puppet::DevError) - end - - it "should tag the catalog with the name of each not-found class" do - @compile.catalog.expects(:tag).with("notfound") - @scope.expects(:findclass).with("notfound").returns(nil) - @compile.evaluate_classes(%w{notfound}, @scope) - end -end - -describe Puppet::Parser::Compile, " when evaluating found classes" do - include CompileTesting - - before do - @class = stub 'class', :classname => "my::class" - @scope.stubs(:findclass).with("myclass").returns(@class) - - @resource = stub 'resource', :ref => "Class[myclass]" - end - - it "should evaluate each class" do - @compile.catalog.stubs(:tag) - - @class.expects(:evaluate).with(@scope) - - @compile.evaluate_classes(%w{myclass}, @scope) - end - - it "should not evaluate the resources created for found classes unless asked" do - @compile.catalog.stubs(:tag) - - @resource.expects(:evaluate).never - - @class.expects(:evaluate).returns(@resource) - - @compile.evaluate_classes(%w{myclass}, @scope) - end - - it "should immediately evaluate the resources created for found classes when asked" do - @compile.catalog.stubs(:tag) - - @resource.expects(:evaluate) - @class.expects(:evaluate).returns(@resource) - - @compile.evaluate_classes(%w{myclass}, @scope, false) - end - - it "should skip classes that have already been evaluated" do - @compile.catalog.stubs(:tag) - - @compile.expects(:class_scope).with(@class).returns("something") - - @compile.expects(:add_resource).never - - @resource.expects(:evaluate).never - - Puppet::Parser::Resource.expects(:new).never - @compile.evaluate_classes(%w{myclass}, @scope, false) - end - - it "should return the list of found classes" do - @compile.catalog.stubs(:tag) - - @compile.stubs(:add_resource) - @scope.stubs(:findclass).with("notfound").returns(nil) - - Puppet::Parser::Resource.stubs(:new).returns(@resource) - @class.stubs :evaluate - @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 - include CompileTesting - - 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 - include CompileTesting - - before do - @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 evaluate the first node class matching the node name" do - node_class = stub 'node', :classname => "c", :evaluate_code => nil - @nodes.stubs(:[]).with("c").returns(node_class) - - node_resource = stub 'node resource', :ref => "Node[c]", :evaluate => nil - node_class.expects(:evaluate).returns(node_resource) - - @compile.compile - end - - it "should match the default node if no matching node can be found" do - node_class = stub 'node', :classname => "default", :evaluate_code => nil - @nodes.stubs(:[]).with("default").returns(node_class) - - node_resource = stub 'node resource', :ref => "Node[default]", :evaluate => nil - node_class.expects(:evaluate).returns(node_resource) - - @compile.compile - 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]" - node_class.expects(:evaluate).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_resource = stub 'node resource', :ref => "Node[c]", :evaluate => nil - node_class = stub 'node', :classname => "c", :evaluate => node_resource - - @nodes.stubs(:[]).with("c").returns(node_class) - - # The #evaluate method normally does this. - scope = stub 'scope', :source => "mysource" - @compile.class_set(node_class.classname, scope) - node_resource.stubs(:evaluate) - - @compile.compile - - @compile.topscope.should equal(scope) - end -end - -describe Puppet::Parser::Compile, "when storing compiled resources" do - include CompileTesting - - it "should store the resources" do - Puppet.features.expects(:rails?).returns(true) - Puppet::Rails.expects(:connect) - - @compile.catalog.expects(:vertices).returns(:resources) - - @compile.expects(:store_to_active_record).with(@node, :resources) - @compile.send(:store) - end - - it "should store to active_record" do - @node.expects(:name).returns("myname") - Puppet::Rails::Host.stubs(:transaction).yields - Puppet::Rails::Host.expects(:store).with(@node, :resources) - @compile.send(:store_to_active_record, @node, :resources) - end -end - -describe Puppet::Parser::Compile, "when managing resource overrides" do - include CompileTesting - - before do - @override = stub 'override', :ref => "My[ref]" - @resource = stub 'resource', :ref => "My[ref]", :builtin? => true - end - - it "should be able to store overrides" do - lambda { @compile.add_override(@override) }.should_not raise_error - end - - it "should apply overrides to the appropriate resources" do - @compile.add_resource(@scope, @resource) - @resource.expects(:merge).with(@override) - - @compile.add_override(@override) - - @compile.compile - end - - it "should accept overrides before the related resource has been created" do - @resource.expects(:merge).with(@override) - - # First store the override - @compile.add_override(@override) - - # Then the resource - @compile.add_resource(@scope, @resource) - - # And compile, so they get resolved - @compile.compile - end - - it "should fail if the compile is finished and resource overrides have not been applied" do - @compile.add_override(@override) - - lambda { @compile.compile }.should raise_error(Puppet::ParseError) - end -end - -# #620 - Nodes and classes should conflict, else classes don't get evaluated -describe Puppet::Parser::Compile, "when evaluating nodes and classes with the same name (#620)" do - include CompileTesting - - before do - @node = stub :nodescope? => true - @class = stub :nodescope? => false - end - - it "should fail if a node already exists with the same name as the class being evaluated" do - @compile.class_set("one", @node) - lambda { @compile.class_set("one", @class) }.should raise_error(Puppet::ParseError) - end - - it "should fail if a class already exists with the same name as the node being evaluated" do - @compile.class_set("one", @class) - lambda { @compile.class_set("one", @node) }.should raise_error(Puppet::ParseError) - end -end diff --git a/spec/unit/parser/compiler.rb b/spec/unit/parser/compiler.rb new file mode 100755 index 000000000..d3039996f --- /dev/null +++ b/spec/unit/parser/compiler.rb @@ -0,0 +1,535 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../spec_helper' + +module CompilerTesting + def setup + @node = Puppet::Node.new "testnode" + @parser = Puppet::Parser::Parser.new :environment => "development" + + @scope_resource = stub 'scope_resource', :builtin? => true + @scope = stub 'scope', :resource => @scope_resource, :source => mock("source") + @compiler = Puppet::Parser::Compiler.new(@node, @parser) + end +end + +describe Puppet::Parser::Compiler do + include CompilerTesting + + it "should be able to store references to class scopes" do + lambda { @compiler.class_set "myname", "myscope" }.should_not raise_error + end + + it "should be able to retrieve class scopes by name" do + @compiler.class_set "myname", "myscope" + @compiler.class_scope("myname").should == "myscope" + end + + it "should be able to retrieve class scopes by object" do + klass = mock 'ast_class' + klass.expects(:classname).returns("myname") + @compiler.class_set "myname", "myscope" + @compiler.class_scope(klass).should == "myscope" + end + + it "should be able to return a class list containing all set classes" do + @compiler.class_set "", "empty" + @compiler.class_set "one", "yep" + @compiler.class_set "two", "nope" + + @compiler.classlist.sort.should == %w{one two}.sort + end +end + +describe Puppet::Parser::Compiler, " when initializing" do + include CompilerTesting + + it "should set its node attribute" do + @compiler.node.should equal(@node) + end + + it "should set its parser attribute" do + @compiler.parser.should equal(@parser) + end + + it "should detect when ast nodes are absent" do + @compiler.ast_nodes?.should be_false + end + + it "should detect when ast nodes are present" do + @parser.nodes["testing"] = "yay" + @compiler.ast_nodes?.should be_true + end +end + +describe Puppet::Parser::Compiler, "when managing scopes" do + include CompilerTesting + + it "should create a top scope" do + @compiler.topscope.should be_instance_of(Puppet::Parser::Scope) + end + + it "should be able to create new scopes" do + @compiler.newscope(@compiler.topscope).should be_instance_of(Puppet::Parser::Scope) + end + + it "should correctly set the level of newly created scopes" do + @compiler.newscope(@compiler.topscope, :level => 5).level.should == 5 + end + + it "should set the parent scope of the new scope to be the passed-in parent" do + scope = mock 'scope' + newscope = @compiler.newscope(scope) + + @compiler.parent(newscope).should equal(scope) + end +end + +describe Puppet::Parser::Compiler, " when compiling" do + include CompilerTesting + + def compile_methods + [:set_node_parameters, :evaluate_main, :evaluate_ast_node, :evaluate_node_classes, :evaluate_generators, :fail_on_unevaluated, + :finish, :store, :extract] + end + + # Stub all of the main compile methods except the ones we're specifically interested in. + def compile_stub(*except) + (compile_methods - except).each { |m| @compiler.stubs(m) } + end + + it "should set node parameters as variables in the top scope" do + params = {"a" => "b", "c" => "d"} + @node.stubs(:parameters).returns(params) + compile_stub(:set_node_parameters) + @compiler.compile + @compiler.topscope.lookupvar("a").should == "b" + @compiler.topscope.lookupvar("c").should == "d" + end + + it "should evaluate any existing classes named in the node" do + classes = %w{one two three four} + main = stub 'main' + one = stub 'one', :classname => "one" + three = stub 'three', :classname => "three" + @node.stubs(:name).returns("whatever") + @node.stubs(:classes).returns(classes) + + @compiler.expects(:evaluate_classes).with(classes, @compiler.topscope) + @compiler.class.publicize_methods(:evaluate_node_classes) { @compiler.evaluate_node_classes } + end + + it "should enable ast_nodes if the parser has any nodes" do + @parser.expects(:nodes).returns(:one => :yay) + @compiler.ast_nodes?.should be_true + end + + it "should disable ast_nodes if the parser has no nodes" do + @parser.expects(:nodes).returns({}) + @compiler.ast_nodes?.should be_false + end + + it "should evaluate the main class if it exists" do + compile_stub(:evaluate_main) + main_class = mock 'main_class' + main_class.expects(:evaluate_code).with { |r| r.is_a?(Puppet::Parser::Resource) } + @compiler.topscope.expects(:source=).with(main_class) + @parser.stubs(:findclass).with("", "").returns(main_class) + + @compiler.compile + end + + it "should evaluate any node classes" do + @node.stubs(:classes).returns(%w{one two three four}) + @compiler.expects(:evaluate_classes).with(%w{one two three four}, @compiler.topscope) + @compiler.send(:evaluate_node_classes) + end + + it "should evaluate all added collections" do + colls = [] + # And when the collections fail to evaluate. + colls << mock("coll1-false") + colls << mock("coll2-false") + colls.each { |c| c.expects(:evaluate).returns(false) } + + @compiler.add_collection(colls[0]) + @compiler.add_collection(colls[1]) + + compile_stub(:evaluate_generators) + @compiler.compile + end + + it "should ignore builtin resources" do + resource = stub 'builtin', :ref => "File[testing]", :builtin? => true + + @compiler.add_resource(@scope, resource) + resource.expects(:evaluate).never + + @compiler.compile + end + + it "should evaluate unevaluated resources" do + resource = stub 'notevaluated', :ref => "File[testing]", :builtin? => false, :evaluated? => false + @compiler.add_resource(@scope, resource) + + # We have to now mark the resource as evaluated + resource.expects(:evaluate).with { |*whatever| resource.stubs(:evaluated?).returns true } + + @compiler.compile + end + + it "should not evaluate already-evaluated resources" do + resource = stub 'already_evaluated', :ref => "File[testing]", :builtin? => false, :evaluated? => true + @compiler.add_resource(@scope, resource) + resource.expects(:evaluate).never + + @compiler.compile + end + + it "should evaluate unevaluated resources created by evaluating other resources" do + resource = stub 'notevaluated', :ref => "File[testing]", :builtin? => false, :evaluated? => false + @compiler.add_resource(@scope, resource) + + resource2 = stub 'created', :ref => "File[other]", :builtin? => false, :evaluated? => false + + # We have to now mark the resource as evaluated + resource.expects(:evaluate).with { |*whatever| resource.stubs(:evaluated?).returns(true); @compiler.add_resource(@scope, resource2) } + resource2.expects(:evaluate).with { |*whatever| resource2.stubs(:evaluated?).returns(true) } + + + @compiler.compile + end + + it "should call finish() on all resources" do + # Add a resource that does respond to :finish + resource = Puppet::Parser::Resource.new :scope => @scope, :type => "file", :title => "finish" + resource.expects(:finish) + + @compiler.add_resource(@scope, resource) + + # And one that does not + dnf = stub "dnf", :ref => "File[dnf]" + + @compiler.add_resource(@scope, dnf) + + @compiler.send(:finish) + end + + it "should add resources that do not conflict with existing resources" do + resource = stub "noconflict", :ref => "File[yay]" + @compiler.add_resource(@scope, resource) + + @compiler.catalog.should be_vertex(resource) + end + + it "should fail to add resources that conflict with existing resources" do + type = stub 'faketype', :isomorphic? => true, :name => "mytype" + Puppet::Type.stubs(:type).with("mytype").returns(type) + + resource1 = stub "iso1conflict", :ref => "Mytype[yay]", :type => "mytype", :file => "eh", :line => 0 + resource2 = stub "iso2conflict", :ref => "Mytype[yay]", :type => "mytype", :file => "eh", :line => 0 + + @compiler.add_resource(@scope, resource1) + lambda { @compiler.add_resource(@scope, resource2) }.should raise_error(ArgumentError) + end + + it "should have a method for looking up resources" do + resource = stub 'resource', :ref => "Yay[foo]" + @compiler.add_resource(@scope, resource) + @compiler.findresource("Yay[foo]").should equal(resource) + end + + it "should be able to look resources up by type and title" do + resource = stub 'resource', :ref => "Yay[foo]" + @compiler.add_resource(@scope, resource) + @compiler.findresource("Yay", "foo").should equal(resource) + end +end + +describe Puppet::Parser::Compiler, " when evaluating collections" do + include CompilerTesting + + it "should evaluate each collection" do + 2.times { |i| + coll = mock 'coll%s' % i + @compiler.add_collection(coll) + + # This is the hard part -- we have to emulate the fact that + # collections delete themselves if they are done evaluating. + coll.expects(:evaluate).with do + @compiler.delete_collection(coll) + end + } + + @compiler.class.publicize_methods(:evaluate_collections) { @compiler.evaluate_collections } + end + + it "should not fail when there are unevaluated resource collections that do not refer to specific resources" do + coll = stub 'coll', :evaluate => false + coll.expects(:resources).returns(nil) + + @compiler.add_collection(coll) + + lambda { @compiler.compile }.should_not raise_error + end + + it "should fail when there are unevaluated resource collections that refer to a specific resource" do + coll = stub 'coll', :evaluate => false + coll.expects(:resources).returns(:something) + + @compiler.add_collection(coll) + + lambda { @compiler.compile }.should raise_error(Puppet::ParseError) + end + + it "should fail when there are unevaluated resource collections that refer to multiple specific resources" do + coll = stub 'coll', :evaluate => false + coll.expects(:resources).returns([:one, :two]) + + @compiler.add_collection(coll) + + lambda { @compiler.compile }.should raise_error(Puppet::ParseError) + end +end + +describe Puppet::Parser::Compiler, "when told to evaluate missing classes" do + include CompilerTesting + + it "should fail if there's no source listed for the scope" do + scope = stub 'scope', :source => nil + proc { @compiler.evaluate_classes(%w{one two}, scope) }.should raise_error(Puppet::DevError) + end + + it "should tag the catalog with the name of each not-found class" do + @compiler.catalog.expects(:tag).with("notfound") + @scope.expects(:findclass).with("notfound").returns(nil) + @compiler.evaluate_classes(%w{notfound}, @scope) + end +end + +describe Puppet::Parser::Compiler, " when evaluating found classes" do + include CompilerTesting + + before do + @class = stub 'class', :classname => "my::class" + @scope.stubs(:findclass).with("myclass").returns(@class) + + @resource = stub 'resource', :ref => "Class[myclass]" + end + + it "should evaluate each class" do + @compiler.catalog.stubs(:tag) + + @class.expects(:evaluate).with(@scope) + + @compiler.evaluate_classes(%w{myclass}, @scope) + end + + it "should not evaluate the resources created for found classes unless asked" do + @compiler.catalog.stubs(:tag) + + @resource.expects(:evaluate).never + + @class.expects(:evaluate).returns(@resource) + + @compiler.evaluate_classes(%w{myclass}, @scope) + end + + it "should immediately evaluate the resources created for found classes when asked" do + @compiler.catalog.stubs(:tag) + + @resource.expects(:evaluate) + @class.expects(:evaluate).returns(@resource) + + @compiler.evaluate_classes(%w{myclass}, @scope, false) + end + + it "should skip classes that have already been evaluated" do + @compiler.catalog.stubs(:tag) + + @compiler.expects(:class_scope).with(@class).returns("something") + + @compiler.expects(:add_resource).never + + @resource.expects(:evaluate).never + + Puppet::Parser::Resource.expects(:new).never + @compiler.evaluate_classes(%w{myclass}, @scope, false) + end + + it "should return the list of found classes" do + @compiler.catalog.stubs(:tag) + + @compiler.stubs(:add_resource) + @scope.stubs(:findclass).with("notfound").returns(nil) + + Puppet::Parser::Resource.stubs(:new).returns(@resource) + @class.stubs :evaluate + @compiler.evaluate_classes(%w{myclass notfound}, @scope).should == %w{myclass} + end +end + +describe Puppet::Parser::Compiler, " when evaluating AST nodes with no AST nodes present" do + include CompilerTesting + + it "should do nothing" do + @compiler.expects(:ast_nodes?).returns(false) + @compiler.parser.expects(:nodes).never + Puppet::Parser::Resource.expects(:new).never + + @compiler.send(:evaluate_ast_node) + end +end + +describe Puppet::Parser::Compiler, " when evaluating AST nodes with AST nodes present" do + include CompilerTesting + + before do + @nodes = mock 'node_hash' + @compiler.stubs(:ast_nodes?).returns(true) + @compiler.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 { @compiler.send(:evaluate_ast_node) }.should raise_error(Puppet::ParseError) + end + + it "should evaluate the first node class matching the node name" do + node_class = stub 'node', :classname => "c", :evaluate_code => nil + @nodes.stubs(:[]).with("c").returns(node_class) + + node_resource = stub 'node resource', :ref => "Node[c]", :evaluate => nil + node_class.expects(:evaluate).returns(node_resource) + + @compiler.compile + end + + it "should match the default node if no matching node can be found" do + node_class = stub 'node', :classname => "default", :evaluate_code => nil + @nodes.stubs(:[]).with("default").returns(node_class) + + node_resource = stub 'node resource', :ref => "Node[default]", :evaluate => nil + node_class.expects(:evaluate).returns(node_resource) + + @compiler.compile + 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]" + node_class.expects(:evaluate).returns(node_resource) + + node_resource.expects(:evaluate) + + @compiler.send(:evaluate_ast_node) + end + + it "should set the node's scope as the top scope" do + node_resource = stub 'node resource', :ref => "Node[c]", :evaluate => nil + node_class = stub 'node', :classname => "c", :evaluate => node_resource + + @nodes.stubs(:[]).with("c").returns(node_class) + + # The #evaluate method normally does this. + scope = stub 'scope', :source => "mysource" + @compiler.class_set(node_class.classname, scope) + node_resource.stubs(:evaluate) + + @compiler.compile + + @compiler.topscope.should equal(scope) + end +end + +describe Puppet::Parser::Compiler, "when storing compiled resources" do + include CompilerTesting + + it "should store the resources" do + Puppet.features.expects(:rails?).returns(true) + Puppet::Rails.expects(:connect) + + @compiler.catalog.expects(:vertices).returns(:resources) + + @compiler.expects(:store_to_active_record).with(@node, :resources) + @compiler.send(:store) + end + + it "should store to active_record" do + @node.expects(:name).returns("myname") + Puppet::Rails::Host.stubs(:transaction).yields + Puppet::Rails::Host.expects(:store).with(@node, :resources) + @compiler.send(:store_to_active_record, @node, :resources) + end +end + +describe Puppet::Parser::Compiler, "when managing resource overrides" do + include CompilerTesting + + before do + @override = stub 'override', :ref => "My[ref]" + @resource = stub 'resource', :ref => "My[ref]", :builtin? => true + end + + it "should be able to store overrides" do + lambda { @compiler.add_override(@override) }.should_not raise_error + end + + it "should apply overrides to the appropriate resources" do + @compiler.add_resource(@scope, @resource) + @resource.expects(:merge).with(@override) + + @compiler.add_override(@override) + + @compiler.compile + end + + it "should accept overrides before the related resource has been created" do + @resource.expects(:merge).with(@override) + + # First store the override + @compiler.add_override(@override) + + # Then the resource + @compiler.add_resource(@scope, @resource) + + # And compile, so they get resolved + @compiler.compile + end + + it "should fail if the compile is finished and resource overrides have not been applied" do + @compiler.add_override(@override) + + lambda { @compiler.compile }.should raise_error(Puppet::ParseError) + end +end + +# #620 - Nodes and classes should conflict, else classes don't get evaluated +describe Puppet::Parser::Compiler, "when evaluating nodes and classes with the same name (#620)" do + include CompilerTesting + + before do + @node = stub :nodescope? => true + @class = stub :nodescope? => false + end + + it "should fail if a node already exists with the same name as the class being evaluated" do + @compiler.class_set("one", @node) + lambda { @compiler.class_set("one", @class) }.should raise_error(Puppet::ParseError) + end + + it "should fail if a class already exists with the same name as the node being evaluated" do + @compiler.class_set("one", @class) + lambda { @compiler.class_set("one", @node) }.should raise_error(Puppet::ParseError) + end +end diff --git a/spec/unit/parser/interpreter.rb b/spec/unit/parser/interpreter.rb index ed30ced93..7885f0542 100755 --- a/spec/unit/parser/interpreter.rb +++ b/spec/unit/parser/interpreter.rb @@ -115,14 +115,14 @@ describe Puppet::Parser::Interpreter, " when compiling catalog" do before do @interp = Puppet::Parser::Interpreter.new @node = stub 'node', :environment => :myenv - @compile = mock 'compile' + @compiler = mock 'compile' @parser = mock 'parser' end it "should create a compile with the node and parser" do - @compile.expects(:compile).returns(:config) + @compiler.expects(:compile).returns(:config) @interp.expects(:parser).with(:myenv).returns(@parser) - Puppet::Parser::Compile.expects(:new).with(@node, @parser).returns(@compile) + Puppet::Parser::Compiler.expects(:new).with(@node, @parser).returns(@compiler) @interp.compile(@node) end diff --git a/spec/unit/parser/resource.rb b/spec/unit/parser/resource.rb index 099cfd05e..a5a49e2a6 100755 --- a/spec/unit/parser/resource.rb +++ b/spec/unit/parser/resource.rb @@ -15,8 +15,8 @@ describe Puppet::Parser::Resource, " when evaluating" do @class = @parser.newclass "myclass" @nodedef = @parser.newnode("mynode")[0] @node = Puppet::Node.new("yaynode") - @compile = Puppet::Parser::Compile.new(@node, @parser) - @scope = @compile.topscope + @compiler = Puppet::Parser::Compiler.new(@node, @parser) + @scope = @compiler.topscope end it "should evaluate the associated AST definition" do @@ -47,8 +47,8 @@ describe Puppet::Parser::Resource, " when finishing" do @class = @parser.newclass "myclass" @nodedef = @parser.newnode("mynode")[0] @node = Puppet::Node.new("yaynode") - @compile = Puppet::Parser::Compile.new(@node, @parser) - @scope = @compile.topscope + @compiler = Puppet::Parser::Compiler.new(@node, @parser) + @scope = @compiler.topscope @resource = Puppet::Parser::Resource.new(:type => "mydefine", :title => "whatever", :scope => @scope, :source => @source) end diff --git a/spec/unit/parser/resource/reference.rb b/spec/unit/parser/resource/reference.rb index e7385f796..147f772d1 100755 --- a/spec/unit/parser/resource/reference.rb +++ b/spec/unit/parser/resource/reference.rb @@ -52,23 +52,23 @@ describe Puppet::Parser::Resource::Reference, " when modeling defined types" do @nodedef = @parser.newnode("mynode")[0] @node = Puppet::Node.new("yaynode") - @compile = Puppet::Parser::Compile.new(@node, @parser) + @compiler = Puppet::Parser::Compiler.new(@node, @parser) end it "should be able to find defined types" do - ref = @type.new(:type => "mydefine", :title => "/tmp/yay", :scope => @compile.topscope) + ref = @type.new(:type => "mydefine", :title => "/tmp/yay", :scope => @compiler.topscope) ref.builtin?.should be_false ref.definedtype.should equal(@definition) end it "should be able to find classes" do - ref = @type.new(:type => "class", :title => "myclass", :scope => @compile.topscope) + ref = @type.new(:type => "class", :title => "myclass", :scope => @compiler.topscope) ref.builtin?.should be_false ref.definedtype.should equal(@class) end it "should be able to find nodes" do - ref = @type.new(:type => "node", :title => "mynode", :scope => @compile.topscope) + ref = @type.new(:type => "node", :title => "mynode", :scope => @compiler.topscope) ref.builtin?.should be_false ref.definedtype.object_id.should == @nodedef.object_id end -- cgit From c8da318a2a4445e0ce10c76a7fbb64635b291ccd Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Tue, 12 Feb 2008 14:19:19 -0600 Subject: Moving the ast node tests to rspec (which I could have *sworn* I did this weekend). In the process, I fixed a couple of bugs related to differentiating between nodes and classes, and then cleaned up quite a few error messages. --- spec/unit/parser/ast/definition.rb | 148 +++++++++++++++++++++++++++++++++++++ spec/unit/parser/ast/node.rb | 127 +++++++++++++++++++++++++++++++ 2 files changed, 275 insertions(+) create mode 100755 spec/unit/parser/ast/node.rb (limited to 'spec/unit/parser') diff --git a/spec/unit/parser/ast/definition.rb b/spec/unit/parser/ast/definition.rb index ba80894e8..f236e23b7 100755 --- a/spec/unit/parser/ast/definition.rb +++ b/spec/unit/parser/ast/definition.rb @@ -44,4 +44,152 @@ describe Puppet::Parser::AST::Definition, "when evaluating" do # it "should not copy the resource's title as the name if 'name' is one of the resource parameters" # # it "should evaluate the associated code with the new scope" + + def test_initialize + parser = mkparser + + # Create a new definition + klass = parser.newdefine "yayness", + :arguments => [["owner", stringobj("nobody")], %w{mode}], + :code => AST::ASTArray.new( + :children => [resourcedef("file", "/tmp/$name", + "owner" => varref("owner"), "mode" => varref("mode"))] + ) + + # Test validattr? a couple different ways + [:owner, "owner", :schedule, "schedule"].each do |var| + assert(klass.validattr?(var), "%s was not considered valid" % var.inspect) + end + + [:random, "random"].each do |var| + assert(! klass.validattr?(var), "%s was considered valid" % var.inspect) + end + + end + + def test_evaluate + parser = mkparser + config = mkcompiler + config.send(:evaluate_main) + scope = config.topscope + klass = parser.newdefine "yayness", + :arguments => [["owner", stringobj("nobody")], %w{mode}], + :code => AST::ASTArray.new( + :children => [resourcedef("file", "/tmp/$name", + "owner" => varref("owner"), "mode" => varref("mode"))] + ) + + resource = Puppet::Parser::Resource.new( + :title => "first", + :type => "yayness", + :exported => false, + :virtual => false, + :scope => scope, + :source => scope.source + ) + resource.send(:set_parameter, "name", "first") + resource.send(:set_parameter, "mode", "755") + + resource.stubs(:title) + assert_nothing_raised do + klass.evaluate_code(resource) + end + + firstobj = config.findresource("File[/tmp/first]") + assert(firstobj, "Did not create /tmp/first obj") + + assert_equal("File", firstobj.type) + assert_equal("/tmp/first", firstobj.title) + assert_equal("nobody", firstobj[:owner]) + assert_equal("755", firstobj[:mode]) + + # Make sure we can't evaluate it with the same args + assert_raise(Puppet::ParseError) do + klass.evaluate_code(resource) + end + + # Now create another with different args + resource2 = Puppet::Parser::Resource.new( + :title => "second", + :type => "yayness", + :exported => false, + :virtual => false, + :scope => scope, + :source => scope.source + ) + resource2.send(:set_parameter, "name", "second") + resource2.send(:set_parameter, "mode", "755") + resource2.send(:set_parameter, "owner", "daemon") + + assert_nothing_raised do + klass.evaluate_code(resource2) + end + + secondobj = config.findresource("File[/tmp/second]") + assert(secondobj, "Did not create /tmp/second obj") + + assert_equal("File", secondobj.type) + assert_equal("/tmp/second", secondobj.title) + assert_equal("daemon", secondobj[:owner]) + assert_equal("755", secondobj[:mode]) + end + + # #539 - definitions should support both names and titles + def test_names_and_titles + parser = mkparser + scope = mkscope :parser => parser + + [ + {:name => "one", :title => "two"}, + {:title => "mytitle"} + ].each_with_index do |hash, i| + # Create a definition that uses both name and title. Put this + # inside the loop so the subscope expectations work. + klass = parser.newdefine "yayness%s" % i + + resource = Puppet::Parser::Resource.new( + :title => hash[:title], + :type => "yayness%s" % i, + :exported => false, + :virtual => false, + :scope => scope, + :source => scope.source + ) + + subscope = klass.subscope(scope, resource) + + klass.expects(:subscope).returns(subscope) + + if hash[:name] + resource.stubs(:to_hash).returns({:name => hash[:name]}) + end + + assert_nothing_raised("Could not evaluate definition with %s" % hash.inspect) do + klass.evaluate_code(resource) + end + + name = hash[:name] || hash[:title] + title = hash[:title] + + assert_equal(name, subscope.lookupvar("name"), + "Name did not get set correctly") + assert_equal(title, subscope.lookupvar("title"), + "title did not get set correctly") + + [:name, :title].each do |param| + val = resource.send(param) + assert(subscope.tags.include?(val), + "Scope was not tagged with %s '%s'" % [param, val]) + end + end + end + + # 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 + parser = mkparser + klass = parser.newclass("one::two") + + assert_equal("one::two", klass.classname, "Class did not get fully qualified class name") + end end diff --git a/spec/unit/parser/ast/node.rb b/spec/unit/parser/ast/node.rb new file mode 100755 index 000000000..340630194 --- /dev/null +++ b/spec/unit/parser/ast/node.rb @@ -0,0 +1,127 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../../spec_helper' + +module ASTNodeTesting + def setup + @node = Puppet::Node.new "testnode" + @parser = Puppet::Parser::Parser.new :environment => "development" + @scope_resource = stub 'scope_resource', :builtin? => true + @compiler = Puppet::Parser::Compiler.new(@node, @parser) + + @scope = @compiler.topscope + end +end + +describe Puppet::Parser::AST::Node, "when evaluating" do + include ASTNodeTesting + + before do + @top = @parser.newnode("top").shift + @middle = @parser.newnode("middle", :parent => "top").shift + end + + it "should create a resource that references itself" do + @top.evaluate(@scope) + + @compiler.catalog.resource(:node, "top").should be_an_instance_of(Puppet::Parser::Resource) + end + + it "should evaluate the parent class if one exists" do + @middle.evaluate(@scope) + + @compiler.catalog.resource(:node, "top").should be_an_instance_of(Puppet::Parser::Resource) + end + + it "should fail to evaluate if a parent class is defined but cannot be found" do + othertop = @parser.newnode("something", :parent => "yay").shift + lambda { othertop.evaluate(@scope) }.should raise_error(Puppet::ParseError) + end + + it "should not create a new resource if one already exists" do + @compiler.catalog.expects(:resource).with(:node, "top").returns("something") + @compiler.catalog.expects(:add_resource).never + @top.evaluate(@scope) + end + + it "should not create a new parent resource if one already exists and it has a parent class" do + @top.evaluate(@scope) + + top_resource = @compiler.catalog.resource(:node, "top") + + @middle.evaluate(@scope) + + @compiler.catalog.resource(:node, "top").should equal(top_resource) + end + + # #795 - tag before evaluation. + it "should tag the catalog with the resource tags when it is evaluated" do + @middle.evaluate(@scope) + + @compiler.catalog.should be_tagged("middle") + end + + it "should tag the catalog with the parent class tags when it is evaluated" do + @middle.evaluate(@scope) + + @compiler.catalog.should be_tagged("top") + end +end + +describe Puppet::Parser::AST::Node, "when evaluating code" do + include ASTNodeTesting + + before do + @top_resource = stub "top_resource" + @top = @parser.newnode("top", :code => @top_resource).shift + + @middle_resource = stub "middle_resource" + @middle = @parser.newnode("middle", :parent => "top", :code => @middle_resource).shift + end + + it "should evaluate the code referred to by the class" do + @top_resource.expects(:safeevaluate) + + resource = @top.evaluate(@scope) + + @top.evaluate_code(resource) + end + + it "should evaluate the parent class's code if it has a parent" do + @top_resource.expects(:safeevaluate) + @middle_resource.expects(:safeevaluate) + + resource = @middle.evaluate(@scope) + + @middle.evaluate_code(resource) + end + + it "should not evaluate the parent class's code if the parent has already been evaluated" do + @top_resource.stubs(:safeevaluate) + resource = @top.evaluate(@scope) + @top.evaluate_code(resource) + + @top_resource.expects(:safeevaluate).never + @middle_resource.stubs(:safeevaluate) + resource = @middle.evaluate(@scope) + @middle.evaluate_code(resource) + end + + it "should use the parent class's scope as its parent scope" do + @top_resource.stubs(:safeevaluate) + @middle_resource.stubs(:safeevaluate) + resource = @middle.evaluate(@scope) + @middle.evaluate_code(resource) + + @compiler.class_scope(@middle).parent.should equal(@compiler.class_scope(@top)) + end + + it "should add the parent class's namespace to its namespace search path" do + @top_resource.stubs(:safeevaluate) + @middle_resource.stubs(:safeevaluate) + resource = @middle.evaluate(@scope) + @middle.evaluate_code(resource) + + @compiler.class_scope(@middle).namespaces.should be_include(@top.namespace) + end +end -- cgit From 7e45553448f2a051594ee4f2fc83ebcfa4a8114a Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Tue, 12 Feb 2008 14:57:24 -0600 Subject: Fixed #997 -- virtual defined types are no longer evaluated. NOTE: This introduces a behaviour change, in that you previously could realize a resource within a virtual defined resource, and now you must realize the entire defined resource, rather than just the contained resource. --- spec/unit/parser/compiler.rb | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'spec/unit/parser') diff --git a/spec/unit/parser/compiler.rb b/spec/unit/parser/compiler.rb index d3039996f..6b821977d 100755 --- a/spec/unit/parser/compiler.rb +++ b/spec/unit/parser/compiler.rb @@ -169,7 +169,7 @@ describe Puppet::Parser::Compiler, " when compiling" do end it "should evaluate unevaluated resources" do - resource = stub 'notevaluated', :ref => "File[testing]", :builtin? => false, :evaluated? => false + resource = stub 'notevaluated', :ref => "File[testing]", :builtin? => false, :evaluated? => false, :virtual? => false @compiler.add_resource(@scope, resource) # We have to now mark the resource as evaluated @@ -179,7 +179,7 @@ describe Puppet::Parser::Compiler, " when compiling" do end it "should not evaluate already-evaluated resources" do - resource = stub 'already_evaluated', :ref => "File[testing]", :builtin? => false, :evaluated? => true + resource = stub 'already_evaluated', :ref => "File[testing]", :builtin? => false, :evaluated? => true, :virtual? => false @compiler.add_resource(@scope, resource) resource.expects(:evaluate).never @@ -187,10 +187,10 @@ describe Puppet::Parser::Compiler, " when compiling" do end it "should evaluate unevaluated resources created by evaluating other resources" do - resource = stub 'notevaluated', :ref => "File[testing]", :builtin? => false, :evaluated? => false + resource = stub 'notevaluated', :ref => "File[testing]", :builtin? => false, :evaluated? => false, :virtual? => false @compiler.add_resource(@scope, resource) - resource2 = stub 'created', :ref => "File[other]", :builtin? => false, :evaluated? => false + resource2 = stub 'created', :ref => "File[other]", :builtin? => false, :evaluated? => false, :virtual? => false # We have to now mark the resource as evaluated resource.expects(:evaluate).with { |*whatever| resource.stubs(:evaluated?).returns(true); @compiler.add_resource(@scope, resource2) } @@ -244,6 +244,15 @@ describe Puppet::Parser::Compiler, " when compiling" do @compiler.add_resource(@scope, resource) @compiler.findresource("Yay", "foo").should equal(resource) end + + it "should not evaluate virtual defined resources" do + resource = stub 'notevaluated', :ref => "File[testing]", :builtin? => false, :evaluated? => false, :virtual? => true + @compiler.add_resource(@scope, resource) + + resource.expects(:evaluate).never + + @compiler.compile + end end describe Puppet::Parser::Compiler, " when evaluating collections" do -- cgit