diff options
Diffstat (limited to 'spec/unit')
-rwxr-xr-x | spec/unit/node/catalog.rb | 60 | ||||
-rwxr-xr-x | spec/unit/other/pgraph.rb | 34 | ||||
-rwxr-xr-x | spec/unit/parser/ast/definition.rb | 158 | ||||
-rwxr-xr-x | spec/unit/parser/ast/hostclass.rb | 131 | ||||
-rwxr-xr-x | spec/unit/parser/ast/node.rb | 127 | ||||
-rwxr-xr-x | spec/unit/parser/collector.rb | 60 | ||||
-rwxr-xr-x | spec/unit/parser/compile.rb | 281 | ||||
-rwxr-xr-x | spec/unit/parser/compiler.rb | 544 | ||||
-rwxr-xr-x | spec/unit/parser/interpreter.rb | 6 | ||||
-rwxr-xr-x | spec/unit/parser/resource.rb | 14 | ||||
-rwxr-xr-x | spec/unit/parser/resource/reference.rb | 8 | ||||
-rwxr-xr-x | spec/unit/ral/type.rb | 4 | ||||
-rwxr-xr-x | spec/unit/simple_graph.rb | 64 | ||||
-rwxr-xr-x | spec/unit/util/constant_inflector.rb | 70 | ||||
-rwxr-xr-x | spec/unit/util/tagging.rb | 9 |
15 files changed, 1162 insertions, 408 deletions
diff --git a/spec/unit/node/catalog.rb b/spec/unit/node/catalog.rb index 3833890f7..aa49909e2 100755 --- a/spec/unit/node/catalog.rb +++ b/spec/unit/node/catalog.rb @@ -57,11 +57,11 @@ describe Puppet::Node::Catalog, " when extracting transobjects" do def mkscope @parser = Puppet::Parser::Parser.new :Code => "" @node = Puppet::Node.new("mynode") - @compile = Puppet::Parser::Compile.new(@node, @parser) + @compiler = Puppet::Parser::Compiler.new(@node, @parser) # XXX This is ridiculous. - @compile.send(:evaluate_main) - @scope = @compile.topscope + @compiler.send(:evaluate_main) + @scope = @compiler.topscope end def mkresource(type, name) @@ -75,7 +75,7 @@ describe Puppet::Node::Catalog, " when extracting transobjects" do @source = mock 'source' main = mkresource("class", :main) - config.add_vertex!(main) + config.add_vertex(main) bucket = mock 'bucket' bucket.expects(:classes=).with(config.classes) @@ -95,7 +95,7 @@ describe Puppet::Node::Catalog, " when extracting transobjects" do defined = mkresource("class", :main) builtin = mkresource("file", "/yay") - config.add_edge!(defined, builtin) + config.add_edge(defined, builtin) bucket = [] bucket.expects(:classes=).with(config.classes) @@ -121,21 +121,21 @@ describe Puppet::Node::Catalog, " when extracting transobjects" do top.expects(:to_trans).returns(topbucket) topres = mkresource "file", "/top" topres.expects(:to_trans).returns(:topres) - config.add_edge! top, topres + config.add_edge top, topres middle = mkresource "class", "middle" middle.expects(:to_trans).returns([]) - config.add_edge! top, middle + config.add_edge top, middle midres = mkresource "file", "/mid" midres.expects(:to_trans).returns(:midres) - config.add_edge! middle, midres + config.add_edge middle, midres bottom = mkresource "class", "bottom" bottom.expects(:to_trans).returns([]) - config.add_edge! middle, bottom + config.add_edge middle, bottom botres = mkresource "file", "/bot" botres.expects(:to_trans).returns(:botres) - config.add_edge! bottom, botres + config.add_edge bottom, botres toparray = config.extract_to_transportable @@ -196,13 +196,13 @@ describe Puppet::Node::Catalog, " when converting to a transobject catalog" do @resources = [@top, @topobject, @middle, @middleobject, @bottom, @bottomobject] - @original.add_edge!(@top, @topobject) - @original.add_edge!(@top, @virtual) - @original.add_edge!(@virtual, @virtualobject) - @original.add_edge!(@top, @middle) - @original.add_edge!(@middle, @middleobject) - @original.add_edge!(@middle, @bottom) - @original.add_edge!(@bottom, @bottomobject) + @original.add_edge(@top, @topobject) + @original.add_edge(@top, @virtual) + @original.add_edge(@virtual, @virtualobject) + @original.add_edge(@top, @middle) + @original.add_edge(@middle, @middleobject) + @original.add_edge(@middle, @bottom) + @original.add_edge(@bottom, @bottomobject) @catalog = @original.to_transportable end @@ -261,11 +261,11 @@ describe Puppet::Node::Catalog, " when converting to a RAL catalog" do @original.add_resource(*@resources) - @original.add_edge!(@top, @topobject) - @original.add_edge!(@top, @middle) - @original.add_edge!(@middle, @middleobject) - @original.add_edge!(@middle, @bottom) - @original.add_edge!(@bottom, @bottomobject) + @original.add_edge(@top, @topobject) + @original.add_edge(@top, @middle) + @original.add_edge(@middle, @middleobject) + @original.add_edge(@middle, @bottom) + @original.add_edge(@bottom, @bottomobject) @catalog = @original.to_ral end @@ -300,7 +300,7 @@ describe Puppet::Node::Catalog, " when converting to a RAL catalog" do config.add_resource(changer) config.add_resource(@top) - config.add_edge!(@top, changer) + config.add_edge(@top, changer) resource = stub 'resource', :name => "changer2", :title => "changer2", :ref => "Test[changer2]", :catalog= => nil, :remove => nil @@ -365,6 +365,12 @@ describe Puppet::Node::Catalog, " when functioning as a resource container" do it "should not allow two resources with the same resource reference" do @catalog.add_resource(@one) + + # These are used to build the failure + @dupe.stubs(:file) + @dupe.stubs(:line) + @one.stubs(:file) + @one.stubs(:line) proc { @catalog.add_resource(@dupe) }.should raise_error(ArgumentError) end @@ -591,8 +597,8 @@ describe Puppet::Node::Catalog, " when creating a relationship graph" do @file = Puppet::Type.type(:file) @one = @file.create :path => "/one" @two = @file.create :path => "/two" - @catalog.add_edge! @compone, @one - @catalog.add_edge! @comptwo, @two + @catalog.add_edge @compone, @one + @catalog.add_edge @comptwo, @two @three = @file.create :path => "/three" @four = @file.create :path => "/four", :require => ["file", "/three"] @@ -765,7 +771,7 @@ end describe Puppet::Node::Catalog, " when converting to yaml" do before do @catalog = Puppet::Node::Catalog.new("me") - @catalog.add_edge!("one", "two") + @catalog.add_edge("one", "two") end it "should be able to be dumped to yaml" do @@ -776,7 +782,7 @@ end describe Puppet::Node::Catalog, " when converting from yaml" do before do @catalog = Puppet::Node::Catalog.new("me") - @catalog.add_edge!("one", "two") + @catalog.add_edge("one", "two") text = YAML.dump(@catalog) @newcatalog = YAML.load(text) diff --git a/spec/unit/other/pgraph.rb b/spec/unit/other/pgraph.rb index 252a807ec..7d66ae331 100755 --- a/spec/unit/other/pgraph.rb +++ b/spec/unit/other/pgraph.rb @@ -35,8 +35,8 @@ describe Puppet::PGraph do end it "should correctly clear vertices and edges when asked" do - @graph.add_edge!("a", "b") - @graph.add_vertex! "c" + @graph.add_edge("a", "b") + @graph.add_vertex "c" @graph.clear @graph.vertices.should be_empty @graph.edges.should be_empty @@ -52,7 +52,7 @@ describe Puppet::PGraph, " when matching edges" do @edges = {} @edges["a/b"] = Puppet::Relationship.new("a", "b", {:event => :yay, :callback => :refresh}) @edges["a/c"] = Puppet::Relationship.new("a", "c", {:event => :yay, :callback => :refresh}) - @graph.add_edge!(@edges["a/b"]) + @graph.add_edge(@edges["a/b"]) end it "should match edges whose source matches the source of the event" do @@ -64,7 +64,7 @@ describe Puppet::PGraph, " when matching edges" do end it "should match multiple edges" do - @graph.add_edge!(@edges["a/c"]) + @graph.add_edge(@edges["a/c"]) edges = @graph.matching_edges([@event]) edges.should be_include(@edges["a/b"]) edges.should be_include(@edges["a/c"]) @@ -75,9 +75,9 @@ describe Puppet::PGraph, " when determining dependencies" do before do @graph = Puppet::PGraph.new - @graph.add_edge!("a", "b") - @graph.add_edge!("a", "c") - @graph.add_edge!("b", "d") + @graph.add_edge("a", "b") + @graph.add_edge("a", "c") + @graph.add_edge("b", "d") end it "should find all dependents when they are on multiple levels" do @@ -118,19 +118,19 @@ describe Puppet::PGraph, " when splicing the relationship graph" do # We have to add the container to the main graph, else it won't # be spliced in the dependency graph. - @contgraph.add_vertex!(@empty) + @contgraph.add_vertex(@empty) end def dependency_graph @depgraph = Puppet::PGraph.new @contgraph.vertices.each do |v| - @depgraph.add_vertex!(v) + @depgraph.add_vertex(v) end # We have to specify a relationship to our empty container, else it # never makes it into the dep graph in the first place. {@one => @two, "f" => "c", "h" => @middle, "c" => @empty}.each do |source, target| - @depgraph.add_edge!(source, target, :callback => :refresh) + @depgraph.add_edge(source, target, :callback => :refresh) end end @@ -176,13 +176,13 @@ describe Puppet::PGraph, " when splicing the relationship graph" do end it "should not add labels to edges that have none" do - @depgraph.add_edge!(@two, @three) + @depgraph.add_edge(@two, @three) splice @depgraph.edge_label("c", "i").should == {} end it "should copy labels over edges that have none" do - @depgraph.add_edge!("c", @three, {:callback => :refresh}) + @depgraph.add_edge("c", @three, {:callback => :refresh}) splice # And make sure the label got copied. @depgraph.edge_label("c", "i").should == {:callback => :refresh} @@ -190,18 +190,18 @@ describe Puppet::PGraph, " when splicing the relationship graph" do it "should not replace a label with a nil label" do # Lastly, add some new label-less edges and make sure the label stays. - @depgraph.add_edge!(@middle, @three) - @depgraph.add_edge!("c", @three, {:callback => :refresh}) + @depgraph.add_edge(@middle, @three) + @depgraph.add_edge("c", @three, {:callback => :refresh}) splice @depgraph.edge_label("c", "i").should == {:callback => :refresh} end it "should copy labels to all created edges" do - @depgraph.add_edge!(@middle, @three) - @depgraph.add_edge!("c", @three, {:callback => :refresh}) + @depgraph.add_edge(@middle, @three) + @depgraph.add_edge("c", @three, {:callback => :refresh}) splice @three.each do |child| - edge = @depgraph.edge_class.new("c", child) + edge = Puppet::Relationship.new("c", child) @depgraph.should be_edge(edge.source, edge.target) @depgraph.edge_label(edge.source, edge.target).should == {:callback => :refresh} end diff --git a/spec/unit/parser/ast/definition.rb b/spec/unit/parser/ast/definition.rb index a27fb4721..f236e23b7 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 @@ -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_code(@resource) end # it "should copy its namespace to the scope" @@ -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/hostclass.rb b/spec/unit/parser/ast/hostclass.rb new file mode 100755 index 000000000..422861857 --- /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 + @compiler = Puppet::Parser::Compiler.new(@node, @parser) + + @scope = @compiler.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) + + @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) + + @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 + 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 + @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 = @compiler.catalog.resource(:class, "top") + + @middle.evaluate(@scope) + + @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) + + @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::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) + + @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 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 diff --git a/spec/unit/parser/collector.rb b/spec/unit/parser/collector.rb index 9b5eab1f4..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(:store_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(:store_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(:store_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(:store_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(:store_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 092bece0c..000000000 --- a/spec/unit/parser/compile.rb +++ /dev/null @@ -1,281 +0,0 @@ -#!/usr/bin/env ruby - -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" - @compile = Puppet::Parser::Compile.new(@node, @parser) - end - - 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.send :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 -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 - - 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 - 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 - - 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 -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) - - @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) - end - - it "should store each created resource in the compile" 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") - - @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) - @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) - - Puppet::Parser::Resource.stubs(:new).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(:store_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(:store_resource) - @scope.stubs(:findclass).with("notfound").returns(nil) - - Puppet::Parser::Resource.stubs(:new).returns(@resource) - @compile.evaluate_classes(%w{myclass notfound}, @scope).should == %w{myclass} - end -end - -describe Puppet::Parser::Compile, " when evaluating AST nodes with no AST nodes present" do - before do - @node = stub 'node', :name => "foo" - @parser = stub 'parser', :version => "1.0", :nodes => {} - @compile = Puppet::Parser::Compile.new(@node, @parser) - end - - it "should do nothing" do - @compile.expects(:ast_nodes?).returns(false) - @compile.parser.expects(:nodes).never - Puppet::Parser::Resource.expects(:new).never - - @compile.send(:evaluate_ast_node) - end -end - -describe Puppet::Parser::Compile, " when evaluating AST nodes with AST nodes present" do - before do - @node = stub 'node', :name => "foo" - @parser = stub 'parser', :version => "1.0", :nodes => {} - @compile = Puppet::Parser::Compile.new(@node, @parser) - - @nodes = mock 'node_hash' - @compile.stubs(:ast_nodes?).returns(true) - @compile.parser.stubs(:nodes).returns(@nodes) - - # Set some names for our test - @node.stubs(:names).returns(%w{a b c}) - @nodes.stubs(:[]).with("a").returns(nil) - @nodes.stubs(:[]).with("b").returns(nil) - @nodes.stubs(:[]).with("c").returns(nil) - - # It should check this last, of course. - @nodes.stubs(:[]).with("default").returns(nil) - end - - it "should fail if the named node cannot be found" do - proc { @compile.send(:evaluate_ast_node) }.should raise_error(Puppet::ParseError) - end - - it "should create a resource for the first node class matching the node name" do - node_class = stub 'node', :classname => "c" - @nodes.stubs(:[]).with("c").returns(node_class) - - node_resource = stub 'node resource', :ref => "Node[c]", :evaluate => nil - Puppet::Parser::Resource.expects(:new).with { |args| args[:title] == "c" and args[:type] == "node" }.returns(node_resource) - - @compile.send(:evaluate_ast_node) - end - - it "should match the default node if no matching node can be found" do - node_class = stub 'node', :classname => "default" - @nodes.stubs(:[]).with("default").returns(node_class) - - node_resource = stub 'node resource', :ref => "Node[default]", :evaluate => nil - Puppet::Parser::Resource.expects(:new).with { |args| args[:title] == "default" and args[:type] == "node" }.returns(node_resource) - - @compile.send(:evaluate_ast_node) - end - - it "should tag the 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) - - @compile.catalog.expects(:tag).with("c") - @compile.send(:evaluate_ast_node) - end - - it "should evaluate the node resource immediately rather than using lazy evaluation" do - node_class = stub 'node', :classname => "c" - @nodes.stubs(:[]).with("c").returns(node_class) - - node_resource = stub 'node resource', :ref => "Node[c]" - Puppet::Parser::Resource.stubs(:new).returns(node_resource) - - node_resource.expects(:evaluate) - - @compile.send(:evaluate_ast_node) - end - - it "should set the node's scope as the top scope" do - node_class = stub 'node', :classname => "c" - @nodes.stubs(:[]).with("c").returns(node_class) - - node_resource = stub 'node resource', :ref => "Node[c]" - Puppet::Parser::Resource.stubs(:new).returns(node_resource) - - # The #evaluate method normally does this. - @compile.class_set(node_class.classname, :my_node_scope) - node_resource.stubs(:evaluate) - - @compile.send(:evaluate_ast_node) - - @compile.topscope.should == :my_node_scope - end -end diff --git a/spec/unit/parser/compiler.rb b/spec/unit/parser/compiler.rb new file mode 100755 index 000000000..6b821977d --- /dev/null +++ b/spec/unit/parser/compiler.rb @@ -0,0 +1,544 @@ +#!/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, :virtual? => 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, :virtual? => false + @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, :virtual? => false + @compiler.add_resource(@scope, resource) + + 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) } + 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 + + 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 + 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 319d8f7d8..a5a49e2a6 100755 --- a/spec/unit/parser/resource.rb +++ b/spec/unit/parser/resource.rb @@ -15,26 +15,26 @@ 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 res = @type.new(:type => "mydefine", :title => "whatever", :scope => @scope, :source => @source) - @definition.expects(:evaluate).with(:scope => @scope, :resource => 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 => @scope, :resource => 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 => @scope, :resource => res) + @nodedef.expects(:evaluate_code).with(res) res.evaluate end end @@ -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 diff --git a/spec/unit/ral/type.rb b/spec/unit/ral/type.rb index 25f8cbaf1..5980167d6 100755 --- a/spec/unit/ral/type.rb +++ b/spec/unit/ral/type.rb @@ -11,8 +11,8 @@ describe Puppet::Type, " when in a configuration" do @catalog.add_resource @container @catalog.add_resource @one @catalog.add_resource @two - @catalog.add_edge! @container, @one - @catalog.add_edge! @container, @two + @catalog.add_edge @container, @one + @catalog.add_edge @container, @two end it "should have no parent if there is no in edge" do diff --git a/spec/unit/simple_graph.rb b/spec/unit/simple_graph.rb index 061a07458..c8fe14cf3 100755 --- a/spec/unit/simple_graph.rb +++ b/spec/unit/simple_graph.rb @@ -9,8 +9,8 @@ require 'puppet/simple_graph' describe Puppet::SimpleGraph do it "should return the number of its vertices as its length" do @graph = Puppet::SimpleGraph.new - @graph.add_vertex!("one") - @graph.add_vertex!("two") + @graph.add_vertex("one") + @graph.add_vertex("two") @graph.size.should == 2 end @@ -20,13 +20,13 @@ describe Puppet::SimpleGraph do it "should provide a method for reversing the graph" do @graph = Puppet::SimpleGraph.new - @graph.add_edge!(:one, :two) + @graph.add_edge(:one, :two) @graph.reversal.edge?(:two, :one).should be_true end it "should be able to produce a dot graph" do @graph = Puppet::SimpleGraph.new - @graph.add_edge!(:one, :two) + @graph.add_edge(:one, :two) proc { @graph.to_dot_graph }.should_not raise_error end @@ -38,17 +38,17 @@ describe Puppet::SimpleGraph, " when managing vertices" do end it "should provide a method to add a vertex" do - @graph.add_vertex!(:test) + @graph.add_vertex(:test) @graph.vertex?(:test).should be_true end it "should ignore already-present vertices when asked to add a vertex" do - @graph.add_vertex!(:test) - proc { @graph.add_vertex!(:test) }.should_not raise_error + @graph.add_vertex(:test) + proc { @graph.add_vertex(:test) }.should_not raise_error end it "should return true when asked if a vertex is present" do - @graph.add_vertex!(:test) + @graph.add_vertex(:test) @graph.vertex?(:test).should be_true end @@ -57,15 +57,15 @@ describe Puppet::SimpleGraph, " when managing vertices" do end it "should return all set vertices when asked" do - @graph.add_vertex!(:one) - @graph.add_vertex!(:two) + @graph.add_vertex(:one) + @graph.add_vertex(:two) @graph.vertices.length.should == 2 @graph.vertices.should include(:one) @graph.vertices.should include(:two) end it "should remove a given vertex when asked" do - @graph.add_vertex!(:one) + @graph.add_vertex(:one) @graph.remove_vertex!(:one) @graph.vertex?(:one).should be_false end @@ -86,49 +86,49 @@ describe Puppet::SimpleGraph, " when managing edges" do it "should provide a method to add an edge as an instance of the edge class" do edge = Puppet::Relationship.new(:one, :two) - @graph.add_edge!(edge) + @graph.add_edge(edge) @graph.edge?(:one, :two).should be_true end it "should provide a method to add an edge by specifying the two vertices" do - @graph.add_edge!(:one, :two) + @graph.add_edge(:one, :two) @graph.edge?(:one, :two).should be_true end it "should provide a method to add an edge by specifying the two vertices and a label" do - @graph.add_edge!(:one, :two, :stuff => :awesome) + @graph.add_edge(:one, :two, :stuff => :awesome) @graph.edge?(:one, :two).should be_true end it "should provide a method for retrieving an edge label" do edge = Puppet::Relationship.new(:one, :two, :stuff => :awesome) - @graph.add_edge!(edge) + @graph.add_edge(edge) @graph.edge_label(:one, :two).should == {:stuff => :awesome} end it "should provide a method for retrieving an edge" do edge = Puppet::Relationship.new(:one, :two) - @graph.add_edge!(edge) + @graph.add_edge(edge) @graph.edge(:one, :two).should equal(edge) end it "should add the edge source as a vertex if it is not already" do edge = Puppet::Relationship.new(:one, :two) - @graph.add_edge!(edge) + @graph.add_edge(edge) @graph.vertex?(:one).should be_true end it "should add the edge target as a vertex if it is not already" do edge = Puppet::Relationship.new(:one, :two) - @graph.add_edge!(edge) + @graph.add_edge(edge) @graph.vertex?(:two).should be_true end it "should return all edges as edge instances when asked" do one = Puppet::Relationship.new(:one, :two) two = Puppet::Relationship.new(:two, :three) - @graph.add_edge!(one) - @graph.add_edge!(two) + @graph.add_edge(one) + @graph.add_edge(two) edges = @graph.edges edges.length.should == 2 edges.should include(one) @@ -137,7 +137,7 @@ describe Puppet::SimpleGraph, " when managing edges" do it "should remove an edge when asked" do edge = Puppet::Relationship.new(:one, :two) - @graph.add_edge!(edge) + @graph.add_edge(edge) @graph.remove_edge!(edge) @graph.edge?(edge.source, edge.target).should be_false end @@ -145,8 +145,8 @@ describe Puppet::SimpleGraph, " when managing edges" do it "should remove all related edges when a vertex is removed" do one = Puppet::Relationship.new(:one, :two) two = Puppet::Relationship.new(:two, :three) - @graph.add_edge!(one) - @graph.add_edge!(two) + @graph.add_edge(one) + @graph.add_edge(two) @graph.remove_vertex!(:two) @graph.edge?(:one, :two).should be_false @graph.edge?(:two, :three).should be_false @@ -160,9 +160,9 @@ describe Puppet::SimpleGraph, " when finding adjacent vertices" do @one_two = Puppet::Relationship.new(:one, :two) @two_three = Puppet::Relationship.new(:two, :three) @one_three = Puppet::Relationship.new(:one, :three) - @graph.add_edge!(@one_two) - @graph.add_edge!(@one_three) - @graph.add_edge!(@two_three) + @graph.add_edge(@one_two) + @graph.add_edge(@one_three) + @graph.add_edge(@two_three) end it "should return adjacent vertices" do @@ -193,8 +193,8 @@ describe Puppet::SimpleGraph, " when clearing" do @graph = Puppet::SimpleGraph.new one = Puppet::Relationship.new(:one, :two) two = Puppet::Relationship.new(:two, :three) - @graph.add_edge!(one) - @graph.add_edge!(two) + @graph.add_edge(one) + @graph.add_edge(two) @graph.clear end @@ -214,18 +214,18 @@ describe Puppet::SimpleGraph, " when reversing graphs" do end it "should provide a method for reversing the graph" do - @graph.add_edge!(:one, :two) + @graph.add_edge(:one, :two) @graph.reversal.edge?(:two, :one).should be_true end it "should add all vertices to the reversed graph" do - @graph.add_edge!(:one, :two) + @graph.add_edge(:one, :two) @graph.vertex?(:one).should be_true @graph.vertex?(:two).should be_true end it "should retain labels on edges" do - @graph.add_edge!(:one, :two, :stuff => :awesome) + @graph.add_edge(:one, :two, :stuff => :awesome) edge = @graph.reversal.edge(:two, :one) edge.label.should == {:stuff => :awesome} end @@ -238,7 +238,7 @@ describe Puppet::SimpleGraph, " when sorting the graph" do def add_edges(hash) hash.each do |a,b| - @graph.add_edge!(a, b) + @graph.add_edge(a, b) end end diff --git a/spec/unit/util/constant_inflector.rb b/spec/unit/util/constant_inflector.rb new file mode 100755 index 000000000..5112e730f --- /dev/null +++ b/spec/unit/util/constant_inflector.rb @@ -0,0 +1,70 @@ +#!/usr/bin/env ruby +# +# Created by Luke Kanies on 2008-02-12. +# Copyright (c) 2007. All rights reserved. + +require File.dirname(__FILE__) + '/../../spec_helper' + +require 'puppet/util/constant_inflector' + +describe Puppet::Util::ConstantInflector, "when converting file names to constants" do + before do + @inflector = Object.new + @inflector.extend(Puppet::Util::ConstantInflector) + end + + it "should capitalize terms" do + @inflector.file2constant("file").should == "File" + end + + it "should switch all '/' characters to double colons" do + @inflector.file2constant("file/other").should == "File::Other" + end + + it "should remove underscores and capitalize the proceeding letter" do + @inflector.file2constant("file_other").should == "FileOther" + end + + it "should correctly replace as many underscores as exist in the file name" do + @inflector.file2constant("two_under_scores/with_some_more_underscores").should == "TwoUnderScores::WithSomeMoreUnderscores" + end + + it "should collapse multiple underscores" do + @inflector.file2constant("many___scores").should == "ManyScores" + end + + it "should correctly handle file names deeper than two directories" do + @inflector.file2constant("one_two/three_four/five_six").should == "OneTwo::ThreeFour::FiveSix" + end +end + +describe Puppet::Util::ConstantInflector, "when converting constnats to file names" do + before do + @inflector = Object.new + @inflector.extend(Puppet::Util::ConstantInflector) + end + + it "should convert them to a string if necessary" do + @inflector.constant2file(Puppet::Util::ConstantInflector).should be_instance_of(String) + end + + it "should accept string inputs" do + @inflector.constant2file("Puppet::Util::ConstantInflector").should be_instance_of(String) + end + + it "should downcase all terms" do + @inflector.constant2file("Puppet").should == "puppet" + end + + it "should convert '::' to '/'" do + @inflector.constant2file("Puppet::Util::Constant").should == "puppet/util/constant" + end + + it "should convert mid-word capitalization to an underscore" do + @inflector.constant2file("OneTwo::ThreeFour").should == "one_two/three_four" + end + + it "should correctly handle constants with more than two parts" do + @inflector.constant2file("OneTwoThree::FourFiveSixSeven").should == "one_two_three/four_five_six_seven" + end +end diff --git a/spec/unit/util/tagging.rb b/spec/unit/util/tagging.rb index 51b69a63c..91cbb213d 100755 --- a/spec/unit/util/tagging.rb +++ b/spec/unit/util/tagging.rb @@ -76,4 +76,13 @@ describe Puppet::Util::Tagging, "when adding tags" do @tagger.tags.should be_include("two") @tagger.tags.should be_include("three") end + + it "should indicate when the object is tagged with a provided tag" do + @tagger.tag("one") + @tagger.should be_tagged("one") + end + + it "should indicate when the object is not tagged with a provided tag" do + @tagger.should_not be_tagged("one") + end end |