diff options
author | Luke Kanies <luke@madstop.com> | 2008-12-02 16:26:54 -0600 |
---|---|---|
committer | Luke Kanies <luke@madstop.com> | 2008-12-02 16:26:54 -0600 |
commit | 99a9b5a045af6f1c68619792a45603cbe450652d (patch) | |
tree | 579963d464c0529d4e9250f937d495e415f1e867 /spec/unit | |
parent | f73e13e7464edab73443857d628602b89361c220 (diff) | |
parent | 278bfe83015312292360f727d6532a143610db0d (diff) | |
download | puppet-99a9b5a045af6f1c68619792a45603cbe450652d.tar.gz puppet-99a9b5a045af6f1c68619792a45603cbe450652d.tar.xz puppet-99a9b5a045af6f1c68619792a45603cbe450652d.zip |
Merge branch '0.24.x'
Conflicts:
bin/puppetca
lib/puppet/type/group.rb
lib/puppet/type/tidy.rb
lib/puppet/util/settings.rb
Also edited the following files so tests will pass:
lib/puppet/type/component.rb
spec/unit/ssl/certificate_request.rb
spec/unit/type/computer.rb
spec/unit/type/mcx.rb
spec/unit/type/resources.rb
spec/unit/util/settings.rb
spec/unit/util/storage.rb
test/ral/type/zone.rb
Diffstat (limited to 'spec/unit')
53 files changed, 2046 insertions, 215 deletions
diff --git a/spec/unit/module.rb b/spec/unit/module.rb index a6608fc1b..1deaec232 100755 --- a/spec/unit/module.rb +++ b/spec/unit/module.rb @@ -114,6 +114,12 @@ describe Puppet::Module, " when searching for templates" do Puppet::Module.find_template("mytemplate").should == "/my/templates/mytemplate" end + it "should accept relative templatedirs" do + Puppet[:templatedir] = "my/templates" + File.expects(:directory?).with(File.join(Dir.getwd,"my/templates")).returns(true) + Puppet::Module.find_template("mytemplate").should == File.join(Dir.getwd,"my/templates/mytemplate") + end + it "should use the environment templatedir if no module is found and an environment is specified" do Puppet::Module.stubs(:templatepath).with("myenv").returns(["/myenv/templates"]) Puppet::Module.expects(:find).with("mymod", "myenv").returns(nil) diff --git a/spec/unit/network/client/master.rb b/spec/unit/network/client/master.rb index f55ba316c..050088707 100755 --- a/spec/unit/network/client/master.rb +++ b/spec/unit/network/client/master.rb @@ -411,29 +411,29 @@ describe Puppet::Network::Client::Master, " when using the cached catalog" do Puppet.stubs(:[]).with(:splaylimit).returns(42) end - it "should sleep for a random time" do - @client.expects(:rand).with(42).returns(42) - @client.expects(:sleep).with(42) + it "should sleep for a random time plus 1" do + @client.expects(:rand).with(43).returns(43) + @client.expects(:sleep).with(43) @client.send(:splay) end it "should inform that it is splayed" do - @client.stubs(:rand).with(42).returns(42) - @client.stubs(:sleep).with(42) + @client.stubs(:rand).with(43).returns(43) + @client.stubs(:sleep).with(43) Puppet.expects(:info) @client.send(:splay) end it "should set splay = true" do - @client.stubs(:rand).with(42).returns(42) - @client.stubs(:sleep).with(42) + @client.stubs(:rand).returns(43) + @client.stubs(:sleep) @client.send(:splay) @client.send(:splayed?).should == true end it "should do nothing if already splayed" do - @client.stubs(:rand).with(42).returns(42).at_most_once - @client.stubs(:sleep).with(42).at_most_once + @client.stubs(:rand).returns(43).at_most_once + @client.stubs(:sleep).at_most_once @client.send(:splay) @client.send(:splay) end diff --git a/spec/unit/network/xmlrpc/client.rb b/spec/unit/network/xmlrpc/client.rb index a0a2e77fb..a0a2e77fb 100644..100755 --- a/spec/unit/network/xmlrpc/client.rb +++ b/spec/unit/network/xmlrpc/client.rb diff --git a/spec/unit/node/catalog.rb b/spec/unit/node/catalog.rb index e3661d995..97674dfc2 100755 --- a/spec/unit/node/catalog.rb +++ b/spec/unit/node/catalog.rb @@ -152,7 +152,7 @@ describe Puppet::Node::Catalog, " when extracting transobjects" do end describe Puppet::Node::Catalog, " when converting to a transobject catalog" do - class TestResource + class CatalogTestResource attr_accessor :name, :virtual, :builtin def initialize(name, options = {}) @name = name @@ -185,14 +185,14 @@ describe Puppet::Node::Catalog, " when converting to a transobject catalog" do @original.tag(*%w{one two three}) @original.add_class *%w{four five six} - @top = TestResource.new 'top' - @topobject = TestResource.new 'topobject', :builtin => true - @virtual = TestResource.new 'virtual', :virtual => true - @virtualobject = TestResource.new 'virtualobject', :builtin => true, :virtual => true - @middle = TestResource.new 'middle' - @middleobject = TestResource.new 'middleobject', :builtin => true - @bottom = TestResource.new 'bottom' - @bottomobject = TestResource.new 'bottomobject', :builtin => true + @top = CatalogTestResource.new 'top' + @topobject = CatalogTestResource.new 'topobject', :builtin => true + @virtual = CatalogTestResource.new 'virtual', :virtual => true + @virtualobject = CatalogTestResource.new 'virtualobject', :builtin => true, :virtual => true + @middle = CatalogTestResource.new 'middle' + @middleobject = CatalogTestResource.new 'middleobject', :builtin => true + @bottom = CatalogTestResource.new 'bottom' + @bottomobject = CatalogTestResource.new 'bottomobject', :builtin => true @resources = [@top, @topobject, @middle, @middleobject, @bottom, @bottomobject] diff --git a/spec/unit/other/transobject.rb b/spec/unit/other/transobject.rb index 07ffdf8bd..33de72c74 100755 --- a/spec/unit/other/transobject.rb +++ b/spec/unit/other/transobject.rb @@ -77,9 +77,15 @@ describe Puppet::TransObject, " when converting to a RAL component instance" do @resource.to_component.should == :yay end + it "should copy over the catalog" do + @resource.catalog = "mycat" + Puppet::Type::Component.expects(:create).with { |resource| resource.catalog == "mycat" }.returns(:yay) + @resource.to_component + end + # LAK:FIXME This really isn't the design we want going forward, but it's # good enough for now. - it "should not pass resource paramaters that are not metaparams" do + it "should not pass resource parameters that are not metaparams" do Puppet::Type::Component.expects(:create).with { |resource| resource["one"].nil? }.returns(:yay) @resource.to_component.should == :yay end diff --git a/spec/unit/parser/ast.rb b/spec/unit/parser/ast.rb new file mode 100644 index 000000000..513943725 --- /dev/null +++ b/spec/unit/parser/ast.rb @@ -0,0 +1,37 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../spec_helper' + +require 'puppet/parser/ast' + +describe Puppet::Parser::AST do + + it "should have a doc accessor" do + ast = Puppet::Parser::AST.new({}) + ast.should respond_to(:doc) + end + + it "should have a use_docs accessor to indicate it wants documentation" do + ast = Puppet::Parser::AST.new({}) + ast.should respond_to(:use_docs) + end + + [ Puppet::Parser::AST::Collection, Puppet::Parser::AST::Definition, Puppet::Parser::AST::Else, + Puppet::Parser::AST::Function, Puppet::Parser::AST::HostClass, Puppet::Parser::AST::IfStatement, + Puppet::Parser::AST::Node, Puppet::Parser::AST::Resource, Puppet::Parser::AST::ResourceDefaults, + Puppet::Parser::AST::ResourceOverride, Puppet::Parser::AST::VarDef + ].each do |k| + it "#{k}.use_docs should return true" do + ast = k.new({}) + ast.use_docs.should be_true + end + end + + describe "when initializing" do + it "should store the doc argument if passed" do + ast = Puppet::Parser::AST.new(:doc => "documentation") + ast.doc.should == "documentation" + end + end + +end
\ No newline at end of file diff --git a/spec/unit/parser/ast/arithmetic_operator.rb b/spec/unit/parser/ast/arithmetic_operator.rb index 24d6ad47d..ce6d42faf 100755 --- a/spec/unit/parser/ast/arithmetic_operator.rb +++ b/spec/unit/parser/ast/arithmetic_operator.rb @@ -4,7 +4,7 @@ require File.dirname(__FILE__) + '/../../../spec_helper' describe Puppet::Parser::AST::ArithmeticOperator do - AST = Puppet::Parser::AST + ast = Puppet::Parser::AST before :each do @scope = Puppet::Parser::Scope.new() @@ -18,19 +18,19 @@ describe Puppet::Parser::AST::ArithmeticOperator do rval = stub "rval" rval.expects(:safeevaluate).with(@scope).returns(2) - operator = AST::ArithmeticOperator.new :rval => rval, :operator => "+", :lval => lval + operator = ast::ArithmeticOperator.new :rval => rval, :operator => "+", :lval => lval operator.evaluate(@scope) end it "should fail for an unknown operator" do - lambda { operator = AST::ArithmeticOperator.new :lval => @one, :operator => "%", :rval => @two }.should raise_error + lambda { operator = ast::ArithmeticOperator.new :lval => @one, :operator => "%", :rval => @two }.should raise_error end it "should call Puppet::Parser::Scope.number?" do Puppet::Parser::Scope.expects(:number?).with(1).returns(1) Puppet::Parser::Scope.expects(:number?).with(2).returns(2) - AST::ArithmeticOperator.new(:lval => @one, :operator => "+", :rval => @two).evaluate(@scope) + ast::ArithmeticOperator.new(:lval => @one, :operator => "+", :rval => @two).evaluate(@scope) end @@ -38,7 +38,7 @@ describe Puppet::Parser::AST::ArithmeticOperator do it "should call ruby Numeric '#{op}'" do one = stub 'one' two = stub 'two' - operator = AST::ArithmeticOperator.new :lval => @one, :operator => op, :rval => @two + operator = ast::ArithmeticOperator.new :lval => @one, :operator => op, :rval => @two Puppet::Parser::Scope.stubs(:number?).with(1).returns(one) Puppet::Parser::Scope.stubs(:number?).with(2).returns(two) one.expects(:send).with(op,two) @@ -49,24 +49,24 @@ describe Puppet::Parser::AST::ArithmeticOperator do it "should work even with numbers embedded in strings" do two = stub 'two', :safeevaluate => "2" one = stub 'one', :safeevaluate => "1" - operator = AST::ArithmeticOperator.new :lval => two, :operator => "+", :rval => one + operator = ast::ArithmeticOperator.new :lval => two, :operator => "+", :rval => one operator.evaluate(@scope).should == 3 end it "should work even with floats" do two = stub 'two', :safeevaluate => 2.53 one = stub 'one', :safeevaluate => 1.80 - operator = AST::ArithmeticOperator.new :lval => two, :operator => "+", :rval => one + operator = ast::ArithmeticOperator.new :lval => two, :operator => "+", :rval => one operator.evaluate(@scope).should == 4.33 end it "should work for variables too" do @scope.expects(:lookupvar).with("one").returns(1) @scope.expects(:lookupvar).with("two").returns(2) - one = AST::Variable.new( :value => "one" ) - two = AST::Variable.new( :value => "two" ) + one = ast::Variable.new( :value => "one" ) + two = ast::Variable.new( :value => "two" ) - operator = AST::ArithmeticOperator.new :lval => one, :operator => "+", :rval => two + operator = ast::ArithmeticOperator.new :lval => one, :operator => "+", :rval => two operator.evaluate(@scope).should == 3 end diff --git a/spec/unit/parser/ast/boolean_operator.rb b/spec/unit/parser/ast/boolean_operator.rb index 7304e2a10..98e173bf0 100755 --- a/spec/unit/parser/ast/boolean_operator.rb +++ b/spec/unit/parser/ast/boolean_operator.rb @@ -4,12 +4,12 @@ require File.dirname(__FILE__) + '/../../../spec_helper' describe Puppet::Parser::AST::BooleanOperator do - AST = Puppet::Parser::AST + ast = Puppet::Parser::AST before :each do @scope = Puppet::Parser::Scope.new() - @true_ast = AST::Boolean.new( :value => true) - @false_ast = AST::Boolean.new( :value => false) + @true_ast = ast::Boolean.new( :value => true) + @false_ast = ast::Boolean.new( :value => false) end it "should evaluate left operand inconditionally" do @@ -18,7 +18,7 @@ describe Puppet::Parser::AST::BooleanOperator do rval = stub "rval", :safeevaluate => false rval.expects(:safeevaluate).never - operator = AST::BooleanOperator.new :rval => rval, :operator => "or", :lval => lval + operator = ast::BooleanOperator.new :rval => rval, :operator => "or", :lval => lval operator.evaluate(@scope) end @@ -26,7 +26,7 @@ describe Puppet::Parser::AST::BooleanOperator do lval = stub "lval", :safeevaluate => true rval = stub "rval", :safeevaluate => false rval.expects(:safeevaluate).with(@scope).returns(false) - operator = AST::BooleanOperator.new :rval => rval, :operator => "and", :lval => lval + operator = ast::BooleanOperator.new :rval => rval, :operator => "and", :lval => lval operator.evaluate(@scope) end @@ -34,20 +34,20 @@ describe Puppet::Parser::AST::BooleanOperator do lval = stub "lval", :safeevaluate => false rval = stub "rval", :safeevaluate => false rval.expects(:safeevaluate).with(@scope).returns(false) - operator = AST::BooleanOperator.new :rval => rval, :operator => "or", :lval => lval + operator = ast::BooleanOperator.new :rval => rval, :operator => "or", :lval => lval operator.evaluate(@scope) end it "should return true for false OR true" do - AST::BooleanOperator.new(:rval => @true_ast, :operator => "or", :lval => @false_ast).evaluate(@scope).should be_true + ast::BooleanOperator.new(:rval => @true_ast, :operator => "or", :lval => @false_ast).evaluate(@scope).should be_true end it "should return false for true AND false" do - AST::BooleanOperator.new(:rval => @true_ast, :operator => "and", :lval => @false_ast ).evaluate(@scope).should be_false + ast::BooleanOperator.new(:rval => @true_ast, :operator => "and", :lval => @false_ast ).evaluate(@scope).should be_false end it "should return true for true AND true" do - AST::BooleanOperator.new(:rval => @true_ast, :operator => "and", :lval => @true_ast ).evaluate(@scope).should be_true + ast::BooleanOperator.new(:rval => @true_ast, :operator => "and", :lval => @true_ast ).evaluate(@scope).should be_true end end diff --git a/spec/unit/parser/ast/collexpr.rb b/spec/unit/parser/ast/collexpr.rb index e5e6e0d7a..5f0ca941e 100755 --- a/spec/unit/parser/ast/collexpr.rb +++ b/spec/unit/parser/ast/collexpr.rb @@ -4,7 +4,7 @@ require File.dirname(__FILE__) + '/../../../spec_helper' describe Puppet::Parser::AST::CollExpr do - AST = Puppet::Parser::AST + ast = Puppet::Parser::AST before :each do @scope = Puppet::Parser::Scope.new() @@ -19,12 +19,12 @@ describe Puppet::Parser::AST::CollExpr do end it "should evaluate both" do - collexpr = AST::CollExpr.new(:test1 => @test1, :test2 => @test2, :oper=>"==") + collexpr = ast::CollExpr.new(:test1 => @test1, :test2 => @test2, :oper=>"==") collexpr.evaluate(@scope) end it "should produce a textual representation and code of the expression" do - collexpr = AST::CollExpr.new(:test1 => @test1, :test2 => @test2, :oper=>"==") + collexpr = ast::CollExpr.new(:test1 => @test1, :test2 => @test2, :oper=>"==") result = collexpr.evaluate(@scope) result[0].should == "param_values.value = 'test2' and param_names.name = 'test1'" result[1].should be_an_instance_of(Proc) @@ -39,7 +39,7 @@ describe Puppet::Parser::AST::CollExpr do t.expects(:form=) end - collexpr = AST::CollExpr.new(:test1 => @test1, :test2 => @test2, :oper=>"==", :form => true, :type => true) + collexpr = ast::CollExpr.new(:test1 => @test1, :test2 => @test2, :oper=>"==", :form => true, :type => true) result = collexpr.evaluate(@scope) end @@ -50,25 +50,25 @@ describe Puppet::Parser::AST::CollExpr do end it "should evaluate like the original expression for ==" do - collexpr = AST::CollExpr.new(:test1 => @test1, :test2 => @test2, :oper => "==") + collexpr = ast::CollExpr.new(:test1 => @test1, :test2 => @test2, :oper => "==") collexpr.evaluate(@scope)[1].call(@resource).should === (@resource["test1"] == "test2") end it "should evaluate like the original expression for !=" do - collexpr = AST::CollExpr.new(:test1 => @test1, :test2 => @test2, :oper => "!=") + collexpr = ast::CollExpr.new(:test1 => @test1, :test2 => @test2, :oper => "!=") collexpr.evaluate(@scope)[1].call(@resource).should === (@resource["test1"] != "test2") end end it "should warn if this is an exported collection containing parenthesis (unsupported)" do - collexpr = AST::CollExpr.new(:test1 => @test1, :test2 => @test2, :oper=>"==", :parens => true, :form => :exported) + collexpr = ast::CollExpr.new(:test1 => @test1, :test2 => @test2, :oper=>"==", :parens => true, :form => :exported) Puppet.expects(:warning) collexpr.evaluate(@scope) end %w{and or}.each do |op| it "should raise an error if this is an exported collection with #{op} operator (unsupported)" do - collexpr = AST::CollExpr.new(:test1 => @test1, :test2 => @test2, :oper=> op, :form => :exported) + collexpr = ast::CollExpr.new(:test1 => @test1, :test2 => @test2, :oper=> op, :form => :exported) lambda { collexpr.evaluate(@scope) }.should raise_error(Puppet::ParseError) end end @@ -81,12 +81,12 @@ describe Puppet::Parser::AST::CollExpr do resource = mock 'resource' resource.expects(:[]).with("array").at_least(1).returns(["test1","test2","test3"]) - collexpr = AST::CollExpr.new(:test1 => array, :test2 => test1, :oper => "==") + collexpr = ast::CollExpr.new(:test1 => array, :test2 => test1, :oper => "==") collexpr.evaluate(@scope)[1].call(resource).should be_true end it "should raise an error for invalid operator" do - lambda { collexpr = AST::CollExpr.new(:oper=>">") }.should raise_error + lambda { collexpr = ast::CollExpr.new(:oper=>">") }.should raise_error end -end
\ No newline at end of file +end diff --git a/spec/unit/parser/ast/comparison_operator.rb b/spec/unit/parser/ast/comparison_operator.rb index dbea349f2..80e8307fa 100755 --- a/spec/unit/parser/ast/comparison_operator.rb +++ b/spec/unit/parser/ast/comparison_operator.rb @@ -5,8 +5,8 @@ require File.dirname(__FILE__) + '/../../../spec_helper' describe Puppet::Parser::AST::ComparisonOperator do before :each do @scope = Puppet::Parser::Scope.new() - @one = Puppet::Parser::AST::FlatString.new( :value => 1 ) - @two = Puppet::Parser::AST::FlatString.new( :value => 2 ) + @one = stub 'one', :safeevaluate => "1" + @two = stub 'two', :safeevaluate => "2" end it "should evaluate both branches" do @@ -19,34 +19,74 @@ describe Puppet::Parser::AST::ComparisonOperator do operator.evaluate(@scope) end + it "should convert arguments strings to numbers if they are" do + Puppet::Parser::Scope.expects(:number?).with("1").returns(1) + Puppet::Parser::Scope.expects(:number?).with("2").returns(2) + + operator = Puppet::Parser::AST::ComparisonOperator.new :lval => @one, :operator => "==", :rval => @two + operator.evaluate(@scope) + end + + %w{< > <= >= ==}.each do |oper| + it "should use string comparison #{oper} if operands are strings" do + lval = stub 'one', :safeevaluate => "one" + rval = stub 'two', :safeevaluate => "two" + Puppet::Parser::Scope.stubs(:number?).with("one").returns(nil) + Puppet::Parser::Scope.stubs(:number?).with("two").returns(nil) + + operator = Puppet::Parser::AST::ComparisonOperator.new :lval => lval, :operator => oper, :rval => rval + operator.evaluate(@scope).should == "one".send(oper,"two") + end + end + + it "should fail with arguments of different types" do + lval = stub 'one', :safeevaluate => "one" + rval = stub 'two', :safeevaluate => "2" + Puppet::Parser::Scope.stubs(:number?).with("one").returns(nil) + Puppet::Parser::Scope.stubs(:number?).with("2").returns(2) + + operator = Puppet::Parser::AST::ComparisonOperator.new :lval => lval, :operator => ">", :rval => rval + lambda { operator.evaluate(@scope) }.should raise_error(ArgumentError) + end + it "should fail for an unknown operator" do lambda { operator = Puppet::Parser::AST::ComparisonOperator.new :lval => @one, :operator => "or", :rval => @two }.should raise_error end %w{< > <= >= ==}.each do |oper| it "should return the result of using '#{oper}' to compare the left and right sides" do - one = stub 'one', :safeevaluate => "1" - two = stub 'two', :safeevaluate => "2" - operator = Puppet::Parser::AST::ComparisonOperator.new :lval => one, :operator => oper, :rval => two + operator = Puppet::Parser::AST::ComparisonOperator.new :lval => @one, :operator => oper, :rval => @two + operator.evaluate(@scope).should == 1.send(oper,2) end end it "should return the result of using '!=' to compare the left and right sides" do - one = stub 'one', :safeevaluate => "1" - two = stub 'two', :safeevaluate => "2" - operator = Puppet::Parser::AST::ComparisonOperator.new :lval => one, :operator => '!=', :rval => two + operator = Puppet::Parser::AST::ComparisonOperator.new :lval => @one, :operator => '!=', :rval => @two + operator.evaluate(@scope).should == true end it "should work for variables too" do - @scope.expects(:lookupvar).with("one").returns(1) - @scope.expects(:lookupvar).with("two").returns(2) one = Puppet::Parser::AST::Variable.new( :value => "one" ) two = Puppet::Parser::AST::Variable.new( :value => "two" ) + + @scope.expects(:lookupvar).with("one").returns(1) + @scope.expects(:lookupvar).with("two").returns(2) operator = Puppet::Parser::AST::ComparisonOperator.new :lval => one, :operator => "<", :rval => two operator.evaluate(@scope).should == true end + # see ticket #1759 + %w{< > <= >=}.each do |oper| + it "should return the correct result of using '#{oper}' to compare 10 and 9" do + ten = stub 'one', :safeevaluate => "10" + nine = stub 'two', :safeevaluate => "9" + operator = Puppet::Parser::AST::ComparisonOperator.new :lval => ten, :operator => oper, :rval => nine + + operator.evaluate(@scope).should == 10.send(oper,9) + end + end + end diff --git a/spec/unit/parser/ast/function.rb b/spec/unit/parser/ast/function.rb new file mode 100644 index 000000000..15420132f --- /dev/null +++ b/spec/unit/parser/ast/function.rb @@ -0,0 +1,77 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe Puppet::Parser::AST::Function do + before :each do + @scope = mock 'scope' + end + + describe "when initializing" do + it "should not fail if the function doesn't exist" do + Puppet::Parser::Functions.stubs(:function).returns(false) + + lambda{ Puppet::Parser::AST::Function.new :name => "dontexist" }.should_not raise_error(Puppet::ParseError) + + end + end + + describe "when evaluating" do + + it "should fail if the function doesn't exist" do + Puppet::Parser::Functions.stubs(:function).returns(false) + func = Puppet::Parser::AST::Function.new :name => "dontexist" + + lambda{ func.evaluate(@scope) }.should raise_error(Puppet::ParseError) + end + + it "should fail if the function is a statement used as rvalue" do + Puppet::Parser::Functions.stubs(:function).with("exist").returns(true) + Puppet::Parser::Functions.stubs(:rvalue?).with("exist").returns(false) + + func = Puppet::Parser::AST::Function.new :name => "exist", :ftype => :rvalue + + lambda{ func.evaluate(@scope) }.should raise_error(Puppet::ParseError, "Function 'exist' does not return a value") + end + + it "should fail if the function is an rvalue used as statement" do + Puppet::Parser::Functions.stubs(:function).with("exist").returns(true) + Puppet::Parser::Functions.stubs(:rvalue?).with("exist").returns(true) + + func = Puppet::Parser::AST::Function.new :name => "exist", :ftype => :statement + + lambda{ func.evaluate(@scope) }.should raise_error(Puppet::ParseError,"Function 'exist' must be the value of a statement") + end + + it "should evaluate its arguments" do + argument = stub 'arg' + Puppet::Parser::Functions.stubs(:function).with("exist").returns(true) + func = Puppet::Parser::AST::Function.new :name => "exist", :ftype => :statement, :arguments => argument + @scope.stubs(:function_exist) + + argument.expects(:safeevaluate).with(@scope).returns("argument") + + func.evaluate(@scope) + end + + it "should call the underlying ruby function" do + argument = stub 'arg', :safeevaluate => "nothing" + Puppet::Parser::Functions.stubs(:function).with("exist").returns(true) + func = Puppet::Parser::AST::Function.new :name => "exist", :ftype => :statement, :arguments => argument + + @scope.expects(:function_exist).with("nothing") + + func.evaluate(@scope) + end + + it "should return the ruby function return for rvalue functions" do + argument = stub 'arg', :safeevaluate => "nothing" + Puppet::Parser::Functions.stubs(:function).with("exist").returns(true) + func = Puppet::Parser::AST::Function.new :name => "exist", :ftype => :statement, :arguments => argument + @scope.stubs(:function_exist).with("nothing").returns("returning") + + func.evaluate(@scope).should == "returning" + end + + end +end diff --git a/spec/unit/parser/ast/resource_override.rb b/spec/unit/parser/ast/resource_override.rb index 3fbeb323c..c1520bf78 100755 --- a/spec/unit/parser/ast/resource_override.rb +++ b/spec/unit/parser/ast/resource_override.rb @@ -4,12 +4,12 @@ require File.dirname(__FILE__) + '/../../../spec_helper' describe Puppet::Parser::AST::ResourceOverride do - AST = Puppet::Parser::AST + ast = Puppet::Parser::AST before :each do @compiler = stub 'compiler' @scope = Puppet::Parser::Scope.new(:compiler => @compiler) - @params = AST::ASTArray.new({}) + @params = ast::ASTArray.new({}) @compiler.stubs(:add_override) end @@ -17,7 +17,7 @@ describe Puppet::Parser::AST::ResourceOverride do klass = stub 'klass', :title => "title", :type => "type" object = mock 'object' object.expects(:safeevaluate).with(@scope).returns(klass) - AST::ResourceOverride.new(:object => object, :params => @params ).evaluate(@scope) + ast::ResourceOverride.new(:object => object, :params => @params ).evaluate(@scope) end it "should tell the compiler to override the resource with our own" do @@ -25,13 +25,13 @@ describe Puppet::Parser::AST::ResourceOverride do klass = stub 'klass', :title => "title", :type => "one" object = mock 'object', :safeevaluate => klass - AST::ResourceOverride.new(:object => object , :params => @params).evaluate(@scope) + ast::ResourceOverride.new(:object => object , :params => @params).evaluate(@scope) end it "should return the overriden resource directly when called with one item" do klass = stub 'klass', :title => "title", :type => "one" object = mock 'object', :safeevaluate => klass - override = AST::ResourceOverride.new(:object => object , :params => @params).evaluate(@scope) + override = ast::ResourceOverride.new(:object => object , :params => @params).evaluate(@scope) override.should be_an_instance_of(Puppet::Parser::Resource) override.title.should == "title" override.type.should == "One" @@ -43,9 +43,9 @@ describe Puppet::Parser::AST::ResourceOverride do object = mock 'object', :safeevaluate => [klass1,klass2] - override = AST::ResourceOverride.new(:object => object , :params => @params).evaluate(@scope) + override = ast::ResourceOverride.new(:object => object , :params => @params).evaluate(@scope) override.should have(2).elements override.each {|o| o.should be_an_instance_of(Puppet::Parser::Resource) } end -end
\ No newline at end of file +end diff --git a/spec/unit/parser/ast/resource_reference.rb b/spec/unit/parser/ast/resource_reference.rb index e4b7c763b..ce2915a97 100755 --- a/spec/unit/parser/ast/resource_reference.rb +++ b/spec/unit/parser/ast/resource_reference.rb @@ -4,7 +4,7 @@ require File.dirname(__FILE__) + '/../../../spec_helper' describe Puppet::Parser::AST::ResourceReference do - AST = Puppet::Parser::AST + ast = Puppet::Parser::AST before :each do @scope = Puppet::Parser::Scope.new() @@ -12,7 +12,7 @@ describe Puppet::Parser::AST::ResourceReference do def newref(title, type) title = stub 'title', :safeevaluate => title - ref = AST::ResourceReference.new(:type => type, :title => title) + ref = Puppet::Parser::AST::ResourceReference.new(:type => type, :title => title) end it "should evaluate correctly reference to builtin types" do @@ -45,7 +45,7 @@ describe Puppet::Parser::AST::ResourceReference do it "should return an array of reference if given an array of titles" do titles = mock 'titles', :safeevaluate => ["title1","title2"] - ref = AST::ResourceReference.new( :title => titles, :type => "Resource" ) + ref = ast::ResourceReference.new( :title => titles, :type => "Resource" ) ref.stubs(:qualified_type).with(@scope).returns("Resource") ref.evaluate(@scope).should have(2).elements @@ -53,11 +53,11 @@ describe Puppet::Parser::AST::ResourceReference do it "should qualify class of all titles for Class resource references" do titles = mock 'titles', :safeevaluate => ["title1","title2"] - ref = AST::ResourceReference.new( :title => titles, :type => "Class" ) + ref = ast::ResourceReference.new( :title => titles, :type => "Class" ) ref.expects(:qualified_class).with(@scope,"title1").returns("class") ref.expects(:qualified_class).with(@scope,"title2").returns("class") ref.evaluate(@scope) end -end
\ No newline at end of file +end diff --git a/spec/unit/parser/compiler.rb b/spec/unit/parser/compiler.rb index c70fe8e13..bf50d8790 100755 --- a/spec/unit/parser/compiler.rb +++ b/spec/unit/parser/compiler.rb @@ -2,6 +2,34 @@ require File.dirname(__FILE__) + '/../../spec_helper' +class CompilerTestResource + attr_accessor :builtin, :virtual, :evaluated, :type, :title + + def initialize(type, title) + @type = type + @title = title + end + + def ref + "%s[%s]" % [type.to_s.capitalize, title] + end + + def evaluated? + @evaluated + end + + def builtin? + @builtin + end + + def virtual? + @virtual + end + + def evaluate + end +end + describe Puppet::Parser::Compiler do before :each do @node = Puppet::Node.new "testnode" @@ -164,11 +192,12 @@ describe Puppet::Parser::Compiler do end it "should evaluate unevaluated resources" do - resource = stub 'notevaluated', :ref => "File[testing]", :builtin? => false, :evaluated? => false, :virtual? => false + resource = CompilerTestResource.new(:file, "testing") + @compiler.add_resource(@scope, resource) # We have to now mark the resource as evaluated - resource.expects(:evaluate).with { |*whatever| resource.stubs(:evaluated?).returns true } + resource.expects(:evaluate).with { |*whatever| resource.evaluated = true } @compiler.compile end @@ -182,14 +211,14 @@ describe Puppet::Parser::Compiler do end it "should evaluate unevaluated resources created by evaluating other resources" do - resource = stub 'notevaluated', :ref => "File[testing]", :builtin? => false, :evaluated? => false, :virtual? => false + resource = CompilerTestResource.new(:file, "testing") @compiler.add_resource(@scope, resource) - resource2 = stub 'created', :ref => "File[other]", :builtin? => false, :evaluated? => false, :virtual? => false + resource2 = CompilerTestResource.new(:file, "other") # 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) } + resource.expects(:evaluate).with { |*whatever| resource.evaluated = true; @compiler.add_resource(@scope, resource2) } + resource2.expects(:evaluate).with { |*whatever| resource2.evaluated = true } @compiler.compile diff --git a/spec/unit/parser/functions.rb b/spec/unit/parser/functions.rb new file mode 100644 index 000000000..fe449139d --- /dev/null +++ b/spec/unit/parser/functions.rb @@ -0,0 +1,83 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../spec_helper' + +describe Puppet::Parser::Functions do + + before(:each) do + end + + after(:each) do + # Rationale: + # our various tests will almost all register to Pupet::Parser::Functions + # a new function called "name". All tests are required to stub Puppet::Parser::Scope + # so that +no+ new real ruby method are defined. + # After each test, we want to leave the whole Puppet::Parser::Functions environment + # as it was before we were called, hence we call rmfunction (which might not succeed + # if the function hasn't been registered in the test). It is also important in this + # section to stub +remove_method+ here so that we don't pollute the scope. + Puppet::Parser::Scope.stubs(:remove_method) + begin + Puppet::Parser::Functions.rmfunction("name") + rescue + end + end + + describe "when calling newfunction" do + it "should create the function in the scope class" do + Puppet::Parser::Scope.expects(:define_method).with { |name,block| name == "function_name" } + + Puppet::Parser::Functions.newfunction("name", :type => :rvalue) + end + + it "should raise an error if the function already exists" do + Puppet::Parser::Scope.expects(:define_method).with { |name,block| name == "function_name" }.once + Puppet::Parser::Functions.newfunction("name", :type => :rvalue) + + lambda { Puppet::Parser::Functions.newfunction("name", :type => :rvalue) }.should raise_error + end + + it "should raise an error if the function type is not correct" do + Puppet::Parser::Scope.expects(:define_method).with { |name,block| name == "function_name" }.never + + lambda { Puppet::Parser::Functions.newfunction("name", :type => :unknown) }.should raise_error + end + end + + describe "when calling rmfunction" do + it "should remove the function in the scope class" do + Puppet::Parser::Scope.expects(:define_method).with { |name,block| name == "function_name" } + Puppet::Parser::Functions.newfunction("name", :type => :rvalue) + + Puppet::Parser::Scope.expects(:remove_method).with("function_name").once + + Puppet::Parser::Functions.rmfunction("name") + end + + it "should raise an error if the function doesn't exists" do + lambda { Puppet::Parser::Functions.rmfunction("name") }.should raise_error + end + end + + describe "when calling function to test function existance" do + + it "should return false if the function doesn't exist" do + Puppet::Parser::Functions.autoloader.stubs(:load) + + Puppet::Parser::Functions.function("name").should be_false + end + + it "should return it's name if the function exists" do + Puppet::Parser::Scope.expects(:define_method).with { |name,block| name == "function_name" } + Puppet::Parser::Functions.newfunction("name", :type => :rvalue) + + Puppet::Parser::Functions.function("name").should == "function_name" + end + + it "should try to autoload the function if it doesn't exist yet" do + Puppet::Parser::Functions.autoloader.expects(:load) + + Puppet::Parser::Functions.function("name") + end + end +end diff --git a/spec/unit/parser/functions/inline_template.rb b/spec/unit/parser/functions/inline_template.rb new file mode 100644 index 000000000..19e1a3b2a --- /dev/null +++ b/spec/unit/parser/functions/inline_template.rb @@ -0,0 +1,59 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "the inline_template function" do + + before :each do + @scope = Puppet::Parser::Scope.new() + end + + it "should exist" do + Puppet::Parser::Functions.function("inline_template").should == "function_inline_template" + end + + it "should create a TemplateWrapper when called" do + tw = stub_everything 'template_wrapper' + + Puppet::Parser::TemplateWrapper.expects(:new).returns(tw) + + @scope.function_inline_template("test") + end + + it "should pass the template string to TemplateWrapper.result" do + tw = stub_everything 'template_wrapper' + Puppet::Parser::TemplateWrapper.stubs(:new).returns(tw) + + tw.expects(:result).with("test") + + @scope.function_inline_template("test") + end + + it "should return what TemplateWrapper.result returns" do + tw = stub_everything 'template_wrapper' + Puppet::Parser::TemplateWrapper.stubs(:new).returns(tw) + + tw.expects(:result).returns("template contents evaluated") + + @scope.function_inline_template("test").should == "template contents evaluated" + end + + it "should concatenate template wrapper outputs for multiple templates" do + tw1 = stub_everything "template_wrapper1" + tw2 = stub_everything "template_wrapper2" + Puppet::Parser::TemplateWrapper.stubs(:new).returns(tw1,tw2) + tw1.stubs(:result).returns("result1") + tw2.stubs(:result).returns("result2") + + @scope.function_inline_template(["1","2"]).should == "result1result2" + end + + it "should raise an error if the template raises an error" do + tw = stub_everything 'template_wrapper' + Puppet::Parser::TemplateWrapper.stubs(:new).returns(tw) + tw.stubs(:result).raises + + lambda { @scope.function_inline_template("1") }.should raise_error(Puppet::ParseError) + end + +end
\ No newline at end of file diff --git a/spec/unit/parser/functions/template.rb b/spec/unit/parser/functions/template.rb new file mode 100644 index 000000000..8fc64d0c3 --- /dev/null +++ b/spec/unit/parser/functions/template.rb @@ -0,0 +1,62 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "the template function" do + + before :each do + @scope = Puppet::Parser::Scope.new() + end + + it "should exist" do + Puppet::Parser::Functions.function("template").should == "function_template" + end + + it "should create a TemplateWrapper when called" do + tw = stub_everything 'template_wrapper' + + Puppet::Parser::TemplateWrapper.expects(:new).returns(tw) + + @scope.function_template("test") + end + + it "should give the template filename to the TemplateWrapper" do + tw = stub_everything 'template_wrapper' + Puppet::Parser::TemplateWrapper.stubs(:new).returns(tw) + + tw.expects(:file=).with("test") + + @scope.function_template("test") + end + + it "should return what TemplateWrapper.result returns" do + tw = stub_everything 'template_wrapper' + Puppet::Parser::TemplateWrapper.stubs(:new).returns(tw) + tw.stubs(:file=).with("test") + + tw.expects(:result).returns("template contents evaluated") + + @scope.function_template("test").should == "template contents evaluated" + end + + it "should concatenate template wrapper outputs for multiple templates" do + tw1 = stub_everything "template_wrapper1" + tw2 = stub_everything "template_wrapper2" + Puppet::Parser::TemplateWrapper.stubs(:new).returns(tw1,tw2) + tw1.stubs(:file=).with("1") + tw2.stubs(:file=).with("2") + tw1.stubs(:result).returns("result1") + tw2.stubs(:result).returns("result2") + + @scope.function_template(["1","2"]).should == "result1result2" + end + + it "should raise an error if the template raises an error" do + tw = stub_everything 'template_wrapper' + Puppet::Parser::TemplateWrapper.stubs(:new).returns(tw) + tw.stubs(:result).raises + + lambda { @scope.function_template("1") }.should raise_error(Puppet::ParseError) + end + +end
\ No newline at end of file diff --git a/spec/unit/parser/lexer.rb b/spec/unit/parser/lexer.rb index d62d99258..24c34632f 100755 --- a/spec/unit/parser/lexer.rb +++ b/spec/unit/parser/lexer.rb @@ -30,7 +30,7 @@ describe Puppet::Parser::Lexer::Token do @token = Puppet::Parser::Lexer::Token.new(%r{something}, :NAME) end - [:regex, :name, :string, :skip, :incr_line, :skip_text].each do |param| + [:regex, :name, :string, :skip, :incr_line, :skip_text, :accumulate].each do |param| it "should have a #{param.to_s} reader" do @token.should be_respond_to(param) end @@ -208,6 +208,42 @@ describe Puppet::Parser::Lexer::TOKENS do end end +describe Puppet::Parser::Lexer::TOKENS[:CLASSNAME] do + before { @token = Puppet::Parser::Lexer::TOKENS[:CLASSNAME] } + + it "should match against lower-case alpha-numeric terms separated by double colons" do + @token.regex.should =~ "one::two" + end + + it "should match against many lower-case alpha-numeric terms separated by double colons" do + @token.regex.should =~ "one::two::three::four::five" + end + + it "should match against lower-case alpha-numeric terms prefixed by double colons" do + @token.regex.should =~ "::one" + end +end + +describe Puppet::Parser::Lexer::TOKENS[:CLASSREF] do + before { @token = Puppet::Parser::Lexer::TOKENS[:CLASSREF] } + + it "should match against single upper-case alpha-numeric terms" do + @token.regex.should =~ "One" + end + + it "should match against upper-case alpha-numeric terms separated by double colons" do + @token.regex.should =~ "One::Two" + end + + it "should match against many upper-case alpha-numeric terms separated by double colons" do + @token.regex.should =~ "One::Two::Three::Four::Five" + end + + it "should match against upper-case alpha-numeric terms prefixed by double colons" do + @token.regex.should =~ "::One" + end +end + describe Puppet::Parser::Lexer::TOKENS[:NAME] do before { @token = Puppet::Parser::Lexer::TOKENS[:NAME] } @@ -285,6 +321,14 @@ describe Puppet::Parser::Lexer::TOKENS[:COMMENT] do it "should be marked to get skipped" do @token.skip?.should be_true end + + it "should be marked to accumulate" do + @token.accumulate?.should be_true + end + + it "'s block should return the comment without the #" do + @token.convert(@lexer,"# this is a comment")[1].should == "this is a comment" + end end describe Puppet::Parser::Lexer::TOKENS[:MLCOMMENT] do @@ -313,6 +357,16 @@ describe Puppet::Parser::Lexer::TOKENS[:MLCOMMENT] do match[1].should == " first " end + it "should be marked to accumulate" do + @token.accumulate?.should be_true + end + + it "'s block should return the comment without the comment marks" do + @lexer.stubs(:line=).with(0) + + @token.convert(@lexer,"/* this is a comment */")[1].should == "this is a comment" + end + end describe Puppet::Parser::Lexer::TOKENS[:RETURN] do @@ -383,6 +437,43 @@ describe Puppet::Parser::Lexer::TOKENS[:VARIABLE] do end end +describe Puppet::Parser::Lexer, "when lexing comments" do + before { @lexer = Puppet::Parser::Lexer.new } + + it "should accumulate token in munge_token" do + token = stub 'token', :skip => true, :accumulate? => true, :incr_line => nil, :skip_text => false + + token.stubs(:convert).with(@lexer, "# this is a comment").returns([token, " this is a comment"]) + @lexer.munge_token(token, "# this is a comment") + @lexer.munge_token(token, "# this is a comment") + + @lexer.getcomment.should == " this is a comment\n this is a comment\n" + end + + it "should add a new comment stack level on LBRACE" do + @lexer.string = "{" + + @lexer.expects(:commentpush) + + @lexer.fullscan + end + + it "should return the current comments on getcomment" do + @lexer.string = "# comment" + @lexer.fullscan + + @lexer.getcomment.should == "comment\n" + end + + it "should discard the previous comments on blank line" do + @lexer.string = "# 1\n\n# 2" + @lexer.fullscan + + @lexer.getcomment.should == "2\n" + 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 } @@ -538,6 +629,7 @@ describe "Puppet::Parser::Lexer in the old tests" do @lexer.fullscan[0].should == [:CLASSREF, foo] end end + end require 'puppettest/support/utils' diff --git a/spec/unit/parser/parser.rb b/spec/unit/parser/parser.rb index 077f93d98..b764dee97 100755 --- a/spec/unit/parser/parser.rb +++ b/spec/unit/parser/parser.rb @@ -4,11 +4,11 @@ require File.dirname(__FILE__) + '/../../spec_helper' describe Puppet::Parser do - AST = Puppet::Parser::AST + ast = Puppet::Parser::AST before :each do @parser = Puppet::Parser::Parser.new :environment => "development" - @true_ast = AST::Boolean.new :value => true + @true_ast = Puppet::Parser::AST::Boolean.new :value => true end describe "when parsing append operator" do @@ -21,13 +21,13 @@ describe Puppet::Parser do lambda { @parser.parse("$var += ") }.should raise_error end - it "should call AST::VarDef with append=true" do - AST::VarDef.expects(:new).with { |h| h[:append] == true } + it "should call ast::VarDef with append=true" do + ast::VarDef.expects(:new).with { |h| h[:append] == true } @parser.parse("$var += 2") end it "should work with arrays too" do - AST::VarDef.expects(:new).with { |h| h[:append] == true } + ast::VarDef.expects(:new).with { |h| h[:append] == true } @parser.parse("$var += ['test']") end @@ -35,22 +35,21 @@ describe Puppet::Parser do describe Puppet::Parser, "when parsing 'if'" do it "not, it should create the correct ast objects" do - AST::Not.expects(:new).with { |h| h[:value].is_a?(AST::Boolean) } + ast::Not.expects(:new).with { |h| h[:value].is_a?(ast::Boolean) } @parser.parse("if ! true { $var = 1 }") - end it "boolean operation, it should create the correct ast objects" do - AST::BooleanOperator.expects(:new).with { - |h| h[:rval].is_a?(AST::Boolean) and h[:lval].is_a?(AST::Boolean) and h[:operator]=="or" + ast::BooleanOperator.expects(:new).with { + |h| h[:rval].is_a?(ast::Boolean) and h[:lval].is_a?(ast::Boolean) and h[:operator]=="or" } @parser.parse("if true or true { $var = 1 }") end it "comparison operation, it should create the correct ast objects" do - AST::ComparisonOperator.expects(:new).with { - |h| h[:lval].is_a?(AST::Name) and h[:rval].is_a?(AST::Name) and h[:operator]=="<" + ast::ComparisonOperator.expects(:new).with { + |h| h[:lval].is_a?(ast::Name) and h[:rval].is_a?(ast::Name) and h[:operator]=="<" } @parser.parse("if 1 < 2 { $var = 1 }") @@ -60,14 +59,15 @@ describe Puppet::Parser do describe Puppet::Parser, "when parsing if complex expressions" do it "should create a correct ast tree" do - AST::ComparisonOperator.expects(:new).with { - |h| h[:rval].is_a?(AST::Name) and h[:lval].is_a?(AST::Name) and h[:operator]==">" - }.returns("whatever") - AST::ComparisonOperator.expects(:new).with { - |h| h[:rval].is_a?(AST::Name) and h[:lval].is_a?(AST::Name) and h[:operator]=="==" - }.returns("whatever") - AST::BooleanOperator.expects(:new).with { - |h| h[:rval]=="whatever" and h[:lval]=="whatever" and h[:operator]=="and" + aststub = stub_everything 'ast' + ast::ComparisonOperator.expects(:new).with { + |h| h[:rval].is_a?(ast::Name) and h[:lval].is_a?(ast::Name) and h[:operator]==">" + }.returns(aststub) + ast::ComparisonOperator.expects(:new).with { + |h| h[:rval].is_a?(ast::Name) and h[:lval].is_a?(ast::Name) and h[:operator]=="==" + }.returns(aststub) + ast::BooleanOperator.expects(:new).with { + |h| h[:rval]==aststub and h[:lval]==aststub and h[:operator]=="and" } @parser.parse("if (1 > 2) and (1 == 2) { $var = 1 }") end @@ -88,10 +88,10 @@ describe Puppet::Parser do lambda { @parser.parse('exec { test: param => File["a","b"] }') }.should_not raise_error end - it "should create an AST::ResourceReference" do - AST::Resource.stubs(:new) - AST::ResourceReference.expects(:new).with { |arg| - arg[:line]==1 and arg[:type]=="File" and arg[:title].is_a?(AST::ASTArray) + it "should create an ast::ResourceReference" do + ast::Resource.stubs(:new) + ast::ResourceReference.expects(:new).with { |arg| + arg[:line]==1 and arg[:type]=="File" and arg[:title].is_a?(ast::ASTArray) } @parser.parse('exec { test: command => File["a","b"] }') end @@ -107,9 +107,9 @@ describe Puppet::Parser do lambda { @parser.parse('Resource["title1","title2"] { param => value }') }.should_not raise_error end - it "should create an AST::ResourceOverride" do - AST::ResourceOverride.expects(:new).with { |arg| - arg[:line]==1 and arg[:object].is_a?(AST::ResourceReference) and arg[:params].is_a?(AST::ResourceParam) + it "should create an ast::ResourceOverride" do + ast::ResourceOverride.expects(:new).with { |arg| + arg[:line]==1 and arg[:object].is_a?(ast::ResourceReference) and arg[:params].is_a?(ast::ResourceParam) } @parser.parse('Resource["title1","title2"] { param => value }') end @@ -131,12 +131,12 @@ describe Puppet::Parser do end it "should create a nop node for empty branch" do - AST::Nop.expects(:new) + ast::Nop.expects(:new) @parser.parse("if true { }") end it "should create a nop node for empty else branch" do - AST::Nop.expects(:new) + ast::Nop.expects(:new) @parser.parse("if true { notice('test') } else { }") end @@ -177,12 +177,12 @@ describe Puppet::Parser do before :each do @one = stub 'one', :is_a? => true - @one.stubs(:is_a?).with(AST::ASTArray).returns(false) - @one.stubs(:is_a?).with(AST).returns(true) + @one.stubs(:is_a?).with(ast::ASTArray).returns(false) + @one.stubs(:is_a?).with(ast).returns(true) @two = stub 'two' - @two.stubs(:is_a?).with(AST::ASTArray).returns(false) - @two.stubs(:is_a?).with(AST).returns(true) + @two.stubs(:is_a?).with(ast::ASTArray).returns(false) + @two.stubs(:is_a?).with(ast).returns(true) end it "should return the first class" do @@ -199,7 +199,30 @@ describe Puppet::Parser do klass1.code.children.should == [@one,@two] end + end + describe Puppet::Parser, "when parsing comments before statement" do + it "should associate the documentation to the statement AST node" do + ast = @parser.parse(""" + # comment + class test {} + """) + + ast[:classes]["test"].doc.should == "comment\n" + end end + describe Puppet::Parser, "when building ast nodes" do + it "should get lexer comments if ast node declares use_docs" do + lexer = stub 'lexer' + ast = mock 'ast', :nil? => false, :use_docs => true, :doc => "" + @parser.stubs(:lexer).returns(lexer) + + Puppet::Parser::AST::Definition.expects(:new).returns(ast) + lexer.expects(:getcomment).returns("comment") + ast.expects(:doc=).with("comment") + + @parser.ast(Puppet::Parser::AST::Definition) + end + end end diff --git a/spec/unit/parser/resource/reference.rb b/spec/unit/parser/resource/reference.rb index 147f772d1..bb1452692 100755 --- a/spec/unit/parser/resource/reference.rb +++ b/spec/unit/parser/resource/reference.rb @@ -72,4 +72,24 @@ describe Puppet::Parser::Resource::Reference, " when modeling defined types" do ref.builtin?.should be_false ref.definedtype.object_id.should == @nodedef.object_id end + + it "should only look for fully qualified classes" do + top = @parser.newclass "top" + sub = @parser.newclass "other::top" + + scope = @compiler.topscope.class.new(:parent => @compiler.topscope, :namespace => "other", :parser => @parser) + + ref = @type.new(:type => "class", :title => "top", :scope => scope) + ref.definedtype.classname.should equal(top.classname) + end + + it "should only look for fully qualified definitions" do + top = @parser.newdefine "top" + sub = @parser.newdefine "other::top" + + scope = @compiler.topscope.class.new(:parent => @compiler.topscope, :namespace => "other", :parser => @parser) + + ref = @type.new(:type => "top", :title => "foo", :scope => scope) + ref.definedtype.classname.should equal(top.classname) + end end diff --git a/spec/unit/parser/templatewrapper.rb b/spec/unit/parser/templatewrapper.rb index 532776223..fd9efa8af 100755 --- a/spec/unit/parser/templatewrapper.rb +++ b/spec/unit/parser/templatewrapper.rb @@ -10,99 +10,118 @@ describe Puppet::Parser::TemplateWrapper do @file = "fake_template" Puppet::Module.stubs(:find_template).returns("/tmp/fake_template") FileTest.stubs(:exists?).returns("true") - @tw = Puppet::Parser::TemplateWrapper.new(@scope, @file) + File.stubs(:read).with("/tmp/fake_template").returns("template content") + @tw = Puppet::Parser::TemplateWrapper.new(@scope) end - it "should create a new object TemplateWrapper from a scope and a file" do + it "should create a new object TemplateWrapper from a scope" do + tw = Puppet::Parser::TemplateWrapper.new(@scope) + + tw.should be_a_kind_of(Puppet::Parser::TemplateWrapper) + end + + it "should check template file existance and read its content" do Puppet::Module.expects(:find_template).with("fake_template", "foo").returns("/tmp/fake_template") FileTest.expects(:exists?).with("/tmp/fake_template").returns(true) - tw = Puppet::Parser::TemplateWrapper.new(@scope, @file) - tw.should be_a_kind_of(Puppet::Parser::TemplateWrapper) + File.expects(:read).with("/tmp/fake_template").returns("template content") + + @tw.file = @file end - it "should turn into a string like template[name]" do + it "should turn into a string like template[name] for file based template" do + @tw.file = @file @tw.to_s.should eql("template[/tmp/fake_template]") end + it "should turn into a string like template[inline] for string-based template" do + @tw.to_s.should eql("template[inline]") + end + it "should return the processed template contents with a call to result" do template_mock = mock("template", :result => "woot!") File.expects(:read).with("/tmp/fake_template").returns("template contents") ERB.expects(:new).with("template contents", 0, "-").returns(template_mock) + + @tw.file = @file @tw.result.should eql("woot!") end + it "should return the processed template contents with a call to result and a string" do + template_mock = mock("template", :result => "woot!") + ERB.expects(:new).with("template contents", 0, "-").returns(template_mock) + + @tw.result("template contents").should eql("woot!") + end + it "should return the contents of a variable if called via method_missing" do @scope.expects(:lookupvar).with("chicken", false).returns("is good") - tw = Puppet::Parser::TemplateWrapper.new(@scope, @file) + tw = Puppet::Parser::TemplateWrapper.new(@scope) tw.chicken.should eql("is good") end it "should throw an exception if a variable is called via method_missing and it does not exist" do @scope.expects(:lookupvar).with("chicken", false).returns(:undefined) - tw = Puppet::Parser::TemplateWrapper.new(@scope, @file) - lambda { tw.chicken }.should raise_error(Puppet::ParseError) + tw = Puppet::Parser::TemplateWrapper.new(@scope) + lambda { tw.chicken }.should raise_error(Puppet::ParseError) end it "should allow you to check whether a variable is defined with has_variable?" do @scope.expects(:lookupvar).with("chicken", false).returns("is good") - tw = Puppet::Parser::TemplateWrapper.new(@scope, @file) + tw = Puppet::Parser::TemplateWrapper.new(@scope) tw.has_variable?("chicken").should eql(true) end it "should allow you to check whether a variable is not defined with has_variable?" do @scope.expects(:lookupvar).with("chicken", false).returns(:undefined) - tw = Puppet::Parser::TemplateWrapper.new(@scope, @file) + tw = Puppet::Parser::TemplateWrapper.new(@scope) tw.has_variable?("chicken").should eql(false) end it "should allow you to retrieve the defined classes with classes" do catalog = mock 'catalog', :classes => ["class1", "class2"] @scope.expects(:catalog).returns( catalog ) - tw = Puppet::Parser::TemplateWrapper.new(@scope, @file) + tw = Puppet::Parser::TemplateWrapper.new(@scope) tw.classes().should == ["class1", "class2"] end it "should allow you to retrieve all the tags with all_tags" do catalog = mock 'catalog', :tags => ["tag1", "tag2"] @scope.expects(:catalog).returns( catalog ) - tw = Puppet::Parser::TemplateWrapper.new(@scope, @file) + tw = Puppet::Parser::TemplateWrapper.new(@scope) tw.all_tags().should == ["tag1","tag2"] end it "should allow you to retrieve the tags defined in the current scope" do @scope.expects(:tags).returns( ["tag1", "tag2"] ) - tw = Puppet::Parser::TemplateWrapper.new(@scope, @file) + tw = Puppet::Parser::TemplateWrapper.new(@scope) tw.tags().should == ["tag1","tag2"] end it "should set all of the scope's variables as instance variables" do template_mock = mock("template", :result => "woot!") - File.expects(:read).with("/tmp/fake_template").returns("template contents") ERB.expects(:new).with("template contents", 0, "-").returns(template_mock) @scope.expects(:to_hash).returns("one" => "foo") - @tw.result + @tw.result("template contents") @tw.instance_variable_get("@one").should == "foo" end it "should not error out if one of the variables is a symbol" do template_mock = mock("template", :result => "woot!") - File.expects(:read).with("/tmp/fake_template").returns("template contents") ERB.expects(:new).with("template contents", 0, "-").returns(template_mock) @scope.expects(:to_hash).returns(:_timestamp => "1234") - @tw.result + @tw.result("template contents") end %w{! . ; :}.each do |badchar| it "should translate #{badchar} to _ when setting the instance variables" do template_mock = mock("template", :result => "woot!") - File.expects(:read).with("/tmp/fake_template").returns("template contents") ERB.expects(:new).with("template contents", 0, "-").returns(template_mock) @scope.expects(:to_hash).returns("one#{badchar}" => "foo") - @tw.result + @tw.result("template contents") @tw.instance_variable_get("@one_").should == "foo" end diff --git a/spec/unit/property/list.rb b/spec/unit/property/list.rb index 9c832c0cd..2fab868db 100644 --- a/spec/unit/property/list.rb +++ b/spec/unit/property/list.rb @@ -143,5 +143,14 @@ describe list_class do @property.insync?(["bar","foo"]).must == false end end + + describe "when calling dearrayify" do + it "should sort and join the array with 'delimiter'" do + array = mock "array" + array.expects(:sort).returns(array) + array.expects(:join).with(@property.delimiter) + @property.dearrayify(array) + end + end end end diff --git a/spec/unit/property/ordered_list.rb b/spec/unit/property/ordered_list.rb new file mode 100644 index 000000000..51c59a7dd --- /dev/null +++ b/spec/unit/property/ordered_list.rb @@ -0,0 +1,64 @@ +#!/usr/bin/env ruby + +Dir.chdir(File.dirname(__FILE__)) { (s = lambda { |f| File.exist?(f) ? require(f) : Dir.chdir("..") { s.call(f) } }).call("spec/spec_helper.rb") } + +require 'puppet/property/ordered_list' + +ordered_list_class = Puppet::Property::OrderedList + +describe ordered_list_class do + + it "should be a subclass of List" do + ordered_list_class.superclass.must == Puppet::Property::List + end + + describe "as an instance" do + before do + # Wow that's a messy interface to the resource. + ordered_list_class.initvars + @resource = stub 'resource', :[]= => nil, :property => nil + @property = ordered_list_class.new(:resource => @resource) + end + + describe "when adding should to current" do + it "should add the arrays when current is an array" do + @property.add_should_with_current(["should"], ["current"]).should == ["should", "current"] + end + + it "should return 'should' if current is not a array" do + @property.add_should_with_current(["should"], :absent).should == ["should"] + end + + it "should return only the uniq elements leading with the order of 'should'" do + @property.add_should_with_current(["this", "is", "should"], ["is", "this", "current"]).should == ["this", "is", "should", "current"] + end + end + + describe "when calling should" do + it "should return nil if @should is nil" do + @property.should.must == nil + end + + it "should return the values of @should (without sorting) as a string if inclusive" do + @property.should = ["foo", "bar"] + @property.expects(:inclusive?).returns(true) + @property.should.must == "foo,bar" + end + + it "should return the uniq values of @should + retrieve as a string if !inclusive with the @ values leading" do + @property.should = ["foo", "bar"] + @property.expects(:inclusive?).returns(false) + @property.expects(:retrieve).returns(["foo","baz"]) + @property.should.must == "foo,bar,baz" + end + end + + describe "when calling dearrayify" do + it "should join the array with the delimiter" do + array = mock "array" + array.expects(:join).with(@property.delimiter) + @property.dearrayify(array) + end + end + end +end diff --git a/spec/unit/provider/confine.rb b/spec/unit/provider/confine.rb index 867b6e6be..626f79b27 100755 --- a/spec/unit/provider/confine.rb +++ b/spec/unit/provider/confine.rb @@ -34,7 +34,10 @@ describe Puppet::Provider::Confine do end describe "when testing all values" do - before { @confine = Puppet::Provider::Confine.new(%w{a b c}) } + before do + @confine = Puppet::Provider::Confine.new(%w{a b c}) + @confine.label = "foo" + end it "should be invalid if any values fail" do @confine.stubs(:pass?).returns true @@ -51,6 +54,14 @@ describe Puppet::Provider::Confine do @confine.expects(:pass?).once.returns false @confine.valid? end + + it "should log failing confines with the label and message" do + @confine.stubs(:pass?).returns false + @confine.expects(:message).returns "My message" + @confine.expects(:label).returns "Mylabel" + Puppet.expects(:debug).with("Mylabel: My message") + @confine.valid? + end end describe "when testing the result of the values" do diff --git a/spec/unit/provider/confine/exists.rb b/spec/unit/provider/confine/exists.rb index 1ab1d39f7..a3539c4f5 100755 --- a/spec/unit/provider/confine/exists.rb +++ b/spec/unit/provider/confine/exists.rb @@ -7,6 +7,7 @@ require 'puppet/provider/confine/exists' describe Puppet::Provider::Confine::Exists do before do @confine = Puppet::Provider::Confine::Exists.new("/my/file") + @confine.label = "eh" end it "should be named :exists" do diff --git a/spec/unit/provider/confine/false.rb b/spec/unit/provider/confine/false.rb index c6c43e391..6ff5cc133 100755 --- a/spec/unit/provider/confine/false.rb +++ b/spec/unit/provider/confine/false.rb @@ -18,6 +18,7 @@ describe Puppet::Provider::Confine::False do it "should use the 'pass?' method to test validity" do @confine = Puppet::Provider::Confine::False.new("foo") + @confine.label = "eh" @confine.expects(:pass?).with("foo") @confine.valid? end diff --git a/spec/unit/provider/confine/feature.rb b/spec/unit/provider/confine/feature.rb index 1845c9a47..67e59363e 100755 --- a/spec/unit/provider/confine/feature.rb +++ b/spec/unit/provider/confine/feature.rb @@ -22,6 +22,7 @@ describe Puppet::Provider::Confine::Feature do @features = mock 'features' Puppet.stubs(:features).returns @features @confine = Puppet::Provider::Confine::Feature.new("myfeature") + @confine.label = "eh" end it "should use the Puppet features instance to test validity" do diff --git a/spec/unit/provider/confine/true.rb b/spec/unit/provider/confine/true.rb index c9cc83c9e..75b36cea5 100755 --- a/spec/unit/provider/confine/true.rb +++ b/spec/unit/provider/confine/true.rb @@ -14,7 +14,10 @@ describe Puppet::Provider::Confine::True do end describe "when testing values" do - before { @confine = Puppet::Provider::Confine::True.new("foo") } + before do + @confine = Puppet::Provider::Confine::True.new("foo") + @confine.label = "eh" + end it "should use the 'pass?' method to test validity" do @confine.expects(:pass?).with("foo") diff --git a/spec/unit/provider/confine/variable.rb b/spec/unit/provider/confine/variable.rb index 38b3dad1c..7a71fc1ae 100755 --- a/spec/unit/provider/confine/variable.rb +++ b/spec/unit/provider/confine/variable.rb @@ -27,60 +27,55 @@ describe Puppet::Provider::Confine::Variable do @confine.name = :myvar end - it "should use the 'pass?' method to test validity" do - @confine.expects(:pass?).with("foo") - @confine.valid? - end - it "should use settings if the variable name is a valid setting" do Puppet.settings.expects(:valid?).with(:myvar).returns true Puppet.settings.expects(:value).with(:myvar).returns "foo" - @confine.pass?("foo") + @confine.valid? end it "should use Facter if the variable name is not a valid setting" do Puppet.settings.expects(:valid?).with(:myvar).returns false Facter.expects(:value).with(:myvar).returns "foo" - @confine.pass?("foo") + @confine.valid? end - it "should return true if the value matches the facter value" do + it "should be valid if the value matches the facter value" do @confine.expects(:test_value).returns "foo" - @confine.pass?("foo").should be_true + @confine.should be_valid end it "should return false if the value does not match the facter value" do @confine.expects(:test_value).returns "fee" - @confine.pass?("foo").should be_false + @confine.should_not be_valid end it "should be case insensitive" do @confine.expects(:test_value).returns "FOO" - @confine.pass?("foo").should be_true + @confine.should be_valid end it "should not care whether the value is a string or symbol" do @confine.expects(:test_value).returns "FOO" - @confine.pass?(:foo).should be_true - end - - it "should cache the facter value during testing" do - Facter.expects(:value).once.returns("FOO") - - @confine.pass?(:foo) - @confine.pass?(:foo) + @confine.should be_valid end it "should produce a message that the fact value is not correct" do @confine = Puppet::Provider::Confine::Variable.new(%w{bar bee}) + @confine.name = "eh" message = @confine.message("value") message.should be_include("facter") message.should be_include("bar,bee") end + + it "should be valid if the test value matches any of the provided values" do + @confine = Puppet::Provider::Confine::Variable.new(%w{bar bee}) + @confine.expects(:test_value).returns "bee" + @confine.should be_valid + end end describe "when summarizing multiple instances" do diff --git a/spec/unit/provider/confine_collection.rb b/spec/unit/provider/confine_collection.rb index 1598b5f99..444281c77 100755 --- a/spec/unit/provider/confine_collection.rb +++ b/spec/unit/provider/confine_collection.rb @@ -6,69 +6,81 @@ require 'puppet/provider/confine_collection' describe Puppet::Provider::ConfineCollection do it "should be able to add confines" do - Puppet::Provider::ConfineCollection.new.should respond_to(:confine) + Puppet::Provider::ConfineCollection.new("label").should respond_to(:confine) + end + + it "should require a label at initialization" do + lambda { Puppet::Provider::ConfineCollection.new }.should raise_error(ArgumentError) + end + + it "should make its label available" do + Puppet::Provider::ConfineCollection.new("mylabel").label.should == "mylabel" end describe "when creating confine instances" do it "should create an instance of the named test with the provided values" do test_class = mock 'test_class' - test_class.expects(:new).with(%w{my values}) + test_class.expects(:new).with(%w{my values}).returns(stub('confine', :label= => nil)) Puppet::Provider::Confine.expects(:test).with(:foo).returns test_class - Puppet::Provider::ConfineCollection.new.confine :foo => %w{my values} + Puppet::Provider::ConfineCollection.new("label").confine :foo => %w{my values} end - describe "and the test cannot be found" do - before do - @variable = mock 'variable_test' + it "should copy its label to the confine instance" do + confine = mock 'confine' + test_class = mock 'test_class' + test_class.expects(:new).returns confine + Puppet::Provider::Confine.expects(:test).returns test_class - Puppet::Provider::Confine.expects(:test).with(:foo).returns nil - Puppet::Provider::Confine.expects(:test).with(:variable).returns @variable - end + confine.expects(:label=).with("label") + Puppet::Provider::ConfineCollection.new("label").confine :foo => %w{my values} + end + + describe "and the test cannot be found" do it "should create a Facter test with the provided values and set the name to the test name" do - confine = mock 'confine' + confine = Puppet::Provider::Confine.test(:variable).new(%w{my values}) confine.expects(:name=).with(:foo) - @variable.expects(:new).with(%w{my values}).returns confine - Puppet::Provider::ConfineCollection.new.confine :foo => %w{my values} + confine.class.expects(:new).with(%w{my values}).returns confine + Puppet::Provider::ConfineCollection.new("label").confine(:foo => %w{my values}) end end describe "and the 'for_binary' option was provided" do it "should mark the test as a binary confine" do - confine = mock 'confine' + confine = Puppet::Provider::Confine.test(:exists).new(:bar) confine.expects(:for_binary=).with true Puppet::Provider::Confine.test(:exists).expects(:new).with(:bar).returns confine - Puppet::Provider::ConfineCollection.new.confine :exists => :bar, :for_binary => true + Puppet::Provider::ConfineCollection.new("label").confine :exists => :bar, :for_binary => true end end end it "should be valid if no confines are present" do - Puppet::Provider::ConfineCollection.new.should be_valid + Puppet::Provider::ConfineCollection.new("label").should be_valid end it "should be valid if all confines pass" do - c1 = mock 'c1', :valid? => true - c2 = mock 'c2', :valid? => true + c1 = stub 'c1', :valid? => true, :label= => nil + c2 = stub 'c2', :valid? => true, :label= => nil Puppet::Provider::Confine.test(:true).expects(:new).returns(c1) Puppet::Provider::Confine.test(:false).expects(:new).returns(c2) - confiner = Puppet::Provider::ConfineCollection.new + confiner = Puppet::Provider::ConfineCollection.new("label") confiner.confine :true => :bar, :false => :bee confiner.should be_valid end it "should not be valid if any confines fail" do - c1 = stub 'c1', :valid? => true - c2 = stub 'c2', :valid? => false + c1 = stub 'c1', :valid? => true, :label= => nil + c2 = stub 'c2', :valid? => false, :label= => nil Puppet::Provider::Confine.test(:true).expects(:new).returns(c1) Puppet::Provider::Confine.test(:false).expects(:new).returns(c2) - confiner = Puppet::Provider::ConfineCollection.new + confiner = Puppet::Provider::ConfineCollection.new("label") confiner.confine :true => :bar, :false => :bee confiner.should_not be_valid @@ -76,7 +88,7 @@ describe Puppet::Provider::ConfineCollection do describe "when providing a summary" do before do - @confiner = Puppet::Provider::ConfineCollection.new + @confiner = Puppet::Provider::ConfineCollection.new("label") end it "should return a hash" do diff --git a/spec/unit/provider/confiner.rb b/spec/unit/provider/confiner.rb index 078fc4420..0a0d67fb5 100755 --- a/spec/unit/provider/confiner.rb +++ b/spec/unit/provider/confiner.rb @@ -30,7 +30,8 @@ describe Puppet::Provider::Confiner do end it "should create a new confine collection if one does not exist" do - Puppet::Provider::ConfineCollection.expects(:new).returns "mycoll" + Puppet::Provider::ConfineCollection.expects(:new).with("mylabel").returns "mycoll" + @object.expects(:to_s).returns "mylabel" @object.confine_collection.should == "mycoll" end diff --git a/spec/unit/provider/mcx/mcxcontent.rb b/spec/unit/provider/mcx/mcxcontent.rb new file mode 100755 index 000000000..eedff7dad --- /dev/null +++ b/spec/unit/provider/mcx/mcxcontent.rb @@ -0,0 +1,175 @@ +#! /usr/bin/env ruby +#-- +# Copyright (C) 2008 Jeffrey J McCune. + +# This program and entire repository is free software; you can +# redistribute it and/or modify it under the terms of the GNU +# General Public License as published by the Free Software +# Foundation; either version 2 of the License, or any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +# Author: Jeff McCune <mccune.jeff@gmail.com> + +require File.dirname(__FILE__) + '/../../../spec_helper' + +provider_class = Puppet::Type.type(:mcx).provider(:mcxcontent) + +# describe creates a new ExampleGroup object. +describe provider_class do + + # :each executes before each test. + # :all executes once for the test group and before :each. + before :each do + # Create a mock resource + @resource = stub 'resource' + + @provider = provider_class.new + @attached_to = "/Users/foobar" + @ds_path = "/Local/Default/Users/foobar" + + # A catch all; no parameters set + @resource.stubs(:[]).returns(nil) + + # But set name, ensure and enable + @resource.stubs(:[]).with(:name).returns @attached_to + @resource.stubs(:[]).with(:ensure).returns :present + @resource.stubs(:ref).returns "Mcx[#{@attached_to}]" + + # stub out the provider methods that actually touch the filesystem + # or execute commands + @provider.class.stubs(:execute).returns('') + @provider.stubs(:execute).returns('') + @provider.stubs(:resource).returns @resource + end + + it "should have a create method." do + @provider.should respond_to(:create) + end + + it "should have a destroy method." do + @provider.should respond_to(:destroy) + end + + it "should have an exists? method." do + @provider.should respond_to(:exists?) + end + + it "should have an content method." do + @provider.should respond_to(:content) + end + + it "should have an content= method." do + @provider.should respond_to(:content=) + end + + describe "when managing the resource" do + it "should execute external command dscl from :create" do + @provider.class.expects(:dscl).returns('').once + @provider.create + end + it "should execute external command dscl from :destroy" do + @provider.class.expects(:dscl).with('localhost', '-mcxdelete', @ds_path).returns('').once + @provider.destroy + end + it "should execute external command dscl from :exists?" do + @provider.class.expects(:dscl).with('localhost', '-mcxexport', @ds_path).returns('').once + @provider.exists? + end + it "should execute external command dscl from :content" do + @provider.class.expects(:dscl).with('localhost', '-mcxexport', @ds_path).returns('') + @provider.content + end + it "should execute external command dscl from :content=" do + @provider.class.expects(:dscl).returns('') + @provider.content='' + end + end + + describe "when creating and parsing the name for ds_type" do + before :each do + @resource.stubs(:[]).with(:name).returns "/Foo/bar" + end + it "should not accept /Foo/bar" do + lambda { @provider.create }.should raise_error(MCXContentProviderException) + end + it "should accept /Foo/bar with ds_type => user" do + @resource.stubs(:[]).with(:ds_type).returns "user" + lambda { @provider.create }.should_not raise_error(MCXContentProviderException) + end + it "should accept /Foo/bar with ds_type => group" do + @resource.stubs(:[]).with(:ds_type).returns "group" + lambda { @provider.create }.should_not raise_error(MCXContentProviderException) + end + it "should accept /Foo/bar with ds_type => computer" do + @resource.stubs(:[]).with(:ds_type).returns "computer" + lambda { @provider.create }.should_not raise_error(MCXContentProviderException) + end + it "should accept :name => /Foo/bar with ds_type => computerlist" do + @resource.stubs(:[]).with(:ds_type).returns "computerlist" + lambda { @provider.create }.should_not raise_error(MCXContentProviderException) + end + end + + describe "when creating and :name => foobar" do + before :each do + @resource.stubs(:[]).with(:name).returns "foobar" + end + it "should not accept unspecified :ds_type and :ds_name" do + lambda { @provider.create }.should raise_error(MCXContentProviderException) + end + it "should not accept unspecified :ds_type" do + @resource.stubs(:[]).with(:ds_type).returns "user" + lambda { @provider.create }.should raise_error(MCXContentProviderException) + end + it "should not accept unspecified :ds_name" do + @resource.stubs(:[]).with(:ds_name).returns "foo" + lambda { @provider.create }.should raise_error(MCXContentProviderException) + end + it "should accept :ds_type => user, ds_name => foo" do + @resource.stubs(:[]).with(:ds_type).returns "user" + @resource.stubs(:[]).with(:ds_name).returns "foo" + lambda { @provider.create }.should_not raise_error(MCXContentProviderException) + end + it "should accept :ds_type => group, ds_name => foo" do + @resource.stubs(:[]).with(:ds_type).returns "group" + @resource.stubs(:[]).with(:ds_name).returns "foo" + lambda { @provider.create }.should_not raise_error(MCXContentProviderException) + end + it "should accept :ds_type => computer, ds_name => foo" do + @resource.stubs(:[]).with(:ds_type).returns "computer" + @resource.stubs(:[]).with(:ds_name).returns "foo" + lambda { @provider.create }.should_not raise_error(MCXContentProviderException) + end + it "should accept :ds_type => computerlist, ds_name => foo" do + @resource.stubs(:[]).with(:ds_type).returns "computerlist" + @resource.stubs(:[]).with(:ds_name).returns "foo" + lambda { @provider.create }.should_not raise_error(MCXContentProviderException) + end + it "should not accept :ds_type => bogustype, ds_name => foo" do + @resource.stubs(:[]).with(:ds_type).returns "bogustype" + @resource.stubs(:[]).with(:ds_name).returns "foo" + lambda { @provider.create }.should raise_error(MCXContentProviderException) + end + end + + describe "when gathering existing instances" do + it "should define an instances class method." do + @provider.class.should respond_to(:instances) + end + it "should call external command dscl -list /Local/Default/<ds_type> on each known ds_type" do + @provider.class.expects(:dscl).with('localhost', '-list', "/Local/Default/Users").returns('') + @provider.class.expects(:dscl).with('localhost', '-list', "/Local/Default/Groups").returns('') + @provider.class.expects(:dscl).with('localhost', '-list', "/Local/Default/Computers").returns('') + @provider.class.expects(:dscl).with('localhost', '-list', "/Local/Default/ComputerLists").returns('') + @provider.class.instances + end + end +end diff --git a/spec/unit/provider/mount/parsed.rb b/spec/unit/provider/mount/parsed.rb index 8d043f97f..9585afa62 100755 --- a/spec/unit/provider/mount/parsed.rb +++ b/spec/unit/provider/mount/parsed.rb @@ -130,11 +130,11 @@ describe provider_class do describe provider_class, " when modifying the filesystem tab" do include ParsedMountTesting before do - @mount = mkmount - @target = @provider_class.default_target - # Never write to disk, only to RAM. @provider_class.stubs(:filetype).returns(Puppet::Util::FileType.filetype(:ram)) + + @mount = mkmount + @target = @provider_class.default_target end it "should write the mount to disk when :flush is called" do diff --git a/spec/unit/provider/service/launchd.rb b/spec/unit/provider/service/launchd.rb new file mode 100755 index 000000000..9650ea423 --- /dev/null +++ b/spec/unit/provider/service/launchd.rb @@ -0,0 +1,134 @@ +#!/usr/bin/env ruby +# +# Unit testing for the launchd service provider +# + +require File.dirname(__FILE__) + '/../../../spec_helper' + +require 'puppet' + +provider_class = Puppet::Type.type(:service).provider(:launchd) + +describe provider_class do + + before :each do + # Create a mock resource + @resource = stub 'resource' + + @provider = provider_class.new + @joblabel = "com.foo.food" + @jobplist = {} + + # A catch all; no parameters set + @resource.stubs(:[]).returns(nil) + + # But set name, ensure and enable + @resource.stubs(:[]).with(:name).returns @joblabel + @resource.stubs(:[]).with(:ensure).returns :enabled + @resource.stubs(:[]).with(:enable).returns :true + @resource.stubs(:ref).returns "Service[#{@joblabel}]" + + # stub out the provider methods that actually touch the filesystem + # or execute commands + @provider.stubs(:plist_from_label).returns([@joblabel, @jobplist]) + @provider.stubs(:execute).returns("") + @provider.stubs(:resource).returns @resource + end + + it "should have a start method for #{@provider.object_id}" do + @provider.should respond_to(:start) + end + + it "should have a stop method" do + @provider.should respond_to(:stop) + end + + it "should have an enabled? method" do + @provider.should respond_to(:enabled?) + end + + it "should have an enable method" do + @provider.should respond_to(:enable) + end + + it "should have a disable method" do + @provider.should respond_to(:disable) + end + + it "should have a status method" do + @provider.should respond_to(:status) + end + + + describe "when checking status" do + it "should call the external command 'launchctl list' once" do + @provider.expects("launchctl").with(:list, @resource[:name]).returns(:running).once + @provider.status + end + end + + describe "when starting the service" do + it "should look for the relevant plist once" do + @provider.expects(:plist_from_label).once + @provider.start + end + it "should execute 'launchctl load' once without writing to the plist if the job is enabled" do + @provider.stubs(:enabled?).returns :true + @provider.expects(:execute).with([:launchctl, :load, @resource[:name]]).once + @provider.start + end + it "should execute 'launchctl load' with writing to the plist once if the job is disabled" do + @provider.stubs(:enabled?).returns :false + @provider.expects(:execute).with([:launchctl, :load, "-w", @resource[:name]]).once + @provider.start + end + it "should disable the job once if the job is disabled and should be disabled at boot" do + @provider.stubs(:enabled?).returns :false + @resource.stubs(:[]).with(:enable).returns :false + @provider.expects(:disable).once + @provider.start + end + end + + describe "when stopping the service" do + it "should look for the relevant plist once" do + @provider.expects(:plist_from_label).once + @provider.stop + end + it "should execute 'launchctl unload' once without writing to the plist if the job is disabled" do + @provider.stubs(:enabled?).returns :false + @provider.expects(:execute).with([:launchctl, :unload, @resource[:name]]).once + @provider.stop + end + it "should execute 'launchctl unload' with writing to the plist once if the job is enabled" do + @provider.stubs(:enabled?).returns :true + @provider.expects(:execute).with([:launchctl, :unload, "-w", @resource[:name]]).once + @provider.stop + end + it "should enable the job once if the job is enabled and should be enabled at boot" do + @provider.stubs(:enabled?).returns :true + @resource.stubs(:[]).with(:enable).returns :true + @provider.expects(:enable).once + @provider.stop + end + end + + describe "when enabling the service" do + it "should look for the relevant plist once" do + @provider.expects(:plist_from_label).once + @provider.stop + end + it "should check if the job is enabled once" do + @provider.expects(:enabled?).once + @provider.stop + end + end + + describe "when disabling the service" do + it "should look for the relevant plist once" do + @provider.expects(:plist_from_label).once + @provider.stop + end + end + + end diff --git a/spec/unit/provider/ssh_authorized_key/parsed.rb b/spec/unit/provider/ssh_authorized_key/parsed.rb index 16efc5b58..21f30f97e 100755 --- a/spec/unit/provider/ssh_authorized_key/parsed.rb +++ b/spec/unit/provider/ssh_authorized_key/parsed.rb @@ -92,4 +92,11 @@ describe provider_class do it "should set correct default permissions" do # No idea how to test the flush method end + + it "'s parse_options method should be able to parse options containing commas" do + options = %w{from="host1.reductlivelabs.com,host.reductivelabs.com" command="/usr/local/bin/run" ssh-pty} + optionstr = options.join(", ") + + @provider.parse_options(optionstr).should == options + end end diff --git a/spec/unit/provider/user/user_role_add.rb b/spec/unit/provider/user/user_role_add.rb index fc2074d44..49359eb10 100644 --- a/spec/unit/provider/user/user_role_add.rb +++ b/spec/unit/provider/user/user_role_add.rb @@ -49,6 +49,10 @@ describe provider_class do end describe "when calling create" do + before do + @provider.stubs(:password=) + end + it "should use the add command when the user is not a role" do @provider.stubs(:is_role?).returns(false) @provider.expects(:addcmd).returns("useradd") @@ -107,6 +111,7 @@ describe provider_class do end it "should add -o when the user is being created" do + @provider.stubs(:password=) @provider.create end @@ -188,4 +193,57 @@ describe provider_class do @provider.keys=({}) end end + + describe "when getting the hashed password" do + before do + @array = mock "array" + end + + it "should readlines of /etc/shadow" do + File.expects(:readlines).with("/etc/shadow").returns([]) + @provider.password + end + + it "should reject anything that doesn't start with alpha numerics" do + @array.expects(:reject).returns([]) + File.stubs(:readlines).with("/etc/shadow").returns(@array) + @provider.password + end + + it "should collect splitting on ':'" do + @array.stubs(:reject).returns(@array) + @array.expects(:collect).returns([]) + File.stubs(:readlines).with("/etc/shadow").returns(@array) + @provider.password + end + + it "should find the matching user" do + @resource.stubs(:[]).with(:name).returns("username") + @array.stubs(:reject).returns(@array) + @array.stubs(:collect).returns([["username", "hashedpassword"], ["someoneelse", "theirpassword"]]) + File.stubs(:readlines).with("/etc/shadow").returns(@array) + @provider.password.must == "hashedpassword" + end + + it "should get the right password" do + @resource.stubs(:[]).with(:name).returns("username") + File.stubs(:readlines).with("/etc/shadow").returns(["#comment", " nonsense", " ", "username:hashedpassword:stuff:foo:bar:::", "other:pword:yay:::"]) + @provider.password.must == "hashedpassword" + end + end + + describe "when setting the password" do + #how can you mock these blocks up? + it "should open /etc/shadow for reading and /etc/shadow_tmp for writing" do + File.expects(:open).with("/etc/shadow", "r") + File.stubs(:rename) + @provider.password=("hashedpassword") + end + + it "should rename the /etc/shadow_tmp to /etc/shadow" do + File.stubs(:open).with("/etc/shadow", "r") + File.expects(:rename).with("/etc/shadow_tmp", "/etc/shadow") + @provider.password=("hashedpassword") + end + end end diff --git a/spec/unit/provider/zfs/solaris.rb b/spec/unit/provider/zfs/solaris.rb new file mode 100755 index 000000000..63aefcdc4 --- /dev/null +++ b/spec/unit/provider/zfs/solaris.rb @@ -0,0 +1,87 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../../spec_helper' + +provider_class = Puppet::Type.type(:zfs).provider(:solaris) + +describe provider_class do + before do + @resource = stub("resource", :name => "myzfs") + @resource.stubs(:[]).with(:name).returns "myzfs" + @resource.stubs(:[]).returns "shouldvalue" + @provider = provider_class.new(@resource) + end + + describe "when calling add_properties" do + it "should add -o and the key=value for each properties with a value" do + @resource.stubs(:[]).with(:quota).returns "" + @resource.stubs(:[]).with(:mountpoint).returns "/foo" + properties = @provider.add_properties + properties.include?("-o").should == true + properties.include?("mountpoint=/foo").should == true + properties.detect { |a| a.include?("quota") }.should == nil + end + end + + describe "when calling create" do + it "should call add_properties" do + @provider.stubs(:zfs) + @provider.expects(:add_properties).returns([]) + @provider.create + end + + it "should call zfs with create, properties and this zfs" do + @provider.stubs(:add_properties).returns(%w{a b}) + @provider.expects(:zfs).with(:create, "a", "b", @resource[:name]) + @provider.create + end + end + + describe "when calling delete" do + it "should call zfs with :destroy and this zfs" do + @provider.expects(:zfs).with(:destroy, @resource[:name]) + @provider.delete + end + end + + describe "when calling exist?" do + it "should call zfs with :list" do + #return stuff because we have to slice and dice it + @provider.expects(:zfs).with(:list).returns("NAME USED AVAIL REFER MOUNTPOINT\nmyzfs 100K 27.4M /myzfs") + @provider.exists? + end + + it "should return true if returned values match the name" do + @provider.stubs(:zfs).with(:list).returns("NAME USED AVAIL REFER MOUNTPOINT\n#{@resource[:name]} 100K 27.4M /myzfs") + @provider.exists?.should == true + end + + it "should return false if returned values don't match the name" do + @provider.stubs(:zfs).with(:list).returns("no soup for you") + @provider.exists?.should == false + end + + end + + [:mountpoint, :compression, :copies, :quota, :reservation, :sharenfs, :snapdir].each do |prop| + describe "when getting the #{prop} value" do + it "should call zfs with :get, #{prop} and this zfs" do + @provider.expects(:zfs).with(:get, prop, @resource[:name]).returns("NAME PROPERTY VALUE SOURCE\nmyzfs name value blah") + @provider.send(prop) + end + + it "should get the third value of the second line from the output" do + @provider.stubs(:zfs).with(:get, prop, @resource[:name]).returns("NAME PROPERTY VALUE SOURCE\nmyzfs name value blah") + @provider.send(prop).should == "value" + end + end + + describe "when setting the #{prop} value" do + it "should call zfs with :set, #{prop}=value and this zfs" do + @provider.expects(:zfs).with(:set, "#{prop}=value", @resource[:name]) + @provider.send("#{prop}=".intern, "value") + end + end + end + +end diff --git a/spec/unit/provider/zone/solaris.rb b/spec/unit/provider/zone/solaris.rb new file mode 100755 index 000000000..b7dd74705 --- /dev/null +++ b/spec/unit/provider/zone/solaris.rb @@ -0,0 +1,42 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../../spec_helper' + +provider_class = Puppet::Type.type(:zone).provider(:solaris) + +describe provider_class do + before do + @resource = stub("resource", :name => "mypool") + @resource.stubs(:[]).returns "shouldvalue" + @provider = provider_class.new(@resource) + end + + describe "when calling configure" do + it "should add the create args to the create str" do + @resource.stubs(:properties).returns([]) + @resource.stubs(:[]).with(:create_args).returns("create_args") + @provider.expects(:setconfig).with("create -b create_args\nset zonepath=shouldvalue\ncommit\n") + @provider.configure + end + end + + describe "when installing" do + it "should call zoneadm" do + @provider.expects(:zoneadm) + @provider.install + end + + it "should just install if there are no install args" do + @resource.stubs(:[]).with(:install_args).returns(nil) + @provider.expects(:zoneadm).with(:install) + @provider.install + end + + it "should add the install args to the command if they exist" do + @resource.stubs(:[]).with(:install_args).returns("install args") + @provider.expects(:zoneadm).with(:install, ["install", "args"]) + @provider.install + end + end + +end diff --git a/spec/unit/provider/zpool/solaris.rb b/spec/unit/provider/zpool/solaris.rb new file mode 100755 index 000000000..af4db88c1 --- /dev/null +++ b/spec/unit/provider/zpool/solaris.rb @@ -0,0 +1,158 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../../spec_helper' + +provider_class = Puppet::Type.type(:zpool).provider(:solaris) + +describe provider_class do + before do + @resource = stub("resource", :name => "mypool") + @resource.stubs(:[]).returns "shouldvalue" + @provider = provider_class.new(@resource) + end + + describe "when getting the instance" do + it "should call process_zpool_data with the result of get_pool_data only once" do + @provider.stubs(:get_pool_data).returns(["foo", "disk"]) + @provider.expects(:process_zpool_data).with(["foo", "disk"]).returns("stuff").once + @provider.current_pool + @provider.current_pool + end + end + + describe "when calling flush" do + it "should need to reload the pool" do + @provider.stubs(:get_pool_data) + @provider.expects(:process_zpool_data).returns("stuff").times(2) + @provider.current_pool + @provider.flush + @provider.current_pool + end + end + + describe "when procesing zpool data" do + before do + @zpool_data = ["foo", "disk"] + end + + describe "when there is no data" do + it "should return a hash with ensure=>:absent" do + @provider.process_zpool_data([])[:ensure].should == :absent + end + end + + describe "when there is a spare" do + it "should add the spare disk to the hash and strip the array" do + @zpool_data += ["spares", "spare_disk"] + @provider.process_zpool_data(@zpool_data)[:spare].should == ["spare_disk"] + end + end + + describe "when there is a log" do + it "should add the log disk to the hash and strip the array" do + @zpool_data += ["logs", "log_disk"] + @provider.process_zpool_data(@zpool_data)[:log].should == ["log_disk"] + end + end + + describe "when the vdev is a mirror" do + it "should call create_multi_array with mirror" do + @zpool_data = ["mirrorpool", "mirror", "disk1", "disk2", "mirror", "disk3", "disk4"] + @provider.process_zpool_data(@zpool_data)[:mirror].should == ["disk1 disk2", "disk3 disk4"] + end + end + + describe "when the vdev is a raidz1" do + it "should call create_multi_array with raidz1" do + @zpool_data = ["mirrorpool", "raidz1", "disk1", "disk2"] + @provider.process_zpool_data(@zpool_data)[:raidz].should == ["disk1 disk2"] + end + end + + describe "when the vdev is a raidz2" do + it "should call create_multi_array with raidz2 and set the raid_parity" do + @zpool_data = ["mirrorpool", "raidz2", "disk1", "disk2"] + pool = @provider.process_zpool_data(@zpool_data) + pool[:raidz].should == ["disk1 disk2"] + pool[:raid_parity].should == "raidz2" + end + end + end + + describe "when calling the getters and setters" do + [:disk, :mirror, :raidz, :log, :spare].each do |field| + describe "when calling %s" % field do + it "should get the %s value from the current_pool hash" % field do + pool_hash = mock "pool hash" + pool_hash.expects(:[]).with(field) + @provider.stubs(:current_pool).returns(pool_hash) + @provider.send(field) + end + end + + describe "when setting the %s" % field do + it "should warn the %s values were not in sync" % field do + Puppet.expects(:warning).with("NO CHANGES BEING MADE: zpool %s does not match, should be 'shouldvalue' currently is 'currentvalue'" % field) + @provider.stubs(:current_pool).returns(Hash.new("currentvalue")) + @provider.send((field.to_s + "=").intern, "shouldvalue") + end + end + end + end + + describe "when calling create" do + before do + @resource.stubs(:[]).with(:pool).returns("mypool") + @provider.stubs(:zpool) + end + + + it "should call build_vdevs" do + @provider.expects(:build_vdevs).returns([]) + @provider.create + end + + it "should call build_named with 'spares' and 'log" do + @provider.expects(:build_named).with("spare").returns([]) + @provider.expects(:build_named).with("log").returns([]) + @provider.create + end + + it "should call zpool with arguments from build_vdevs and build_named" do + @provider.expects(:zpool).with(:create, 'mypool', 'shouldvalue', 'spare', 'shouldvalue', 'log', 'shouldvalue') + @provider.create + end + end + + describe "when calling delete" do + it "should call zpool with destroy and the pool name" do + @resource.stubs(:[]).with(:pool).returns("poolname") + @provider.expects(:zpool).with(:destroy, "poolname") + @provider.delete + end + end + + describe "when calling exists?" do + before do + @current_pool = Hash.new(:absent) + @provider.stubs(:get_pool_data).returns([]) + @provider.stubs(:process_zpool_data).returns(@current_pool) + end + + it "should get the current pool" do + @provider.expects(:process_zpool_data).returns(@current_pool) + @provider.exists? + end + + it "should return false if the current_pool is absent" do + #the before sets it up + @provider.exists?.should == false + end + + it "should return true if the current_pool has values" do + @current_pool[:pool] = "mypool" + @provider.exists?.should == true + end + end + +end diff --git a/spec/unit/ssl/certificate_request.rb b/spec/unit/ssl/certificate_request.rb index 3f25500c0..5d0de0814 100755 --- a/spec/unit/ssl/certificate_request.rb +++ b/spec/unit/ssl/certificate_request.rb @@ -142,7 +142,8 @@ describe Puppet::SSL::CertificateRequest do end it "should verify the generated request using the public key" do - @request.expects(:verify).with(@key.public_key) + # Stupid keys don't have a competent == method. + @request.expects(:verify).with { |public_key| public_key.to_s == @key.public_key.to_s }.returns true @instance.generate(@key) end diff --git a/spec/unit/transaction/change.rb b/spec/unit/transaction/change.rb index eaa6fb4ab..1f69311cd 100755 --- a/spec/unit/transaction/change.rb +++ b/spec/unit/transaction/change.rb @@ -108,6 +108,7 @@ describe Puppet::Transaction::Change do @change.stubs(:noop?).returns false @property.stub_everything @property.stubs(:resource).returns "myresource" + @property.stubs(:name).returns :myprop end it "should sync the property" do @@ -116,16 +117,20 @@ describe Puppet::Transaction::Change do @change.forward end - it "should return nil if syncing the property returns nil" do + it "should return the default event if syncing the property returns nil" do @property.stubs(:sync).returns nil - @change.forward.should be_nil + @change.expects(:event).with(:myprop_changed).returns :myevent + + @change.forward.should == [:myevent] end - it "should return nil if syncing the property returns an empty array" do + it "should return the default event if syncing the property returns an empty array" do @property.stubs(:sync).returns [] - @change.forward.should be_nil + @change.expects(:event).with(:myprop_changed).returns :myevent + + @change.forward.should == [:myevent] end it "should log the change" do diff --git a/spec/unit/type/computer.rb b/spec/unit/type/computer.rb new file mode 100755 index 000000000..43a313c5b --- /dev/null +++ b/spec/unit/type/computer.rb @@ -0,0 +1,78 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../spec_helper' + +computer = Puppet::Type.type(:computer) + +describe Puppet.type(:computer), " when checking computer objects" do + before do + provider_class = Puppet::Type::Computer.provider(Puppet::Type::Computer.providers[0]) + Puppet::Type::Computer.expects(:defaultprovider).returns provider_class + @resource = Puppet::Type::Computer.create( + :name => "puppetcomputertest", + :en_address => "aa:bb:cc:dd:ee:ff", + :ip_address => "1.2.3.4") + @properties = {} + @ensure = Puppet::Type::Computer.attrclass(:ensure).new(:resource => @resource) + end + + it "should be able to create a instance" do + provider_class = Puppet::Type::Computer.provider(Puppet::Type::Computer.providers[0]) + Puppet::Type::Computer.expects(:defaultprovider).returns provider_class + computer.create(:name => "bar").should_not be_nil + end + + properties = [:en_address, :ip_address] + params = [:name] + + properties.each do |property| + it "should have a %s property" % property do + computer.attrclass(property).ancestors.should be_include(Puppet::Property) + end + + it "should have documentation for its %s property" % property do + computer.attrclass(property).doc.should be_instance_of(String) + end + + it "should accept :absent as a value" do + prop = computer.attrclass(property).new(:resource => @resource) + prop.should = :absent + prop.should.must == :absent + end + end + + params.each do |param| + it "should have a %s parameter" % param do + computer.attrclass(param).ancestors.should be_include(Puppet::Parameter) + end + + it "should have documentation for its %s parameter" % param do + computer.attrclass(param).doc.should be_instance_of(String) + end + end + + describe "default values" do + before do + provider_class = computer.provider(computer.providers[0]) + computer.expects(:defaultprovider).returns provider_class + end + + it "should be nil for en_address" do + computer.create(:name => :en_address)[:en_address].should == nil + end + + it "should be nil for ip_address" do + computer.create(:name => :ip_address)[:ip_address].should == nil + end + end + + describe "when managing the ensure property" do + it "should support a :present value" do + lambda { @ensure.should = :present }.should_not raise_error + end + + it "should support an :absent value" do + lambda { @ensure.should = :absent }.should_not raise_error + end + end +end diff --git a/spec/unit/type/file/owner.rb b/spec/unit/type/file/owner.rb new file mode 100755 index 000000000..743e64054 --- /dev/null +++ b/spec/unit/type/file/owner.rb @@ -0,0 +1,132 @@ +#!/usr/bin/env ruby + +Dir.chdir(File.dirname(__FILE__)) { (s = lambda { |f| File.exist?(f) ? require(f) : Dir.chdir("..") { s.call(f) } }).call("spec/spec_helper.rb") } + +property = Puppet::Type.type(:file).attrclass(:owner) + +describe property do + before do + @resource = stub 'resource', :line => "foo", :file => "bar" + @resource.stubs(:[]).returns "foo" + @resource.stubs(:[]).with(:path).returns "/my/file" + @owner = property.new :resource => @resource + end + + it "should have a method for testing whether an owner is valid" do + @owner.must respond_to(:validuser?) + end + + it "should return the found uid if an owner is valid" do + @owner.expects(:uid).with("foo").returns 500 + @owner.validuser?("foo").should == 500 + end + + it "should return false if an owner is not valid" do + @owner.expects(:uid).with("foo").returns nil + @owner.validuser?("foo").should be_false + end + + describe "when retrieving the current value" do + it "should return :absent if the file cannot stat" do + @resource.expects(:stat).returns nil + + @owner.retrieve.should == :absent + end + + it "should get the uid from the stat instance from the file" do + stat = stub 'stat', :ftype => "foo" + @resource.expects(:stat).returns stat + stat.expects(:uid).returns 500 + + @owner.retrieve.should == 500 + end + + it "should warn and return :silly if the found value is higher than the maximum uid value" do + Puppet.settings.expects(:value).with(:maximum_uid).returns 500 + + stat = stub 'stat', :ftype => "foo" + @resource.expects(:stat).returns stat + stat.expects(:uid).returns 1000 + + @owner.expects(:warning) + @owner.retrieve.should == :silly + end + end + + describe "when determining if the file is in sync" do + describe "and not running as root" do + it "should warn and return true" do + @owner.should = 10 + Puppet::Util::SUIDManager.expects(:uid).returns 1 + @owner.expects(:warning) + @owner.must be_insync("whatever") + end + end + + before do + Puppet::Util::SUIDManager.stubs(:uid).returns 0 + end + + it "should directly compare the owner values if the desired owner is an integer" do + @owner.should = [10] + @owner.must be_insync(10) + end + + it "should treat numeric strings as integers" do + @owner.should = ["10"] + @owner.must be_insync(10) + end + + it "should convert the owner name to an integer if the desired owner is a string" do + @owner.expects(:uid).with("foo").returns 10 + @owner.should = %w{foo} + + @owner.must be_insync(10) + end + + it "should fail if it cannot convert an owner name to an integer" do + @owner.expects(:uid).with("foo").returns nil + @owner.should = %w{foo} + + lambda { @owner.insync?(10) }.should raise_error(Puppet::Error) + end + + it "should return false if the owners are not equal" do + @owner.should = [10] + @owner.should_not be_insync(20) + end + end + + describe "when changing the owner" do + before do + @owner.should = %w{one} + @owner.stubs(:path).returns "path" + @owner.stubs(:uid).returns 500 + end + + it "should chown the file if :links is set to :follow" do + @resource.expects(:[]).with(:links).returns :follow + File.expects(:chown) + + @owner.sync + end + + it "should lchown the file if :links is set to :manage" do + @resource.expects(:[]).with(:links).returns :manage + File.expects(:lchown) + + @owner.sync + end + + it "should use the first valid owner in its 'should' list" do + @owner.should = %w{one two three} + @owner.expects(:validuser?).with("one").returns nil + @owner.expects(:validuser?).with("two").returns 500 + @owner.expects(:validuser?).with("three").never + + File.expects(:chown).with(500, nil, "/my/file") + + @owner.sync + end + end +end diff --git a/spec/unit/type/file/selinux.rb b/spec/unit/type/file/selinux.rb index d346be362..c81270ab0 100644 --- a/spec/unit/type/file/selinux.rb +++ b/spec/unit/type/file/selinux.rb @@ -4,7 +4,7 @@ Dir.chdir(File.dirname(__FILE__)) { (s = lambda { |f| File.exist?(f) ? require(f [:seluser, :selrole, :seltype, :selrange].each do |param| -property = Puppet::Type.type(:file).attrclass(param) + property = Puppet::Type.type(:file).attrclass(param) describe property do before do @resource = mock 'resource' @@ -69,7 +69,6 @@ property = Puppet::Type.type(:file).attrclass(param) it "should be able to set a new context" do stat = stub 'stat', :ftype => "foo" - @resource.expects(:stat).returns stat @sel.should = %w{newone} @sel.expects(:set_selinux_context).with("/my/file", ["newone"], param) @sel.sync diff --git a/spec/unit/type/mcx.rb b/spec/unit/type/mcx.rb new file mode 100755 index 000000000..de7908e0f --- /dev/null +++ b/spec/unit/type/mcx.rb @@ -0,0 +1,100 @@ +#!/usr/bin/env ruby +#-- +# Copyright (C) 2008 Jeffrey J McCune. + +# This program and entire repository is free software; you can +# redistribute it and/or modify it under the terms of the GNU +# General Public License as published by the Free Software +# Foundation; either version 2 of the License, or any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +# Author: Jeff McCune <mccune.jeff@gmail.com> + +# Most of this code copied from /spec/type/service.rb + +require File.dirname(__FILE__) + '/../../spec_helper' + +require 'puppet/type/mcx' + +mcx_type = Puppet::Type.type(:mcx) + +describe mcx_type, "when validating attributes" do + + properties = [:ensure, :content] + parameters = [:name, :ds_type, :ds_name] + + parameters.each do |p| + it "should have a #{p} parameter" do + mcx_type.attrclass(p).ancestors.should be_include(Puppet::Parameter) + end + it "should have documentation for its #{p} parameter" do + mcx_type.attrclass(p).doc.should be_instance_of(String) + end + end + + properties.each do |p| + it "should have a #{p} property" do + mcx_type.attrclass(p).ancestors.should be_include(Puppet::Property) + end + it "should have documentation for its #{p} property" do + mcx_type.attrclass(p).doc.should be_instance_of(String) + end + end + +end + +describe mcx_type, "default values" do + + before :each do + provider_class = mcx_type.provider(mcx_type.providers[0]) + mcx_type.stubs(:defaultprovider).returns provider_class + end + + it "should be nil for :ds_type" do + mcx_type.create(:name => '/Foo/bar')[:ds_type].should be_nil + end + + it "should be nil for :ds_name" do + mcx_type.create(:name => '/Foo/bar')[:ds_name].should be_nil + end + + it "should be nil for :content" do + mcx_type.create(:name => '/Foo/bar')[:content].should be_nil + end + +end + +describe mcx_type, "when validating properties" do + + before :each do + provider_class = mcx_type.provider(mcx_type.providers[0]) + mcx_type.stubs(:defaultprovider).returns provider_class + end + + it "should be able to create an instance" do + lambda { + mcx_type.create(:name => '/Foo/bar') + }.should_not raise_error + end + + it "should support :present as a value to :ensure" do + lambda { + mcx_type.create(:name => "/Foo/bar", :ensure => :present) + }.should_not raise_error + end + + it "should support :absent as a value to :ensure" do + lambda { + mcx_type.create(:name => "/Foo/bar", :ensure => :absent) + }.should_not raise_error + end + +end diff --git a/spec/unit/type/package.rb b/spec/unit/type/package.rb index 103fd6037..13bf4d3d3 100755 --- a/spec/unit/type/package.rb +++ b/spec/unit/type/package.rb @@ -105,6 +105,7 @@ describe Puppet::Type.type(:package) do before :each do @provider = stub 'provider', :class => Puppet::Type.type(:package).defaultprovider, :clear => nil, :satisfies? => true, :name => :mock Puppet::Type.type(:package).defaultprovider.stubs(:new).returns(@provider) + Puppet::Type.type(:package).defaultprovider.stubs(:instances).returns([]) @package = Puppet::Type.type(:package).create(:name => "yay") @catalog = Puppet::Node::Catalog.new diff --git a/spec/unit/type/resources.rb b/spec/unit/type/resources.rb new file mode 100644 index 000000000..70bc21b5d --- /dev/null +++ b/spec/unit/type/resources.rb @@ -0,0 +1,23 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../spec_helper' + +resources = Puppet::Type.type(:resources) + +# There are still plenty of tests to port over from test/. +describe resources do + describe "when initializing" do + it "should fail if the specified resource type does not exist" do + Puppet::Type.expects(:type).with("nosuchtype").returns nil + lambda { resources.create :name => "nosuchtype" }.should raise_error(Puppet::Error) + end + + it "should not fail when the specified resource type exists" do + lambda { resources.create :name => "file" }.should_not raise_error + end + + it "should set its :resource_type attribute" do + resources.create(:name => "file").resource_type.should == Puppet::Type.type(:file) + end + end +end diff --git a/spec/unit/type/ssh_authorized_key.rb b/spec/unit/type/ssh_authorized_key.rb index 1860f2714..3240b7a94 100755 --- a/spec/unit/type/ssh_authorized_key.rb +++ b/spec/unit/type/ssh_authorized_key.rb @@ -73,6 +73,18 @@ describe ssh_authorized_key do @class.attrtype(:options).should == :property end + it "'s options property should return well formed string of arrays from is_to_s" do + resource = @class.create(:name => "whev", :type => :rsa, :user => "nobody", :options => ["a","b","c"]) + + resource.property(:options).is_to_s(["a","b","c"]).should == "a,b,c" + end + + it "'s options property should return well formed string of arrays from is_to_s" do + resource = @class.create(:name => "whev", :type => :rsa, :user => "nobody", :options => ["a","b","c"]) + + resource.property(:options).should_to_s(["a","b","c"]).should == "a,b,c" + end + it "should have a target property" do @class.attrtype(:target).should == :property end diff --git a/spec/unit/type/user.rb b/spec/unit/type/user.rb index 227a500f1..17524c5e5 100755 --- a/spec/unit/type/user.rb +++ b/spec/unit/type/user.rb @@ -52,6 +52,22 @@ describe user do end end + list_properties = [:groups, :roles, :auths] + + list_properties.each do |property| + it "should have a list '%s'" % property do + user.attrclass(property).ancestors.should be_include(Puppet::Property::List) + end + end + + it "should have an ordered list 'profiles'" do + user.attrclass(:profiles).ancestors.should be_include(Puppet::Property::OrderedList) + end + + it "should have key values 'keys'" do + user.attrclass(:keys).ancestors.should be_include(Puppet::Property::KeyValue) + end + describe "when retrieving all current values" do before do @user = user.create(:name => "foo", :uid => 10, :gid => 10) @@ -159,6 +175,26 @@ describe user do gid.should.must == "foo" end + describe "when testing whether in sync" do + before do + @gid = user.attrclass(:gid).new(:resource => @resource, :should => %w{foo bar}) + end + + it "should return true if any of the specified groups are equal to the current integer" do + Puppet::Util.expects(:gid).with("foo").returns 300 + Puppet::Util.expects(:gid).with("bar").returns 500 + + @gid.must be_insync(500) + end + + it "should return false if none of the specified groups are equal to the current integer" do + Puppet::Util.expects(:gid).with("foo").returns 300 + Puppet::Util.expects(:gid).with("bar").returns 500 + + @gid.should_not be_insync(700) + end + end + describe "when syncing" do before do @gid = user.attrclass(:gid).new(:resource => @resource, :should => %w{foo bar}) @@ -200,4 +236,15 @@ describe user do lambda { @ensure.should = :role }.should_not raise_error end end + + describe "when user has roles" do + it "should autorequire roles" do + testuser = Puppet.type(:user).create(:name => "testuser", :roles => "testrole") + testrole = Puppet.type(:user).create(:name => "testrole") + config = Puppet::Node::Catalog.new :testing do |conf| + [testuser, testrole].each { |resource| conf.add_resource resource } + end + testuser.autorequire + end + end end diff --git a/spec/unit/type/zfs.rb b/spec/unit/type/zfs.rb new file mode 100755 index 000000000..434415e24 --- /dev/null +++ b/spec/unit/type/zfs.rb @@ -0,0 +1,28 @@ +#!/usr/bin/env ruby + +Dir.chdir(File.dirname(__FILE__)) { (s = lambda { |f| File.exist?(f) ? require(f) : Dir.chdir("..") { s.call(f) } }).call("spec/spec_helper.rb") } + +zpool = Puppet::Type.type(:zfs) + +describe zpool do + before do + @provider = stub 'provider' + @resource = stub 'resource', :resource => nil, :provider => @provider, :line => nil, :file => nil + end + + properties = [:ensure, :mountpoint, :compression, :copies, :quota, :reservation, :sharenfs, :snapdir] + + properties.each do |property| + it "should have a %s property" % property do + zpool.attrclass(property).ancestors.should be_include(Puppet::Property) + end + end + + parameters = [:name] + + parameters.each do |parameter| + it "should have a %s parameter" % parameter do + zpool.attrclass(parameter).ancestors.should be_include(Puppet::Parameter) + end + end +end diff --git a/spec/unit/type/zone.rb b/spec/unit/type/zone.rb new file mode 100755 index 000000000..c99302644 --- /dev/null +++ b/spec/unit/type/zone.rb @@ -0,0 +1,20 @@ +#!/usr/bin/env ruby + +Dir.chdir(File.dirname(__FILE__)) { (s = lambda { |f| File.exist?(f) ? require(f) : Dir.chdir("..") { s.call(f) } }).call("spec/spec_helper.rb") } + +zone = Puppet::Type.type(:zone) + +describe zone do + before do + @provider = stub 'provider' + @resource = stub 'resource', :resource => nil, :provider => @provider, :line => nil, :file => nil + end + + parameters = [:create_args, :install_args] + + parameters.each do |parameter| + it "should have a %s parameter" % parameter do + zone.attrclass(parameter).ancestors.should be_include(Puppet::Parameter) + end + end +end diff --git a/spec/unit/type/zpool.rb b/spec/unit/type/zpool.rb new file mode 100755 index 000000000..6477d061d --- /dev/null +++ b/spec/unit/type/zpool.rb @@ -0,0 +1,28 @@ +#!/usr/bin/env ruby + +Dir.chdir(File.dirname(__FILE__)) { (s = lambda { |f| File.exist?(f) ? require(f) : Dir.chdir("..") { s.call(f) } }).call("spec/spec_helper.rb") } + +zpool = Puppet::Type.type(:zpool) + +describe zpool do + before do + @provider = stub 'provider' + @resource = stub 'resource', :resource => nil, :provider => @provider, :line => nil, :file => nil + end + + properties = [:ensure, :disk, :mirror, :raidz, :spare, :log] + + properties.each do |property| + it "should have a %s property" % property do + zpool.attrclass(property).ancestors.should be_include(Puppet::Property) + end + end + + parameters = [:pool, :raid_parity] + + parameters.each do |parameter| + it "should have a %s parameter" % parameter do + zpool.attrclass(parameter).ancestors.should be_include(Puppet::Parameter) + end + end +end diff --git a/spec/unit/util/selinux.rb b/spec/unit/util/selinux.rb index 7a56f914a..dacf9f503 100644 --- a/spec/unit/util/selinux.rb +++ b/spec/unit/util/selinux.rb @@ -1,24 +1,66 @@ #!/usr/bin/env ruby -Dir.chdir(File.dirname(__FILE__)) { (s = lambda { |f| File.exist?(f) ? require(f) : Dir.chdir("..") { s.call(f) } }).call("spec/spec_helper.rb") } +require File.dirname(__FILE__) + '/../../spec_helper' require 'puppet/util/selinux' include Puppet::Util::SELinux +unless defined?(Selinux) + module Selinux + def self.is_selinux_enabled + false + end + end +end + describe Puppet::Util::SELinux do describe "selinux_support?" do + before do + end it "should return :true if this system has SELinux enabled" do - FileTest.expects(:exists?).with("/selinux/enforce").returns true + Selinux.expects(:is_selinux_enabled).returns 1 selinux_support?.should be_true end it "should return :false if this system lacks SELinux" do - FileTest.expects(:exists?).with("/selinux/enforce").returns false + Selinux.expects(:is_selinux_enabled).returns 0 selinux_support?.should be_false end end + describe "filesystem detection" do + before :each do + File.expects(:read).with("/proc/mounts").returns "rootfs / rootfs rw 0 0\n/dev/root / ext3 rw,relatime,errors=continue,user_xattr,acl,data=ordered 0 0\n/dev /dev tmpfs rw,relatime,mode=755 0 0\n/proc /proc proc rw,relatime 0 0\n/sys /sys sysfs rw,relatime 0 0\n192.168.1.1:/var/export /mnt/nfs nfs rw,relatime,vers=3,rsize=32768,wsize=32768,namlen=255,hard,nointr,proto=tcp,timeo=600,retrans=2,sec=sys,mountaddr=192.168.1.1,mountvers=3,mountproto=udp,addr=192.168.1.1 0 0\n" + end + + it "should parse the contents of /proc/mounts" do + read_mounts().should == { + '/' => 'ext3', + '/sys' => 'sysfs', + '/mnt/nfs' => 'nfs', + '/proc' => 'proc', + '/dev' => 'tmpfs' } + end + + it "should match a path on / to ext3" do + find_fs('/etc/puppet/testfile').should == "ext3" + end + + it "should match a path on /mnt/nfs to nfs" do + find_fs('/mnt/nfs/testfile/foobar').should == "nfs" + end + + it "should reture true for a capable filesystem" do + selinux_label_support?('/etc/puppet/testfile').should be_true + end + + it "should return false for a noncapable filesystem" do + selinux_label_support?('/mnt/nfs/testfile').should be_false + end + + end + describe "get_selinux_current_context" do it "should return nil if no SELinux support" do self.expects(:selinux_support?).returns false @@ -27,19 +69,13 @@ describe Puppet::Util::SELinux do it "should return a context" do self.expects(:selinux_support?).returns true - self.expects(:execpipe).with("/usr/bin/stat -c %C /foo").yields ["user_u:role_r:type_t:s0\n"] + Selinux.expects(:lgetfilecon).with("/foo").returns [0, "user_u:role_r:type_t:s0"] get_selinux_current_context("/foo").should == "user_u:role_r:type_t:s0" end - it "should return nil if an exception is raised calling stat" do - self.expects(:selinux_support?).returns true - self.expects(:execpipe).with("/usr/bin/stat -c %C /foo").raises(Puppet::ExecutionFailure, 'error') - get_selinux_current_context("/foo").should be_nil - end - - it "should return nil if stat finds an unlabeled file" do + it "should return nil if lgetfilecon fails" do self.expects(:selinux_support?).returns true - self.expects(:execpipe).with("/usr/bin/stat -c %C /foo").yields ["(null)\n"] + Selinux.expects(:lgetfilecon).with("/foo").returns -1 get_selinux_current_context("/foo").should be_nil end end @@ -50,25 +86,30 @@ describe Puppet::Util::SELinux do get_selinux_default_context("/foo").should be_nil end - it "should return nil if matchpathcon is not executable" do + it "should return a context if a default context exists" do self.expects(:selinux_support?).returns true - FileTest.expects(:executable?).with("/usr/sbin/matchpathcon").returns false - get_selinux_default_context("/foo").should be_nil + fstat = stub 'File::Stat', :mode => 0 + File.expects(:lstat).with("/foo").returns fstat + self.expects(:find_fs).with("/foo").returns "ext3" + Selinux.expects(:matchpathcon).with("/foo", 0).returns [0, "user_u:role_r:type_t:s0"] + get_selinux_default_context("/foo").should == "user_u:role_r:type_t:s0" end - it "should return a context if a default context exists" do + it "should return nil if matchpathcon returns failure" do self.expects(:selinux_support?).returns true - FileTest.expects(:executable?).with("/usr/sbin/matchpathcon").returns true - self.expects(:execpipe).with("/usr/sbin/matchpathcon /foo").yields ["/foo\tuser_u:role_r:type_t:s0\n"] - get_selinux_default_context("/foo").should == "user_u:role_r:type_t:s0" + fstat = stub 'File::Stat', :mode => 0 + File.expects(:lstat).with("/foo").returns fstat + self.expects(:find_fs).with("/foo").returns "ext3" + Selinux.expects(:matchpathcon).with("/foo", 0).returns -1 + get_selinux_default_context("/foo").should be_nil end - it "should return nil if an exception is raised calling matchpathcon" do + it "should return nil if selinux_label_support returns false" do self.expects(:selinux_support?).returns true - FileTest.expects(:executable?).with("/usr/sbin/matchpathcon").returns true - self.expects(:execpipe).with("/usr/sbin/matchpathcon /foo").raises(Puppet::ExecutionFailure, 'error') + self.expects(:find_fs).with("/foo").returns "nfs" get_selinux_default_context("/foo").should be_nil end + end describe "parse_selinux_context" do @@ -115,33 +156,37 @@ describe Puppet::Util::SELinux do set_selinux_context("/foo", "user_u:role_r:type_t:s0").should be_nil end - it "should use chcon to set a context" do + it "should use lsetfilecon to set a context" do self.expects(:selinux_support?).returns true - self.expects(:execute).with(["/usr/bin/chcon","-h","user_u:role_r:type_t:s0","/foo"]).returns 0 + Selinux.expects(:lsetfilecon).with("/foo", "user_u:role_r:type_t:s0").returns 0 set_selinux_context("/foo", "user_u:role_r:type_t:s0").should be_true end - it "should use chcon to set user_u user context" do + it "should use lsetfilecon to set user_u user context" do self.expects(:selinux_support?).returns true - self.expects(:execute).with(["/usr/bin/chcon","-h","-u","user_u","/foo"]).returns 0 + Selinux.expects(:lgetfilecon).with("/foo").returns [0, "foo:role_r:type_t:s0"] + Selinux.expects(:lsetfilecon).with("/foo", "user_u:role_r:type_t:s0").returns 0 set_selinux_context("/foo", "user_u", :seluser).should be_true end - it "should use chcon to set role_r role context" do + it "should use lsetfilecon to set role_r role context" do self.expects(:selinux_support?).returns true - self.expects(:execute).with(["/usr/bin/chcon","-h","-r","role_r","/foo"]).returns 0 + Selinux.expects(:lgetfilecon).with("/foo").returns [0, "user_u:foo:type_t:s0"] + Selinux.expects(:lsetfilecon).with("/foo", "user_u:role_r:type_t:s0").returns 0 set_selinux_context("/foo", "role_r", :selrole).should be_true end - it "should use chcon to set type_t type context" do + it "should use lsetfilecon to set type_t type context" do self.expects(:selinux_support?).returns true - self.expects(:execute).with(["/usr/bin/chcon","-h","-t","type_t","/foo"]).returns 0 + Selinux.expects(:lgetfilecon).with("/foo").returns [0, "user_u:role_r:foo:s0"] + Selinux.expects(:lsetfilecon).with("/foo", "user_u:role_r:type_t:s0").returns 0 set_selinux_context("/foo", "type_t", :seltype).should be_true end - it "should use chcon to set s0:c3,c5 range context" do + it "should use lsetfilecon to set s0:c3,c5 range context" do self.expects(:selinux_support?).returns true - self.expects(:execute).with(["/usr/bin/chcon","-h","-l","s0:c3,c5","/foo"]).returns 0 + Selinux.expects(:lgetfilecon).with("/foo").returns [0, "user_u:role_r:type_t:s0"] + Selinux.expects(:lsetfilecon).with("/foo", "user_u:role_r:type_t:s0:c3,c5").returns 0 set_selinux_context("/foo", "s0:c3,c5", :selrange).should be_true end end |