summaryrefslogtreecommitdiffstats
path: root/spec
diff options
context:
space:
mode:
authorLuke Kanies <luke@madstop.com>2008-10-17 09:01:04 -0500
committerLuke Kanies <luke@madstop.com>2008-10-17 09:01:04 -0500
commit8aee40de69e6fe8d67ab58a2e223443b15820584 (patch)
tree89e230df3b43302a542f2cb6869f63e2fb93f6d8 /spec
parent1b517d2fb048603bd1743a662bde74e8ae4b13dc (diff)
parenta74ec60d33dee1c592ec858faeccc23d7a7b79f3 (diff)
downloadpuppet-8aee40de69e6fe8d67ab58a2e223443b15820584.tar.gz
puppet-8aee40de69e6fe8d67ab58a2e223443b15820584.tar.xz
puppet-8aee40de69e6fe8d67ab58a2e223443b15820584.zip
Merge branch '0.24.x' Removed the 'after' blocks that call Type.clear,
since that method is deprecated. Conflicts: CHANGELOG bin/puppetca lib/puppet/file_serving/fileset.rb lib/puppet/network/xmlrpc/client.rb lib/puppet/type/file/selcontext.rb spec/unit/file_serving/metadata.rb spec/unit/type/file.rb
Diffstat (limited to 'spec')
-rwxr-xr-xspec/integration/provider/package.rb26
-rwxr-xr-xspec/integration/reference/providers.rb17
-rw-r--r--spec/monkey_patches/add_confine_and_runnable_to_rspec_dsl.rb5
-rw-r--r--spec/monkey_patches/alias_should_to_must.rb5
-rwxr-xr-xspec/unit/file_serving/fileset.rb9
-rwxr-xr-xspec/unit/file_serving/metadata.rb22
-rwxr-xr-xspec/unit/module.rb13
-rw-r--r--spec/unit/network/handler/fileserver.rb179
-rw-r--r--spec/unit/network/xmlrpc/client.rb13
-rwxr-xr-xspec/unit/node.rb19
-rwxr-xr-xspec/unit/node/environment.rb52
-rwxr-xr-xspec/unit/parser/ast/arithmetic_operator.rb73
-rwxr-xr-xspec/unit/parser/ast/boolean_operator.rb53
-rwxr-xr-xspec/unit/parser/ast/collexpr.rb92
-rwxr-xr-xspec/unit/parser/ast/comparison_operator.rb52
-rwxr-xr-xspec/unit/parser/ast/minus.rb36
-rwxr-xr-xspec/unit/parser/ast/nop.rb20
-rwxr-xr-xspec/unit/parser/ast/not.rb30
-rwxr-xr-xspec/unit/parser/ast/resource_override.rb51
-rwxr-xr-xspec/unit/parser/ast/resource_reference.rb63
-rwxr-xr-xspec/unit/parser/collector.rb10
-rwxr-xr-xspec/unit/parser/lexer.rb57
-rwxr-xr-xspec/unit/parser/parser.rb113
-rwxr-xr-xspec/unit/parser/resource.rb10
-rwxr-xr-xspec/unit/parser/scope.rb50
-rwxr-xr-xspec/unit/parser/templatewrapper.rb14
-rw-r--r--spec/unit/property/list.rb147
-rwxr-xr-xspec/unit/provider/confine/variable.rb20
-rwxr-xr-xspec/unit/provider/package/apt.rb138
-rwxr-xr-xspec/unit/provider/package/dpkg.rb163
-rwxr-xr-xspec/unit/provider/selboolean.rb37
-rw-r--r--spec/unit/provider/selmodule-example.ppbin0 -> 256 bytes
-rwxr-xr-xspec/unit/provider/selmodule.rb66
-rw-r--r--spec/unit/provider/user/user_role_add.rb131
-rwxr-xr-xspec/unit/type.rb71
-rwxr-xr-xspec/unit/type/file/group.rb118
-rw-r--r--spec/unit/type/file/selinux.rb78
-rwxr-xr-xspec/unit/type/selboolean.rb45
-rwxr-xr-xspec/unit/type/selmodule.rb18
-rwxr-xr-xspec/unit/type/user.rb205
-rwxr-xr-xspec/unit/util/log.rb153
-rwxr-xr-xspec/unit/util/metric.rb95
-rwxr-xr-xspec/unit/util/posix.rb256
-rw-r--r--spec/unit/util/selinux.rb174
-rwxr-xr-xspec/unit/util/settings.rb15
-rw-r--r--spec/unit/util/user_attr.rb47
46 files changed, 2915 insertions, 146 deletions
diff --git a/spec/integration/provider/package.rb b/spec/integration/provider/package.rb
new file mode 100755
index 000000000..24a196266
--- /dev/null
+++ b/spec/integration/provider/package.rb
@@ -0,0 +1,26 @@
+#!/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") }
+
+describe "Package Provider" do
+ Puppet::Type.type(:package).providers.each do |name|
+ provider = Puppet::Type.type(:package).provider(name)
+
+ describe name do
+ confine "Provider %s is not suitable" % name => provider.suitable?
+
+ it "should fail when asked to install an invalid package" do
+ pending("This test hangs forever with recent versions of RubyGems") if provider.name == :gem
+ pkg = Puppet::Type.newpackage :name => "nosuch%s" % provider.name.to_s, :provider => provider.name
+ lambda { pkg.provider.install }.should raise_error
+ end
+
+ it "should be able to get a list of existing packages" do
+ provider.instances.each do |package|
+ package.should be_instance_of(provider)
+ package.properties[:provider].should == provider.name
+ end
+ end
+ end
+ end
+end
diff --git a/spec/integration/reference/providers.rb b/spec/integration/reference/providers.rb
new file mode 100755
index 000000000..79b6ce12d
--- /dev/null
+++ b/spec/integration/reference/providers.rb
@@ -0,0 +1,17 @@
+#!/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/util/reference'
+
+reference = Puppet::Util::Reference.reference(:providers)
+
+describe reference do
+ it "should exist" do
+ reference.should_not be_nil
+ end
+
+ it "should be able to be rendered as text" do
+ lambda { reference.to_text }.should_not raise_error
+ end
+end
diff --git a/spec/monkey_patches/add_confine_and_runnable_to_rspec_dsl.rb b/spec/monkey_patches/add_confine_and_runnable_to_rspec_dsl.rb
index 0b4a5abdb..27cd6b3df 100644
--- a/spec/monkey_patches/add_confine_and_runnable_to_rspec_dsl.rb
+++ b/spec/monkey_patches/add_confine_and_runnable_to_rspec_dsl.rb
@@ -15,7 +15,10 @@ module Spec
prepare
success = true
example_groups.each do |example_group|
- next unless example_group.runnable?
+ unless example_group.runnable?
+ warn "Skipping unsuitable example group %s: %s" % [example_group.description, example_group.messages.join(", ")]
+ next
+ end
success = success & example_group.run
end
return success
diff --git a/spec/monkey_patches/alias_should_to_must.rb b/spec/monkey_patches/alias_should_to_must.rb
new file mode 100644
index 000000000..35d3342f2
--- /dev/null
+++ b/spec/monkey_patches/alias_should_to_must.rb
@@ -0,0 +1,5 @@
+class Object
+ # This is necessary because the RAL has a 'should'
+ # method.
+ alias :must :should
+end
diff --git a/spec/unit/file_serving/fileset.rb b/spec/unit/file_serving/fileset.rb
index f95271050..2100b30f7 100755
--- a/spec/unit/file_serving/fileset.rb
+++ b/spec/unit/file_serving/fileset.rb
@@ -183,6 +183,15 @@ describe Puppet::FileServing::Fileset, " when recursing" do
@fileset.links = :manage
@fileset.files.sort.should == @files.sort
end
+
+ it "should succeed when paths have regexp significant characters" do
+ @path = "/my/path/rV1x2DafFr0R6tGG+1bbk++++TM"
+ File.expects(:lstat).with(@path).returns stub("stat", :directory? => true)
+ @fileset = Puppet::FileServing::Fileset.new(@path)
+ mock_dir_structure(@path)
+ @fileset.recurse = true
+ @fileset.files.sort.should == @files.sort
+ end
end
describe Puppet::FileServing::Fileset, " when following links that point to missing files" do
diff --git a/spec/unit/file_serving/metadata.rb b/spec/unit/file_serving/metadata.rb
index 768a7c56d..de0c4570c 100755
--- a/spec/unit/file_serving/metadata.rb
+++ b/spec/unit/file_serving/metadata.rb
@@ -43,10 +43,6 @@ describe Puppet::FileServing::Metadata, " when finding the file to use for setti
@metadata.collect()
end
- it "should fail if a base path is neither set nor provided" do
- proc { @metadata.collect() }.should raise_error(Errno::ENOENT)
- end
-
it "should raise an exception if the file does not exist" do
File.expects(:lstat).with(@path).raises(Errno::ENOENT)
proc { @metadata.collect()}.should raise_error(Errno::ENOENT)
@@ -100,6 +96,14 @@ describe Puppet::FileServing::Metadata, " when collecting attributes" do
@metadata.checksum.should == "{md5}" + @checksum
end
+ it "should give a mtime checksum when checksum_type is set" do
+ time = Time.now
+ @metadata.checksum_type = "mtime"
+ @metadata.expects(:mtime_file).returns(@time)
+ @metadata.collect
+ @metadata.checksum.should == "{mtime}" + @time.to_s
+ end
+
it "should produce tab-separated mode, type, owner, group, and checksum for xmlrpc" do
@metadata.attributes_with_tabs.should == "#{0755.to_s}\tfile\t10\t20\t{md5}#{@checksum}"
end
@@ -110,14 +114,22 @@ describe Puppet::FileServing::Metadata, " when collecting attributes" do
@stat.stubs(:ftype).returns("directory")
@time = Time.now
@metadata.expects(:ctime_file).returns(@time)
- @metadata.collect
end
it "should only use checksums of type 'ctime' for directories" do
+ @metadata.collect
+ @metadata.checksum.should == "{ctime}" + @time.to_s
+ end
+
+ it "should only use checksums of type 'ctime' for directories even if checksum_type set" do
+ @metadata.checksum_type = "mtime"
+ @metadata.expects(:mtime_file).never
+ @metadata.collect
@metadata.checksum.should == "{ctime}" + @time.to_s
end
it "should produce tab-separated mode, type, owner, group, and checksum for xmlrpc" do
+ @metadata.collect
@metadata.attributes_with_tabs.should == "#{0755.to_s}\tdirectory\t10\t20\t{ctime}#{@time.to_s}"
end
end
diff --git a/spec/unit/module.rb b/spec/unit/module.rb
index 4d66550b5..a6608fc1b 100755
--- a/spec/unit/module.rb
+++ b/spec/unit/module.rb
@@ -89,6 +89,19 @@ describe Puppet::Module, " when searching for templates" do
Puppet::Module.find_template("mymod/mytemplate").should == "/my/templates/mymod/mytemplate"
end
+ it "should raise an error if no valid templatedir exists" do
+ Puppet::Module.stubs(:templatepath).with(nil).returns(nil)
+ lambda { Puppet::Module.find_template("mytemplate") }.should raise_error
+ end
+
+ it "should not raise an error if no valid templatedir exists and the template exists in a module" do
+ Puppet::Module.stubs(:templatepath).with(nil).returns(nil)
+ Puppet[:modulepath] = "/one:/two"
+ File.stubs(:directory?).returns(true)
+ File.stubs(:exists?).returns(true)
+ Puppet::Module.find_template("mymod/mytemplate").should == "/one/mymod/templates/mytemplate"
+ end
+
it "should use the main templatedir if no module is found" do
Puppet::Module.stubs(:templatepath).with(nil).returns(["/my/templates"])
Puppet::Module.expects(:find).with("mymod", nil).returns(nil)
diff --git a/spec/unit/network/handler/fileserver.rb b/spec/unit/network/handler/fileserver.rb
new file mode 100644
index 000000000..4ba8e712d
--- /dev/null
+++ b/spec/unit/network/handler/fileserver.rb
@@ -0,0 +1,179 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+require 'puppet/network/handler/fileserver'
+
+
+describe Puppet::Network::Handler::FileServer do
+ require 'tmpdir'
+
+ def create_file(filename)
+ File.open(filename, "w") { |f| f.puts filename}
+ end
+
+ def create_nested_file()
+ dirname = File.join(@basedir, "nested_dir")
+ Dir.mkdir(dirname)
+ file = File.join(dirname, "nested_dir_file")
+ create_file(file)
+ end
+
+ before do
+ @basedir = File.join(Dir.tmpdir(), "test_network_handler")
+ Dir.mkdir(@basedir)
+ @file = File.join(@basedir, "aFile")
+ @link = File.join(@basedir, "aLink")
+ create_file(@file)
+ @mount = Puppet::Network::Handler::FileServer::Mount.new("some_path", @basedir)
+ end
+
+ it "should list a single directory" do
+ @mount.list("/", false, false).should == [["/", "directory"]]
+ end
+
+ it "should list a file within a directory when given the file path" do
+ @mount.list("/aFile", false, "false").should == [["/", "file"]]
+ end
+
+ it "should list a file within a directory when given the file path with recursion" do
+ @mount.list("/aFile", true, "false").should == [["/", "file"]]
+ end
+
+ it "should return nil for a non-existent path" do
+ @mount.list("/no_such_file", false, false).should be(nil)
+ end
+
+ it "should list a symbolic link as a file when given the link path" do
+ File.symlink(@file, @link)
+ @mount.list("/aLink", false, false).should == [["/", "file"]]
+ end
+
+ it "should return nil for a dangling symbolic link when given the link path" do
+ File.symlink("/some/where", @link)
+ @mount.list("/aLink", false, false).should be(nil)
+ end
+
+ it "should list directory contents of a flat directory structure when asked to recurse" do
+ list = @mount.list("/", true, false)
+ list.should include(["/aFile", "file"])
+ list.should include(["/", "directory"])
+ list.should have(2).items
+ end
+
+ it "should list the contents of a nested directory" do
+ create_nested_file()
+ list = @mount.list("/", true, false)
+ list.sort.should == [ ["/aFile", "file"], ["/", "directory"] ,
+ ["/nested_dir", "directory"], ["/nested_dir/nested_dir_file", "file"]].sort
+ end
+
+ it "should list the contents of a directory ignoring files that match" do
+ create_nested_file()
+ list = @mount.list("/", true, "*File")
+ list.sort.should == [ ["/", "directory"] ,
+ ["/nested_dir", "directory"], ["/nested_dir/nested_dir_file", "file"]].sort
+ end
+
+ it "should list the contents of a directory ignoring directories that match" do
+ create_nested_file()
+ list = @mount.list("/", true, "*nested_dir")
+ list.sort.should == [ ["/aFile", "file"], ["/", "directory"] ].sort
+ end
+
+ it "should list the contents of a directory ignoring all ignore patterns that match" do
+ create_nested_file()
+ list = @mount.list("/", true, ["*File" , "*nested_dir"])
+ list.should == [ ["/", "directory"] ]
+ end
+
+ it "should list the directory when recursing to a depth of zero" do
+ create_nested_file()
+ list = @mount.list("/", 0, false)
+ list.should == [["/", "directory"]]
+ end
+
+ it "should list the base directory and files and nested directory to a depth of one" do
+ create_nested_file()
+ list = @mount.list("/", 1, false)
+ list.sort.should == [ ["/aFile", "file"], ["/nested_dir", "directory"], ["/", "directory"] ].sort
+ end
+
+ it "should list the base directory and files and nested directory to a depth of two" do
+ create_nested_file()
+ list = @mount.list("/", 2, false)
+ list.sort.should == [ ["/aFile", "file"], ["/", "directory"] ,
+ ["/nested_dir", "directory"], ["/nested_dir/nested_dir_file", "file"]].sort
+ end
+
+ it "should list the base directory and files and nested directory to a depth greater than the directory structure" do
+ create_nested_file()
+ list = @mount.list("/", 42, false)
+ list.sort.should == [ ["/aFile", "file"], ["/", "directory"] ,
+ ["/nested_dir", "directory"], ["/nested_dir/nested_dir_file", "file"]].sort
+ end
+
+ it "should list a valid symbolic link as a file when recursing base dir" do
+ File.symlink(@file, @link)
+ list = @mount.list("/", true, false)
+ list.sort.should == [ ["/", "directory"], ["/aFile", "file"], ["/aLink", "file"] ].sort
+ end
+
+ it "should not error when a dangling symlink is present" do
+ File.symlink("/some/where", @link)
+ lambda { @mount.list("/", true, false) }.should_not raise_error
+ end
+
+ it "should return the directory contents of valid entries when a dangling symlink is present" do
+ File.symlink("/some/where", @link)
+ list = @mount.list("/", true, false)
+ list.sort.should == [ ["/aFile", "file"], ["/", "directory"] ].sort
+ end
+
+ describe Puppet::Network::Handler::FileServer::PluginMount do
+ PLUGINS = Puppet::Network::Handler::FileServer::PLUGINS
+
+ # create a module plugin hierarchy
+ def create_plugin(mod, plugin)
+ dirname = File.join(@basedir, mod)
+ Dir.mkdir(dirname)
+ plugins = File.join(dirname, PLUGINS)
+ Dir.mkdir(plugins)
+ facter = File.join(plugins, plugin)
+ Dir.mkdir(facter)
+ create_file(File.join(facter,"fact.rb"))
+ end
+
+ before :each do
+ @modules = ["one","two"]
+ Puppet::Module.stubs(:all).returns(@modules.collect{ |p| File.join(@basedir,p)} )
+ @modules.each { |m| create_plugin(m, "facter") }
+
+ @modules.each do |p|
+ File.stubs(:directory?).with(File.join(@basedir,p,PLUGINS)).returns(true)
+ end
+
+ @mount = Puppet::Network::Handler::FileServer::PluginMount.new(PLUGINS)
+ @mount.allow("*")
+ end
+
+ it "should list a file within a directory when given the file path with recursion" do
+ @mount.list("facter/fact.rb", true, "false").should == [["/", "file"], ["/", "file"]]
+ end
+
+ it "should return a merged view of all plugins for all modules" do
+ list = @mount.list("facter",true,false)
+ list.should == [["/", "directory"], ["/fact.rb", "file"], ["/", "directory"], ["/fact.rb", "file"]]
+ end
+
+ it "should not fail for inexistant plugins type" do
+ lambda { @mount.list("puppet/parser",true,false) }.should_not raise_error
+ end
+
+ end
+
+ after do
+ FileUtils.rm_rf(@basedir)
+ end
+
+end
diff --git a/spec/unit/network/xmlrpc/client.rb b/spec/unit/network/xmlrpc/client.rb
new file mode 100644
index 000000000..a0a2e77fb
--- /dev/null
+++ b/spec/unit/network/xmlrpc/client.rb
@@ -0,0 +1,13 @@
+#!/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") }
+
+describe Puppet::Network do
+ it "should raise an XMLRPCClientError if a generated class raises a Timeout::Error" do
+ http = mock 'http'
+ Puppet::Network::HttpPool.stubs(:http_instance).returns http
+ file = Puppet::Network::Client.file.new({:Server => "foo.com"})
+ http.stubs(:post2).raises Timeout::Error
+ lambda { file.retrieve }.should raise_error(Puppet::Network::XMLRPCClientError)
+ end
+end
diff --git a/spec/unit/node.rb b/spec/unit/node.rb
index 70aa8bd9a..df3b7483c 100755
--- a/spec/unit/node.rb
+++ b/spec/unit/node.rb
@@ -45,20 +45,15 @@ describe Puppet::Node, "when initializing" do
end
it "should accept an environment value" do
- Puppet.settings.stubs(:value).with(:environments).returns("myenv")
+ Puppet.settings.stubs(:value).with(:environment).returns("myenv")
@node = Puppet::Node.new("testing", :environment => "myenv")
@node.environment.should == "myenv"
end
-
- it "should validate the environment" do
- Puppet.settings.stubs(:value).with(:environments).returns("myenv")
- proc { Puppet::Node.new("testing", :environment => "other") }.should raise_error(ArgumentError)
- end
end
describe Puppet::Node, "when returning the environment" do
before do
- Puppet.settings.stubs(:value).with(:environments).returns("one,two")
+ Puppet.settings.stubs(:value).with(:environment).returns("one,two")
Puppet.settings.stubs(:value).with(:environment).returns("one")
@node = Puppet::Node.new("testnode")
end
@@ -73,16 +68,6 @@ describe Puppet::Node, "when returning the environment" do
Puppet::Node::Environment.expects(:new).returns(env)
@node.environment.should == "myenv"
end
-
- it "should fail if the parameter environment is invalid" do
- @node.parameters = {"environment" => "three"}
- proc { @node.environment }.should raise_error(ArgumentError)
- end
-
- it "should fail if the parameter environment is invalid" do
- @node.parameters = {"environment" => "three"}
- proc { @node.environment }.should raise_error(ArgumentError)
- end
end
describe Puppet::Node, "when merging facts" do
diff --git a/spec/unit/node/environment.rb b/spec/unit/node/environment.rb
index 8433a9877..872c70912 100755
--- a/spec/unit/node/environment.rb
+++ b/spec/unit/node/environment.rb
@@ -5,73 +5,21 @@ require File.dirname(__FILE__) + '/../../spec_helper'
require 'puppet/node/environment'
describe Puppet::Node::Environment do
- it "should provide a list of valid environments" do
- Puppet::Node::Environment.valid.should be_instance_of(Array)
- end
-
- it "should determine its list of valid environments from splitting the :environments setting on commas" do
- Puppet.settings.stubs(:value).with(:environments).returns("one,two")
- Puppet::Node::Environment.valid.collect { |e| e.to_s }.sort.should == %w{one two}.sort
- end
-
- it "should not use an environment when determining the list of valid environments" do
- Puppet.settings.expects(:value).with(:environments).returns("one,two")
- Puppet::Node::Environment.valid
- end
-
- it "should provide a means of identifying invalid environments" do
- Puppet.settings.expects(:value).with(:environments).returns("one,two")
- Puppet::Node::Environment.valid?(:three).should be_false
- end
-
- it "should provide a means of identifying valid environments" do
- Puppet.settings.expects(:value).with(:environments).returns("one,two")
- Puppet::Node::Environment.valid?(:one).should be_true
- end
-
- it "should be used to determine when an environment setting is valid" do
- Puppet.settings.expects(:value).with(:environments).returns("one,two")
- proc { Puppet.settings[:environment] = :three }.should raise_error(ArgumentError)
- end
-
it "should use the default environment if no name is provided while initializing an environment" do
- Puppet.settings.expects(:value).with(:environments).returns("one,two")
Puppet.settings.expects(:value).with(:environment).returns("one")
Puppet::Node::Environment.new().name.should == :one
end
it "should treat environment instances as singletons" do
- Puppet.settings.stubs(:value).with(:environments).returns("one")
Puppet::Node::Environment.new("one").should equal(Puppet::Node::Environment.new("one"))
end
it "should treat an environment specified as names or strings as equivalent" do
- Puppet.settings.stubs(:value).with(:environments).returns("one")
Puppet::Node::Environment.new(:one).should equal(Puppet::Node::Environment.new("one"))
end
-
- it "should fail if an invalid environment instance is asked for" do
- Puppet.settings.stubs(:value).with(:environments).returns("one,two")
- proc { Puppet::Node::Environment.new("three") }.should raise_error(ArgumentError)
- end
-
- it "should consider environments that are empty strings invalid" do
- Puppet::Node::Environment.valid?("").should be_false
- end
-
- it "should fail if a no-longer-valid environment instance is asked for" do
- Puppet.settings.expects(:value).with(:environments).returns("one")
- Puppet::Node::Environment.new("one")
- Puppet.settings.expects(:value).with(:environments).returns("two")
- proc { Puppet::Node::Environment.new("one") }.should raise_error(ArgumentError)
- end
end
describe Puppet::Node::Environment, " when modeling a specific environment" do
- before do
- Puppet.settings.expects(:value).with(:environments).returns("testing")
- end
-
it "should have a method for returning the environment name" do
Puppet::Node::Environment.new("testing").name.should == :testing
end
diff --git a/spec/unit/parser/ast/arithmetic_operator.rb b/spec/unit/parser/ast/arithmetic_operator.rb
new file mode 100755
index 000000000..24d6ad47d
--- /dev/null
+++ b/spec/unit/parser/ast/arithmetic_operator.rb
@@ -0,0 +1,73 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+describe Puppet::Parser::AST::ArithmeticOperator do
+
+ AST = Puppet::Parser::AST
+
+ before :each do
+ @scope = Puppet::Parser::Scope.new()
+ @one = stub 'lval', :safeevaluate => 1
+ @two = stub 'rval', :safeevaluate => 2
+ end
+
+ it "should evaluate both branches" do
+ lval = stub "lval"
+ lval.expects(:safeevaluate).with(@scope).returns(1)
+ rval = stub "rval"
+ rval.expects(:safeevaluate).with(@scope).returns(2)
+
+ 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
+ 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)
+ end
+
+
+ %w{ + - * / << >>}.each do |op|
+ it "should call ruby Numeric '#{op}'" do
+ one = stub 'one'
+ two = stub '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)
+ operator.evaluate(@scope)
+ end
+ end
+
+ 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.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.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" )
+
+ operator = AST::ArithmeticOperator.new :lval => one, :operator => "+", :rval => two
+ operator.evaluate(@scope).should == 3
+ end
+
+end
diff --git a/spec/unit/parser/ast/boolean_operator.rb b/spec/unit/parser/ast/boolean_operator.rb
new file mode 100755
index 000000000..7304e2a10
--- /dev/null
+++ b/spec/unit/parser/ast/boolean_operator.rb
@@ -0,0 +1,53 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+describe Puppet::Parser::AST::BooleanOperator do
+
+ 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)
+ end
+
+ it "should evaluate left operand inconditionally" do
+ lval = stub "lval"
+ lval.expects(:safeevaluate).with(@scope).returns("true")
+ rval = stub "rval", :safeevaluate => false
+ rval.expects(:safeevaluate).never
+
+ operator = AST::BooleanOperator.new :rval => rval, :operator => "or", :lval => lval
+ operator.evaluate(@scope)
+ end
+
+ it "should evaluate right 'and' operand only if left operand is true" 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.evaluate(@scope)
+ end
+
+ it "should evaluate right 'or' operand only if left operand is false" 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.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
+ 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
+ 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
+ end
+
+end
diff --git a/spec/unit/parser/ast/collexpr.rb b/spec/unit/parser/ast/collexpr.rb
new file mode 100755
index 000000000..e5e6e0d7a
--- /dev/null
+++ b/spec/unit/parser/ast/collexpr.rb
@@ -0,0 +1,92 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+describe Puppet::Parser::AST::CollExpr do
+
+ AST = Puppet::Parser::AST
+
+ before :each do
+ @scope = Puppet::Parser::Scope.new()
+ end
+
+ describe "when evaluating with two operands" do
+ before :each do
+ @test1 = mock 'test1'
+ @test1.expects(:safeevaluate).with(@scope).returns("test1")
+ @test2 = mock 'test2'
+ @test2.expects(:safeevaluate).with(@scope).returns("test2")
+ end
+
+ it "should evaluate both" do
+ 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=>"==")
+ result = collexpr.evaluate(@scope)
+ result[0].should == "param_values.value = 'test2' and param_names.name = 'test1'"
+ result[1].should be_an_instance_of(Proc)
+ end
+
+ it "should propagate expression type and form to child if expression themselves" do
+ [@test1, @test2].each do |t|
+ t.expects(:is_a?).returns(true)
+ t.expects(:form).returns(false)
+ t.expects(:type).returns(false)
+ t.expects(:type=)
+ t.expects(:form=)
+ end
+
+ collexpr = AST::CollExpr.new(:test1 => @test1, :test2 => @test2, :oper=>"==", :form => true, :type => true)
+ result = collexpr.evaluate(@scope)
+ end
+
+ describe "and when evaluating the produced code" do
+ before :each do
+ @resource = mock 'resource'
+ @resource.expects(:[]).with("test1").at_least(1).returns("test2")
+ end
+
+ it "should evaluate like the original expression for ==" do
+ 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.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)
+ 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)
+ lambda { collexpr.evaluate(@scope) }.should raise_error(Puppet::ParseError)
+ end
+ end
+ end
+
+ it "should check for array member equality if resource parameter is an array for ==" do
+ array = mock 'array', :safeevaluate => "array"
+ test1 = mock 'test1'
+ test1.expects(:safeevaluate).with(@scope).returns("test1")
+
+ resource = mock 'resource'
+ resource.expects(:[]).with("array").at_least(1).returns(["test1","test2","test3"])
+ 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
+ end
+
+end \ No newline at end of file
diff --git a/spec/unit/parser/ast/comparison_operator.rb b/spec/unit/parser/ast/comparison_operator.rb
new file mode 100755
index 000000000..dbea349f2
--- /dev/null
+++ b/spec/unit/parser/ast/comparison_operator.rb
@@ -0,0 +1,52 @@
+#!/usr/bin/env ruby
+
+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 )
+ end
+
+ it "should evaluate both branches" do
+ lval = stub "lval"
+ lval.expects(:safeevaluate).with(@scope)
+ rval = stub "rval"
+ rval.expects(:safeevaluate).with(@scope)
+
+ operator = Puppet::Parser::AST::ComparisonOperator.new :lval => lval, :operator => "==", :rval => rval
+ operator.evaluate(@scope)
+ 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.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.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" )
+
+ operator = Puppet::Parser::AST::ComparisonOperator.new :lval => one, :operator => "<", :rval => two
+ operator.evaluate(@scope).should == true
+ end
+
+end
diff --git a/spec/unit/parser/ast/minus.rb b/spec/unit/parser/ast/minus.rb
new file mode 100755
index 000000000..83bd92d0d
--- /dev/null
+++ b/spec/unit/parser/ast/minus.rb
@@ -0,0 +1,36 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+describe Puppet::Parser::AST::Minus do
+ before :each do
+ @scope = Puppet::Parser::Scope.new()
+ end
+
+ it "should evaluate its argument" do
+ value = stub "value"
+ value.expects(:safeevaluate).with(@scope).returns(123)
+
+ operator = Puppet::Parser::AST::Minus.new :value => value
+ operator.evaluate(@scope)
+ end
+
+ it "should fail if argument is not a string or integer" do
+ array_ast = stub 'array_ast', :safeevaluate => [2]
+ operator = Puppet::Parser::AST::Minus.new :value => array_ast
+ lambda { operator.evaluate(@scope) }.should raise_error
+ end
+
+ it "should work with integer as string" do
+ string = stub 'string', :safeevaluate => "123"
+ operator = Puppet::Parser::AST::Minus.new :value => string
+ operator.evaluate(@scope).should == -123
+ end
+
+ it "should work with integers" do
+ int = stub 'int', :safeevaluate => 123
+ operator = Puppet::Parser::AST::Minus.new :value => int
+ operator.evaluate(@scope).should == -123
+ end
+
+end
diff --git a/spec/unit/parser/ast/nop.rb b/spec/unit/parser/ast/nop.rb
new file mode 100755
index 000000000..5a7132586
--- /dev/null
+++ b/spec/unit/parser/ast/nop.rb
@@ -0,0 +1,20 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+describe Puppet::Parser::AST::Nop do
+
+ before do
+ @scope = mock 'scope'
+ end
+
+ it "should do nothing on evaluation" do
+ Puppet::Parser::AST.expects(:safeevaluate).never
+ Puppet::Parser::AST::Nop.new({}).evaluate(@scope)
+ end
+
+ it "should not return anything" do
+ Puppet::Parser::AST::Nop.new({}).evaluate(@scope).should be_nil
+ end
+
+end
diff --git a/spec/unit/parser/ast/not.rb b/spec/unit/parser/ast/not.rb
new file mode 100755
index 000000000..0fe2deddd
--- /dev/null
+++ b/spec/unit/parser/ast/not.rb
@@ -0,0 +1,30 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+describe Puppet::Parser::AST::Not do
+ before :each do
+ @scope = Puppet::Parser::Scope.new()
+ @true_ast = Puppet::Parser::AST::Boolean.new( :value => true)
+ @false_ast = Puppet::Parser::AST::Boolean.new( :value => false)
+ end
+
+ it "should evaluate its child expression" do
+ val = stub "val"
+ val.expects(:safeevaluate).with(@scope)
+
+ operator = Puppet::Parser::AST::Not.new :value => val
+ operator.evaluate(@scope)
+ end
+
+ it "should return true for ! false" do
+ operator = Puppet::Parser::AST::Not.new :value => @false_ast
+ operator.evaluate(@scope).should == true
+ end
+
+ it "should return false for ! true" do
+ operator = Puppet::Parser::AST::Not.new :value => @true_ast
+ operator.evaluate(@scope).should == false
+ end
+
+end
diff --git a/spec/unit/parser/ast/resource_override.rb b/spec/unit/parser/ast/resource_override.rb
new file mode 100755
index 000000000..3fbeb323c
--- /dev/null
+++ b/spec/unit/parser/ast/resource_override.rb
@@ -0,0 +1,51 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+describe Puppet::Parser::AST::ResourceOverride do
+
+ AST = Puppet::Parser::AST
+
+ before :each do
+ @compiler = stub 'compiler'
+ @scope = Puppet::Parser::Scope.new(:compiler => @compiler)
+ @params = AST::ASTArray.new({})
+ @compiler.stubs(:add_override)
+ end
+
+ it "should evaluate the overriden object" 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)
+ end
+
+ it "should tell the compiler to override the resource with our own" do
+ @compiler.expects(:add_override)
+
+ klass = stub 'klass', :title => "title", :type => "one"
+ object = mock 'object', :safeevaluate => klass
+ 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.should be_an_instance_of(Puppet::Parser::Resource)
+ override.title.should == "title"
+ override.type.should == "One"
+ end
+
+ it "should return an array of overriden resources when called with an array of titles" do
+ klass1 = stub 'klass1', :title => "title1", :type => "one"
+ klass2 = stub 'klass2', :title => "title2", :type => "one"
+
+ object = mock 'object', :safeevaluate => [klass1,klass2]
+
+ 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
diff --git a/spec/unit/parser/ast/resource_reference.rb b/spec/unit/parser/ast/resource_reference.rb
new file mode 100755
index 000000000..e4b7c763b
--- /dev/null
+++ b/spec/unit/parser/ast/resource_reference.rb
@@ -0,0 +1,63 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+describe Puppet::Parser::AST::ResourceReference do
+
+ AST = Puppet::Parser::AST
+
+ before :each do
+ @scope = Puppet::Parser::Scope.new()
+ end
+
+ def newref(title, type)
+ title = stub 'title', :safeevaluate => title
+ ref = AST::ResourceReference.new(:type => type, :title => title)
+ end
+
+ it "should evaluate correctly reference to builtin types" do
+ newref("/tmp/yay", "File").evaluate(@scope).to_s.should == "File[/tmp/yay]"
+ end
+
+ %{ "one::two" "one-two"}.each do |type|
+ it "should evaluate correctly reference to define" do
+ klass = stub 'klass', :title => "three", :classname => type
+ @scope.stubs(:finddefine).returns(klass)
+
+ newref("three", type).evaluate(@scope).to_ref.should == Puppet::Parser::Resource::Reference.new( :type => type, :title => "three" ).to_ref
+ end
+ end
+
+ it "should be able to call qualified_class" do
+ klass = stub 'klass', :title => "three", :classname => "one"
+ @scope.expects(:findclass).with("one").returns(klass)
+ newref("three","class").qualified_class(@scope,"one").should == "one"
+ end
+
+ it "should be able to find qualified classes when evaluating" do
+ klass = stub 'klass', :title => "one", :classname => "one"
+ @scope.stubs(:findclass).returns(klass)
+
+ evaled = newref("one", "class").evaluate(@scope)
+ evaled.type.should == "Class"
+ evaled.title.should == "one"
+ end
+
+ 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.stubs(:qualified_type).with(@scope).returns("Resource")
+
+ ref.evaluate(@scope).should have(2).elements
+ end
+
+ 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.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
diff --git a/spec/unit/parser/collector.rb b/spec/unit/parser/collector.rb
index 2dfae6786..ede583b96 100755
--- a/spec/unit/parser/collector.rb
+++ b/spec/unit/parser/collector.rb
@@ -234,16 +234,16 @@ describe Puppet::Parser::Collector, "when collecting exported resources" do
@collector.evaluate
end
- it "should return all matching resources from the current compile" do
+ it "should return all matching resources from the current compile and mark them non-virtual and non-exported" do
stub_rails(true)
one = stub 'one', :type => "Mytype", :virtual? => true, :exported? => true
two = stub 'two', :type => "Mytype", :virtual? => true, :exported? => true
- one.stubs(:exported=)
- one.stubs(:virtual=)
- two.stubs(:exported=)
- two.stubs(:virtual=)
+ one.expects(:exported=).with(false)
+ one.expects(:virtual=).with(false)
+ two.expects(:exported=).with(false)
+ two.expects(:virtual=).with(false)
@compiler.expects(:resources).returns([one, two])
diff --git a/spec/unit/parser/lexer.rb b/spec/unit/parser/lexer.rb
index fed1ade7d..3b0df96a9 100755
--- a/spec/unit/parser/lexer.rb
+++ b/spec/unit/parser/lexer.rb
@@ -4,6 +4,27 @@ require File.dirname(__FILE__) + '/../../spec_helper'
require 'puppet/parser/lexer'
+describe Puppet::Parser::Lexer do
+ describe "when reading strings" do
+ before { @lexer = Puppet::Parser::Lexer.new }
+ it "should increment the line count for every carriage return in the string" do
+ @lexer.line = 10
+ @lexer.string = "this\nis\natest'"
+ @lexer.slurpstring("'")
+
+ @lexer.line.should == 12
+ end
+
+ it "should not increment the line count for escapes in the string" do
+ @lexer.line = 10
+ @lexer.string = "this\\nis\\natest'"
+ @lexer.slurpstring("'")
+
+ @lexer.line.should == 10
+ end
+ end
+end
+
describe Puppet::Parser::Lexer::Token do
before do
@token = Puppet::Parser::Lexer::Token.new(%r{something}, :NAME)
@@ -136,7 +157,13 @@ describe Puppet::Parser::Lexer::TOKENS do
:BACKSLASH => '\\',
:FARROW => '=>',
:PARROW => '+>',
- :APPENDS => '+='
+ :APPENDS => '+=',
+ :PLUS => '+',
+ :MINUS => '-',
+ :DIV => '/',
+ :TIMES => '*',
+ :LSHIFT => '<<',
+ :RSHIFT => '>>',
}.each do |name, string|
it "should have a token named #{name.to_s}" do
Puppet::Parser::Lexer::TOKENS[name].should_not be_nil
@@ -213,10 +240,34 @@ describe Puppet::Parser::Lexer::TOKENS[:NAME] do
end
describe Puppet::Parser::Lexer::TOKENS[:NUMBER] do
- before { @token = Puppet::Parser::Lexer::TOKENS[:NUMBER] }
+ before do
+ @token = Puppet::Parser::Lexer::TOKENS[:NUMBER]
+# @regex = Regexp.new('^'+@token.regex.source+'$')
+ @regex = @token.regex
+ end
it "should match against numeric terms" do
- @token.regex.should =~ "2982383139"
+ @regex.should =~ "2982383139"
+ end
+
+ it "should match against float terms" do
+ @regex.should =~ "29823.235"
+ end
+
+ it "should match against hexadecimal terms" do
+ @regex.should =~ "0xBEEF0023"
+ end
+
+ it "should match against float with exponent terms" do
+ @regex.should =~ "10e23"
+ end
+
+ it "should match against float terms with negative exponents" do
+ @regex.should =~ "10e-23"
+ end
+
+ it "should match against float terms with fractional parts and exponent" do
+ @regex.should =~ "1.234e23"
end
it "should return the NAME token and the value" do
diff --git a/spec/unit/parser/parser.rb b/spec/unit/parser/parser.rb
index 94b19be40..c0d22a2cc 100755
--- a/spec/unit/parser/parser.rb
+++ b/spec/unit/parser/parser.rb
@@ -8,6 +8,7 @@ describe Puppet::Parser do
before :each do
@parser = Puppet::Parser::Parser.new :environment => "development"
+ @true_ast = AST::Boolean.new :value => true
end
describe "when parsing append operator" do
@@ -31,4 +32,114 @@ describe Puppet::Parser do
end
end
-end
+
+ 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) }
+ @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"
+ }
+ @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]=="<"
+ }
+ @parser.parse("if 1 < 2 { $var = 1 }")
+
+ end
+
+ end
+
+ 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"
+ }
+ @parser.parse("if (1 > 2) and (1 == 2) { $var = 1 }")
+ end
+
+ it "should raise an error on incorrect expression" do
+ lambda { @parser.parse("if (1 > 2 > ) or (1 == 2) { $var = 1 }") }.should raise_error
+ end
+
+ end
+
+ describe Puppet::Parser, "when parsing resource references" do
+
+ it "should not raise syntax errors" do
+ lambda { @parser.parse('exec { test: param => File["a"] }') }.should_not raise_error
+ end
+
+ it "should not raise syntax errors with multiple references" 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)
+ }
+ @parser.parse('exec { test: command => File["a","b"] }')
+ end
+ end
+
+ describe Puppet::Parser, "when parsing resource overrides" do
+
+ it "should not raise syntax errors" do
+ lambda { @parser.parse('Resource["title"] { param => value }') }.should_not raise_error
+ end
+
+ it "should not raise syntax errors with multiple overrides" 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)
+ }
+ @parser.parse('Resource["title1","title2"] { param => value }')
+ end
+
+ end
+
+ describe Puppet::Parser, "when parsing if statements" do
+
+ it "should not raise errors with empty if" do
+ lambda { @parser.parse("if true { }") }.should_not raise_error
+ end
+
+ it "should not raise errors with empty else" do
+ lambda { @parser.parse("if false { notice('if') } else { }") }.should_not raise_error
+ end
+
+ it "should not raise errors with empty if and else" do
+ lambda { @parser.parse("if false { } else { }") }.should_not raise_error
+ end
+
+ it "should create a nop node for empty branch" do
+ AST::Nop.expects(:new)
+ @parser.parse("if true { }")
+ end
+
+ it "should create a nop node for empty else branch" do
+ AST::Nop.expects(:new)
+ @parser.parse("if true { notice('test') } else { }")
+ end
+
+ end
+
+ end
diff --git a/spec/unit/parser/resource.rb b/spec/unit/parser/resource.rb
index 6b2021916..63cfbc2ed 100755
--- a/spec/unit/parser/resource.rb
+++ b/spec/unit/parser/resource.rb
@@ -176,6 +176,16 @@ describe Puppet::Parser::Resource do
@resource["noop"].should == "false"
end
+ it "should copy all metaparams that it finds" do
+ @scope.setvar("require", "container")
+ @scope.setvar("notify", "container")
+
+ @resource.class.publicize_methods(:add_metaparams) { @resource.add_metaparams }
+
+ @resource["require"].should == "container"
+ @resource["notify"].should == "container"
+ end
+
it "should stack relationship metaparams from its container if it already has them" do
@resource.set_parameter("require", "resource")
@scope.setvar("require", "container")
diff --git a/spec/unit/parser/scope.rb b/spec/unit/parser/scope.rb
index ec8ab6d7d..fa76c4ff2 100755
--- a/spec/unit/parser/scope.rb
+++ b/spec/unit/parser/scope.rb
@@ -34,4 +34,54 @@ describe Puppet::Parser::Scope do
end
end
+
+ describe Puppet::Parser::Scope, "when calling number?" do
+
+ it "should return nil if called with anything not a number" do
+ Puppet::Parser::Scope.number?([2]).should be_nil
+ end
+
+ it "should return a Fixnum for a Fixnum" do
+ Puppet::Parser::Scope.number?(2).should be_an_instance_of(Fixnum)
+ end
+
+ it "should return a Float for a Float" do
+ Puppet::Parser::Scope.number?(2.34).should be_an_instance_of(Float)
+ end
+
+ it "should return 234 for '234'" do
+ Puppet::Parser::Scope.number?("234").should == 234
+ end
+
+ it "should return nil for 'not a number'" do
+ Puppet::Parser::Scope.number?("not a number").should be_nil
+ end
+
+ it "should return 23.4 for '23.4'" do
+ Puppet::Parser::Scope.number?("23.4").should == 23.4
+ end
+
+ it "should return 23.4e13 for '23.4e13'" do
+ Puppet::Parser::Scope.number?("23.4e13").should == 23.4e13
+ end
+
+ it "should understand negative numbers" do
+ Puppet::Parser::Scope.number?("-234").should == -234
+ end
+
+ it "should know how to convert exponential float numbers ala '23e13'" do
+ Puppet::Parser::Scope.number?("23e13").should == 23e13
+ end
+
+ it "should understand hexadecimal numbers" do
+ Puppet::Parser::Scope.number?("0x234").should == 0x234
+ end
+
+ it "should understand octal numbers" do
+ Puppet::Parser::Scope.number?("0755").should == 0755
+ end
+
+
+ end
+
end
diff --git a/spec/unit/parser/templatewrapper.rb b/spec/unit/parser/templatewrapper.rb
index 2d4bd141b..20ea76921 100755
--- a/spec/unit/parser/templatewrapper.rb
+++ b/spec/unit/parser/templatewrapper.rb
@@ -55,6 +55,20 @@ describe Puppet::Parser::TemplateWrapper do
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.classes().should == ["class1", "class2"]
+ end
+
+ it "should allow you to retrieve the defined tags with tags" do
+ catalog = mock 'catalog', :tags => ["tag1", "tag2"]
+ @scope.expects(:catalog).returns( catalog )
+ tw = Puppet::Parser::TemplateWrapper.new(@scope, @file)
+ 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")
diff --git a/spec/unit/property/list.rb b/spec/unit/property/list.rb
new file mode 100644
index 000000000..9c832c0cd
--- /dev/null
+++ b/spec/unit/property/list.rb
@@ -0,0 +1,147 @@
+#!/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/list'
+
+list_class = Puppet::Property::List
+
+describe list_class do
+
+ it "should be a subclass of Property" do
+ list_class.superclass.must == Puppet::Property
+ end
+
+ describe "as an instance" do
+ before do
+ # Wow that's a messy interface to the resource.
+ list_class.initvars
+ @resource = stub 'resource', :[]= => nil, :property => nil
+ @property = list_class.new(:resource => @resource)
+ end
+
+ it "should have a , as default delimiter" do
+ @property.delimiter.should == ","
+ end
+
+ it "should have a :membership as default membership" do
+ @property.membership.should == :membership
+ end
+
+ it "should return the same value passed into should_to_s" do
+ @property.should_to_s("foo") == "foo"
+ end
+
+ it "should return the passed in array values joined with the delimiter from is_to_s" do
+ @property.is_to_s(["foo","bar"]).should == "foo,bar"
+ end
+
+ describe "when adding should to current" do
+ it "should add the arrays when current is an array" do
+ @property.add_should_with_current(["foo"], ["bar"]).should == ["foo", "bar"]
+ end
+
+ it "should return should if current is not a array" do
+ @property.add_should_with_current(["foo"], :absent).should == ["foo"]
+ end
+
+ it "should return only the uniq elements" do
+ @property.add_should_with_current(["foo", "bar"], ["foo", "baz"]).should == ["foo", "bar", "baz"]
+ end
+ end
+
+ describe "when calling inclusive?" do
+ it "should use the membership method to look up on the @resource" do
+ @property.expects(:membership).returns(:membership)
+ @resource.expects(:[]).with(:membership)
+ @property.inclusive?
+ end
+
+ it "should return true when @resource[membership] == inclusive" do
+ @property.stubs(:membership).returns(:membership)
+ @resource.stubs(:[]).with(:membership).returns(:inclusive)
+ @property.inclusive?.must == true
+ end
+
+ it "should return false when @resource[membership] != inclusive" do
+ @property.stubs(:membership).returns(:membership)
+ @resource.stubs(:[]).with(:membership).returns(:minimum)
+ @property.inclusive?.must == false
+ 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 sorted values of @should as a string if inclusive" do
+ @property.should = ["foo", "bar"]
+ @property.expects(:inclusive?).returns(true)
+ @property.should.must == "bar,foo"
+ end
+
+ it "should return the uniq sorted values of @should + retrieve as a string if !inclusive" do
+ @property.should = ["foo", "bar"]
+ @property.expects(:inclusive?).returns(false)
+ @property.expects(:retrieve).returns(["foo","baz"])
+ @property.should.must == "bar,baz,foo"
+ end
+ end
+
+ describe "when calling retrieve" do
+ before do
+ @provider = mock("provider")
+ @property.stubs(:provider).returns(@provider)
+ end
+
+ it "should send 'name' to the provider" do
+ @provider.expects(:send).with(:group)
+ @property.expects(:name).returns(:group)
+ @property.retrieve
+ end
+
+ it "should return an array with the provider returned info" do
+ @provider.stubs(:send).with(:group).returns("foo,bar,baz")
+ @property.stubs(:name).returns(:group)
+ @property.retrieve == ["foo", "bar", "baz"]
+ end
+
+ it "should return :absent when the provider returns :absent" do
+ @provider.stubs(:send).with(:group).returns(:absent)
+ @property.stubs(:name).returns(:group)
+ @property.retrieve == :absent
+ end
+ end
+
+ describe "when calling insync?" do
+ it "should return true unless @should is defined and not nil" do
+ @property.insync?("foo") == true
+ end
+
+ it "should return true unless the passed in values is not nil" do
+ @property.should = "foo"
+ @property.insync?(nil) == true
+ end
+
+ it "should call prepare_is_for_comparison with value passed in and should" do
+ @property.should = "foo"
+ @property.expects(:prepare_is_for_comparison).with("bar")
+ @property.expects(:should)
+ @property.insync?("bar")
+ end
+
+ it "should return true if prepared value == should value" do
+ @property.should = "bar,foo"
+ @property.expects(:inclusive?).returns(true)
+ @property.insync?(["bar","foo"]).must == true
+ end
+
+ it "should return false if prepared value != should value" do
+ @property.should = "bar,baz,foo"
+ @property.expects(:inclusive?).returns(true)
+ @property.insync?(["bar","foo"]).must == false
+ end
+ end
+ end
+end
diff --git a/spec/unit/provider/confine/variable.rb b/spec/unit/provider/confine/variable.rb
index 093301bdc..38b3dad1c 100755
--- a/spec/unit/provider/confine/variable.rb
+++ b/spec/unit/provider/confine/variable.rb
@@ -85,16 +85,26 @@ describe Puppet::Provider::Confine::Variable do
describe "when summarizing multiple instances" do
it "should return a hash of failing variables and their values" do
- c1 = stub '1', :valid? => false, :values => %w{one}, :fact => "uno"
- c2 = stub '2', :valid? => true, :values => %w{two}, :fact => "dos"
- c3 = stub '3', :valid? => false, :values => %w{three}, :fact => "tres"
+ c1 = Puppet::Provider::Confine::Variable.new("one")
+ c1.name = "uno"
+ c1.expects(:valid?).returns false
+ c2 = Puppet::Provider::Confine::Variable.new("two")
+ c2.name = "dos"
+ c2.expects(:valid?).returns true
+ c3 = Puppet::Provider::Confine::Variable.new("three")
+ c3.name = "tres"
+ c3.expects(:valid?).returns false
Puppet::Provider::Confine::Variable.summarize([c1, c2, c3]).should == {"uno" => %w{one}, "tres" => %w{three}}
end
it "should combine the values of multiple confines with the same fact" do
- c1 = stub '1', :valid? => false, :values => %w{one}, :fact => "uno"
- c2 = stub '2', :valid? => false, :values => %w{two}, :fact => "uno"
+ c1 = Puppet::Provider::Confine::Variable.new("one")
+ c1.name = "uno"
+ c1.expects(:valid?).returns false
+ c2 = Puppet::Provider::Confine::Variable.new("two")
+ c2.name = "uno"
+ c2.expects(:valid?).returns false
Puppet::Provider::Confine::Variable.summarize([c1, c2]).should == {"uno" => %w{one two}}
end
diff --git a/spec/unit/provider/package/apt.rb b/spec/unit/provider/package/apt.rb
new file mode 100755
index 000000000..0ec1cd9ed
--- /dev/null
+++ b/spec/unit/provider/package/apt.rb
@@ -0,0 +1,138 @@
+#!/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") }
+
+provider = Puppet::Type.type(:package).provider(:apt)
+
+describe provider do
+ before do
+ @resource = stub 'resource', :[] => "asdf"
+ @provider = provider.new(@resource)
+
+ @fakeresult = "install ok installed asdf 1.0\n"
+ end
+
+ it "should be versionable" do
+ provider.should be_versionable
+ end
+
+ it "should use :install to update" do
+ @provider.expects(:install)
+ @provider.update
+ end
+
+ it "should use 'apt-get remove' to uninstall" do
+ @provider.expects(:aptget).with("-y", "-q", :remove, "asdf")
+
+ @provider.uninstall
+ end
+
+ it "should use 'apt-get purge' and 'dpkg purge' to purge" do
+ @provider.expects(:aptget).with("-y", "-q", :remove, "--purge", "asdf")
+ @provider.expects(:dpkg).with("--purge", "asdf")
+
+ @provider.purge
+ end
+
+ it "should use 'apt-cache policy' to determine the latest version of a package" do
+ @provider.expects(:aptcache).with(:policy, "asdf").returns "asdf:
+Installed: 1:1.0
+Candidate: 1:1.1
+Version table:
+ 1:1.0
+ 650 http://ftp.osuosl.org testing/main Packages
+*** 1:1.1
+ 100 /var/lib/dpkg/status"
+
+ @provider.latest.should == "1:1.1"
+ end
+
+ it "should print and error and return nil if no policy is found" do
+ @provider.expects(:aptcache).with(:policy, "asdf").returns "asdf:"
+
+ @provider.expects(:err)
+ @provider.latest.should be_nil
+ end
+
+ it "should be able to preseed" do
+ @provider.should respond_to(:run_preseed)
+ end
+
+ it "should preseed with the provided responsefile when preseeding is called for" do
+ @resource.expects(:[]).with(:responsefile).returns "/my/file"
+ FileTest.expects(:exist?).with("/my/file").returns true
+
+ @provider.expects(:info)
+ @provider.expects(:preseed).with("/my/file")
+
+ @provider.run_preseed
+ end
+
+ it "should not preseed if no responsefile is provided" do
+ @resource.expects(:[]).with(:responsefile).returns nil
+
+ @provider.expects(:info)
+ @provider.expects(:preseed).never
+
+ @provider.run_preseed
+ end
+
+ it "should fail if a cdrom is listed in the sources list and :allowcdrom is not specified"
+
+ describe "when installing" do
+ it "should preseed if a responsefile is provided" do
+ @resource.expects(:[]).with(:responsefile).returns "/my/file"
+ @provider.expects(:run_preseed)
+
+ @provider.stubs(:aptget)
+ @provider.install
+ end
+
+ it "should check for a cdrom" do
+ @provider.expects(:checkforcdrom)
+
+ @provider.stubs(:aptget)
+ @provider.install
+ end
+
+ it "should use 'apt-get install' with the package name if no version is asked for" do
+ @resource.expects(:[]).with(:ensure).returns :installed
+ @provider.expects(:aptget).with { |*command| command[-1] == "asdf" and command[-2] == :install }
+
+ @provider.install
+ end
+
+ it "should specify the package version if one is asked for" do
+ @resource.expects(:[]).with(:ensure).returns "1.0"
+ @provider.expects(:aptget).with { |*command| command[-1] == "asdf=1.0" }
+
+ @provider.install
+ end
+
+ it "should do a quiet install" do
+ @provider.expects(:aptget).with { |*command| command.include?("-q") }
+
+ @provider.install
+ end
+
+ it "should default to 'yes' for all questions" do
+ @provider.expects(:aptget).with { |*command| command.include?("-y") }
+
+ @provider.install
+ end
+
+ it "should keep config files if asked" do
+ @resource.expects(:[]).with(:configfiles).returns :keep
+ @provider.expects(:aptget).with { |*command| command.include?("DPkg::Options::=--force-confold") }
+
+ @provider.install
+ end
+
+ it "should replace config files if asked" do
+ @resource.expects(:[]).with(:configfiles).returns :replace
+ @provider.expects(:aptget).with { |*command| command.include?("DPkg::Options::=--force-confnew") }
+
+ @provider.install
+ end
+ end
+end
diff --git a/spec/unit/provider/package/dpkg.rb b/spec/unit/provider/package/dpkg.rb
new file mode 100755
index 000000000..08aaca875
--- /dev/null
+++ b/spec/unit/provider/package/dpkg.rb
@@ -0,0 +1,163 @@
+#!/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") }
+
+provider = Puppet::Type.type(:package).provider(:dpkg)
+
+describe provider do
+ before do
+ @resource = stub 'resource', :[] => "asdf"
+ @provider = provider.new(@resource)
+
+ @fakeresult = "install ok installed asdf 1.0\n"
+ end
+
+ it "should have documentation" do
+ provider.doc.should be_instance_of(String)
+ end
+
+ describe "when listing all instances" do
+ before do
+ provider.stubs(:command).with(:dpkgquery).returns "myquery"
+ end
+
+ it "should use dpkg-query" do
+ provider.expects(:command).with(:dpkgquery).returns "myquery"
+ provider.expects(:execpipe).with("myquery -W --showformat '${Status} ${Package} ${Version}\\n'").returns @fakeresult
+
+ provider.instances
+ end
+
+ it "should create and return an instance with each parsed line from dpkg-query" do
+ pipe = mock 'pipe'
+ pipe.expects(:each).yields @fakeresult
+ provider.expects(:execpipe).yields pipe
+
+ asdf = mock 'pkg1'
+ provider.expects(:new).with(:ensure => "1.0", :error => "ok", :desired => "install", :name => "asdf", :status => "installed", :provider => :dpkg).returns asdf
+
+ provider.instances.should == [asdf]
+ end
+
+ it "should warn on and ignore any lines it does not understand" do
+ pipe = mock 'pipe'
+ pipe.expects(:each).yields "foobar"
+ provider.expects(:execpipe).yields pipe
+
+ Puppet.expects(:warning)
+ provider.expects(:new).never
+
+ provider.instances.should == []
+ end
+ end
+
+ describe "when querying the current state" do
+ it "should use dpkg-query" do
+ @provider.expects(:dpkgquery).with("-W", "--showformat",'${Status} ${Package} ${Version}\\n', "asdf").returns @fakeresult
+
+ @provider.query
+ end
+
+ it "should consider the package purged if dpkg-query fails" do
+ @provider.expects(:dpkgquery).raises Puppet::ExecutionFailure.new("eh")
+
+ @provider.query[:ensure].should == :purged
+ end
+
+ it "should return a hash of the found status with the desired state, error state, status, name, and 'ensure'" do
+ @provider.expects(:dpkgquery).returns @fakeresult
+
+ @provider.query.should == {:ensure => "1.0", :error => "ok", :desired => "install", :name => "asdf", :status => "installed", :provider => :dpkg}
+ end
+
+ it "should consider the package absent if the dpkg-query result cannot be interpreted" do
+ @provider.expects(:dpkgquery).returns "somebaddata"
+
+ @provider.query[:ensure].should == :absent
+ end
+
+ it "should fail if an error is discovered" do
+ @provider.expects(:dpkgquery).returns @fakeresult.sub("ok", "error")
+
+ lambda { @provider.query }.should raise_error(Puppet::Error)
+ end
+
+ it "should consider the package purged if it is marked 'not-installed'" do
+ @provider.expects(:dpkgquery).returns @fakeresult.sub("installed", "not-installed")
+
+ @provider.query[:ensure].should == :purged
+ end
+
+ it "should consider the package absent if its status is neither 'installed' nor 'not-installed'" do
+ @provider.expects(:dpkgquery).returns @fakeresult.sub("installed", "foo")
+
+ @provider.query[:ensure].should == :absent
+ end
+ end
+
+ it "should be able to install" do
+ @provider.should respond_to(:install)
+ end
+
+ describe "when installing" do
+ before do
+ @resource.stubs(:[]).with(:source).returns "mypkg"
+ end
+
+ it "should fail to install if no source is specified in the resource" do
+ @resource.expects(:[]).with(:source).returns nil
+
+ lambda { @provider.install }.should raise_error(ArgumentError)
+ end
+
+ it "should use 'dpkg -i' to install the package" do
+ @resource.expects(:[]).with(:source).returns "mypackagefile"
+ @provider.expects(:dpkg).with { |*command| command[-1] == "mypackagefile" and command[-2] == "-i" }
+
+ @provider.install
+ end
+
+ it "should keep old config files if told to do so" do
+ @resource.expects(:[]).with(:configfiles).returns :keep
+ @provider.expects(:dpkg).with { |*command| command[0] == "--force-confold" }
+
+ @provider.install
+ end
+
+ it "should replace old config files if told to do so" do
+ @resource.expects(:[]).with(:configfiles).returns :replace
+ @provider.expects(:dpkg).with { |*command| command[0] == "--force-confnew" }
+
+ @provider.install
+ end
+ end
+
+ it "should use :install to update" do
+ @provider.expects(:install)
+ @provider.update
+ end
+
+ describe "when determining latest available version" do
+ it "should return the version found by dpkg-deb" do
+ @resource.expects(:[]).with(:source).returns "myfile"
+ @provider.expects(:dpkg_deb).with { |*command| command[-1] == "myfile" }.returns "asdf\t1.0"
+ @provider.latest.should == "1.0"
+ end
+
+ it "should warn if the package file contains a different package" do
+ @provider.expects(:dpkg_deb).returns("foo\tversion")
+ @provider.expects(:warning)
+ @provider.latest
+ end
+ end
+
+ it "should use 'dpkg -r' to uninstall" do
+ @provider.expects(:dpkg).with("-r", "asdf")
+ @provider.uninstall
+ end
+
+ it "should use 'dpkg --purge' to purge" do
+ @provider.expects(:dpkg).with("--purge", "asdf")
+ @provider.purge
+ end
+end
diff --git a/spec/unit/provider/selboolean.rb b/spec/unit/provider/selboolean.rb
new file mode 100755
index 000000000..4006df151
--- /dev/null
+++ b/spec/unit/provider/selboolean.rb
@@ -0,0 +1,37 @@
+#!/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") }
+
+provider_class = Puppet::Type.type(:selboolean).provider(:getsetsebool)
+
+describe provider_class do
+ before :each do
+ @resource = stub("resource", :name => "foo")
+ @resource.stubs(:[]).returns "foo"
+ @provider = provider_class.new(@resource)
+ end
+
+ it "should return :on when getsebool returns on" do
+ @provider.expects(:getsebool).with("foo").returns "foo --> on\n"
+ @provider.value.should == :on
+ end
+
+ it "should return :off when getsebool returns on" do
+ @provider.expects(:getsebool).with("foo").returns "foo --> off\n"
+ @provider.value.should == :off
+ end
+
+ it "should call execpipe when updating boolean setting" do
+ @provider.expects(:command).with(:setsebool).returns "/usr/sbin/setsebool"
+ @provider.expects(:execpipe).with("/usr/sbin/setsebool foo off")
+ @provider.value = :off
+ end
+
+ it "should call execpipe with -P when updating persistent boolean setting" do
+ @resource.stubs(:[]).with(:persistent).returns :true
+ @provider.expects(:command).with(:setsebool).returns "/usr/sbin/setsebool"
+ @provider.expects(:execpipe).with("/usr/sbin/setsebool -P foo off")
+ @provider.value = :off
+ end
+
+end
diff --git a/spec/unit/provider/selmodule-example.pp b/spec/unit/provider/selmodule-example.pp
new file mode 100644
index 000000000..28166ca40
--- /dev/null
+++ b/spec/unit/provider/selmodule-example.pp
Binary files differ
diff --git a/spec/unit/provider/selmodule.rb b/spec/unit/provider/selmodule.rb
new file mode 100755
index 000000000..e92441d23
--- /dev/null
+++ b/spec/unit/provider/selmodule.rb
@@ -0,0 +1,66 @@
+#!/usr/bin/env ruby
+
+# Note: This unit test depends on having a sample SELinux policy file
+# in the same directory as this test called selmodule-example.pp
+# with version 1.5.0. The provided selmodule-example.pp is the first
+# 256 bytes taken from /usr/share/selinux/targeted/nagios.pp on Fedora 9
+
+Dir.chdir(File.dirname(__FILE__)) { (s = lambda { |f| File.exist?(f) ? require(f) : Dir.chdir("..") { s.call(f) } }).call("spec/spec_helper.rb") }
+
+provider_class = Puppet::Type.type(:selmodule).provider(:semodule)
+
+describe provider_class do
+ before :each do
+ @resource = stub("resource", :name => "foo")
+ @resource.stubs(:[]).returns "foo"
+ @provider = provider_class.new(@resource)
+ end
+
+ describe "exists? method" do
+ it "should find a module if it is already loaded" do
+ @provider.expects(:command).with(:semodule).returns "/usr/sbin/semodule"
+ @provider.expects(:execpipe).with("/usr/sbin/semodule --list").yields ["bar\t1.2.3\n", "foo\t4.4.4\n", "bang\t1.0.0\n"]
+ @provider.exists?.should == :true
+ end
+
+ it "should return nil if not loaded" do
+ @provider.expects(:command).with(:semodule).returns "/usr/sbin/semodule"
+ @provider.expects(:execpipe).with("/usr/sbin/semodule --list").yields ["bar\t1.2.3\n", "bang\t1.0.0\n"]
+ @provider.exists?.should be_nil
+ end
+
+ it "should return nil if no modules are loaded" do
+ @provider.expects(:command).with(:semodule).returns "/usr/sbin/semodule"
+ @provider.expects(:execpipe).with("/usr/sbin/semodule --list").yields []
+ @provider.exists?.should be_nil
+ end
+ end
+
+ describe "selmodversion_file" do
+ it "should return 1.5.0 for the example policy file" do
+ @provider.expects(:selmod_name_to_filename).returns "#{File.dirname(__FILE__)}/selmodule-example.pp"
+ @provider.selmodversion_file.should == "1.5.0"
+ end
+ end
+
+ describe "syncversion" do
+ it "should return :true if loaded and file modules are in sync" do
+ @provider.expects(:selmodversion_loaded).returns "1.5.0"
+ @provider.expects(:selmodversion_file).returns "1.5.0"
+ @provider.syncversion.should == :true
+ end
+
+ it "should return :false if loaded and file modules are not in sync" do
+ @provider.expects(:selmodversion_loaded).returns "1.4.0"
+ @provider.expects(:selmodversion_file).returns "1.5.0"
+ @provider.syncversion.should == :false
+ end
+
+ it "should return before checking file version if no loaded policy" do
+ @provider.expects(:selmodversion_loaded).returns nil
+ @provider.syncversion.should == :false
+ end
+
+ end
+
+end
diff --git a/spec/unit/provider/user/user_role_add.rb b/spec/unit/provider/user/user_role_add.rb
new file mode 100644
index 000000000..e9bd9a68f
--- /dev/null
+++ b/spec/unit/provider/user/user_role_add.rb
@@ -0,0 +1,131 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+provider_class = Puppet::Type.type(:user).provider(:user_role_add)
+
+describe provider_class do
+ before do
+ @resource = stub("resource", :name => "myuser", :managehome? => nil)
+ @resource.stubs(:should).returns "fakeval"
+ @resource.stubs(:[]).returns "fakeval"
+ @resource.stubs(:allowdupe?).returns false
+ @provider = provider_class.new(@resource)
+ end
+
+ describe "when calling command" do
+ before do
+ klass = stub("provider")
+ klass.stubs(:command).with(:foo).returns("userfoo")
+ klass.stubs(:command).with(:role_foo).returns("rolefoo")
+ @provider.stubs(:class).returns(klass)
+ end
+
+ it "should use the command if not a role and ensure!=role" do
+ @provider.stubs(:is_role?).returns(false)
+ @provider.stubs(:exists?).returns(false)
+ @resource.stubs(:[]).with(:ensure).returns(:present)
+ @provider.command(:foo).should == "userfoo"
+ end
+
+ it "should use the role command when a role" do
+ @provider.stubs(:is_role?).returns(true)
+ @provider.command(:foo).should == "rolefoo"
+ end
+
+ it "should use the role command when !exists and ensure=role" do
+ @provider.stubs(:is_role?).returns(false)
+ @provider.stubs(:exists?).returns(false)
+ @resource.stubs(:[]).with(:ensure).returns(:role)
+ @provider.command(:foo).should == "rolefoo"
+ end
+ end
+
+ describe "when calling transition" do
+ it "should return foomod setting the type to bar" do
+ @provider.expects(:command).with(:modify).returns("foomod")
+ @provider.transition("bar").should == ["foomod", "-K", "type=bar", "fakeval"]
+ end
+ end
+
+ describe "when calling create" do
+ 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")
+ @provider.expects(:run)
+ @provider.create
+ end
+
+ it "should use transition(normal) when the user is a role" do
+ @provider.stubs(:is_role?).returns(true)
+ @provider.expects(:transition).with("normal")
+ @provider.expects(:run)
+ @provider.create
+ end
+ end
+
+ describe "when calling destroy" do
+ it "should use the delete command if the user exists and is not a role" do
+ @provider.stubs(:exists?).returns(true)
+ @provider.stubs(:is_role?).returns(false)
+ @provider.expects(:deletecmd)
+ @provider.expects(:run)
+ @provider.destroy
+ end
+
+ it "should use the delete command if the user is a role" do
+ @provider.stubs(:exists?).returns(true)
+ @provider.stubs(:is_role?).returns(true)
+ @provider.expects(:deletecmd)
+ @provider.expects(:run)
+ @provider.destroy
+ end
+ end
+
+ describe "when calling create_role" do
+ it "should use the transition(role) if the user exists" do
+ @provider.stubs(:exists?).returns(true)
+ @provider.stubs(:is_role?).returns(false)
+ @provider.expects(:transition).with("role")
+ @provider.expects(:run)
+ @provider.create_role
+ end
+
+ it "should use the add command when role doesn't exists" do
+ @provider.stubs(:exists?).returns(false)
+ @provider.expects(:addcmd)
+ @provider.expects(:run)
+ @provider.create_role
+ end
+ end
+
+ describe "when allow duplicate is enabled" do
+ before do
+ @resource.expects(:allowdupe?).returns true
+ @provider.stubs(:is_role?).returns(false)
+ @provider.expects(:execute).with { |args| args.include?("-o") }
+ end
+
+ it "should add -o when the user is being created" do
+ @provider.create
+ end
+
+ it "should add -o when the uid is being modified" do
+ @provider.uid = 150
+ end
+ end
+
+ describe "when getting roles" do
+ it "should get the user_attributes" do
+ @provider.expects(:user_attributes)
+ @provider.roles
+ end
+
+ it "should get the :roles attribute" do
+ attributes = mock("attributes")
+ attributes.expects(:[]).with(:roles)
+ @provider.stubs(:user_attributes).returns(attributes)
+ @provider.roles
+ end
+ end
+end
diff --git a/spec/unit/type.rb b/spec/unit/type.rb
index 9815ed32d..4c0cb5077 100755
--- a/spec/unit/type.rb
+++ b/spec/unit/type.rb
@@ -2,28 +2,61 @@
require File.dirname(__FILE__) + '/../spec_helper'
-describe Puppet::Type, " when in a configuration" do
- before do
- @catalog = Puppet::Node::Catalog.new
- @container = Puppet::Type.type(:component).create(:name => "container")
- @one = Puppet::Type.type(:file).create(:path => "/file/one")
- @two = Puppet::Type.type(:file).create(:path => "/file/two")
- @catalog.add_resource @container
- @catalog.add_resource @one
- @catalog.add_resource @two
- @catalog.add_edge @container, @one
- @catalog.add_edge @container, @two
- end
+describe Puppet::Type do
+ describe "when retrieving current properties" do
+ # Use 'mount' as an example, because it doesn't override 'retrieve'
+ before do
+ @resource = Puppet::Type.type(:mount).create(:name => "foo", :fstype => "bar", :pass => 1, :ensure => :present)
+ @properties = {}
+ end
- it "should have no parent if there is no in edge" do
- @container.parent.should be_nil
- end
+ it "should return a hash containing values for all set properties" do
+ values = @resource.retrieve
+ [@resource.property(:fstype), @resource.property(:pass)].each { |property| values.should be_include(property) }
+ end
+
+ it "should not call retrieve on non-ensure properties if the resource is absent" do
+ @resource.property(:ensure).expects(:retrieve).returns :absent
+ @resource.property(:fstype).expects(:retrieve).never
+ @resource.retrieve[@resource.property(:fstype)]
+ end
+
+ it "should set all values to :absent if the resource is absent" do
+ @resource.property(:ensure).expects(:retrieve).returns :absent
+ @resource.retrieve[@resource.property(:fstype)].should == :absent
+ end
- it "should set its parent to its in edge" do
- @one.parent.ref.should == @container.ref
+ it "should include the result of retrieving each property's current value if the resource is present" do
+ @resource.property(:ensure).expects(:retrieve).returns :present
+ @resource.property(:fstype).expects(:retrieve).returns 15
+ @resource.retrieve[@resource.property(:fstype)].should == 15
+ end
end
- after do
- @catalog.clear(true)
+
+ describe "when in a catalog" do
+ before do
+ @catalog = Puppet::Node::Catalog.new
+ @container = Puppet::Type.type(:component).create(:name => "container")
+ @one = Puppet::Type.type(:file).create(:path => "/file/one")
+ @two = Puppet::Type.type(:file).create(:path => "/file/two")
+ @catalog.add_resource @container
+ @catalog.add_resource @one
+ @catalog.add_resource @two
+ @catalog.add_edge @container, @one
+ @catalog.add_edge @container, @two
+ end
+
+ it "should have no parent if there is no in edge" do
+ @container.parent.should be_nil
+ end
+
+ it "should set its parent to its in edge" do
+ @one.parent.ref.should == @container.ref
+ end
+
+ after do
+ @catalog.clear(true)
+ end
end
end
diff --git a/spec/unit/type/file/group.rb b/spec/unit/type/file/group.rb
new file mode 100755
index 000000000..856b05b0d
--- /dev/null
+++ b/spec/unit/type/file/group.rb
@@ -0,0 +1,118 @@
+#!/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(:group)
+
+describe property do
+ before do
+ @resource = stub 'resource', :line => "foo", :file => "bar"
+ @resource.stubs(:[]).returns "foo"
+ @resource.stubs(:[]).with(:path).returns "/my/file"
+ @group = property.new :resource => @resource
+ end
+
+ it "should have a method for testing whether a group is valid" do
+ @group.must respond_to(:validgroup?)
+ end
+
+ it "should return the found gid if a group is valid" do
+ @group.expects(:gid).with("foo").returns 500
+ @group.validgroup?("foo").should == 500
+ end
+
+ it "should return false if a group is not valid" do
+ @group.expects(:gid).with("foo").returns nil
+ @group.validgroup?("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
+
+ @group.retrieve.should == :absent
+ end
+
+ it "should get the gid from the stat instance from the file" do
+ stat = stub 'stat', :ftype => "foo"
+ @resource.expects(:stat).returns stat
+ stat.expects(:gid).returns 500
+
+ @group.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(:gid).returns 1000
+
+ @group.expects(:warning)
+ @group.retrieve.should == :silly
+ end
+ end
+
+ describe "when determining if the file is in sync" do
+ it "should directly compare the group values if the desired group is an integer" do
+ @group.should = [10]
+ @group.must be_insync(10)
+ end
+
+ it "should treat numeric strings as integers" do
+ @group.should = ["10"]
+ @group.must be_insync(10)
+ end
+
+ it "should convert the group name to an integer if the desired group is a string" do
+ @group.expects(:gid).with("foo").returns 10
+ @group.should = %w{foo}
+
+ @group.must be_insync(10)
+ end
+
+ it "should fail if it cannot convert a group name to an integer" do
+ @group.expects(:gid).with("foo").returns nil
+ @group.should = %w{foo}
+
+ lambda { @group.insync?(10) }.should raise_error(Puppet::Error)
+ end
+
+ it "should return false if the groups are not equal" do
+ @group.should = [10]
+ @group.should_not be_insync(20)
+ end
+ end
+
+ describe "when changing the group" do
+ before do
+ @group.should = %w{one}
+ @group.stubs(:gid).returns 500
+ end
+
+ it "should chown the file if :links is set to :follow" do
+ @resource.expects(:[]).with(:links).returns :follow
+ File.expects(:chown)
+
+ @group.sync
+ end
+
+ it "should lchown the file if :links is set to :manage" do
+ @resource.expects(:[]).with(:links).returns :manage
+ File.expects(:lchown)
+
+ @group.sync
+ end
+
+ it "should use the first valid group in its 'should' list" do
+ @group.should = %w{one two three}
+ @group.expects(:validgroup?).with("one").returns nil
+ @group.expects(:validgroup?).with("two").returns 500
+ @group.expects(:validgroup?).with("three").never
+
+ File.expects(:chown).with(nil, 500, "/my/file")
+
+ @group.sync
+ end
+ end
+end
diff --git a/spec/unit/type/file/selinux.rb b/spec/unit/type/file/selinux.rb
new file mode 100644
index 000000000..cee47c342
--- /dev/null
+++ b/spec/unit/type/file/selinux.rb
@@ -0,0 +1,78 @@
+#!/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") }
+
+
+[:seluser, :selrole, :seltype, :selrange].each do |param|
+property = Puppet::Type.type(:file).attrclass(param)
+ describe property do
+ before do
+ @resource = mock 'resource'
+ @resource.stubs(:[]).with(:path).returns "/my/file"
+ @sel = property.new :resource => @resource
+ end
+
+ it "retrieve on #{param} should return :absent if the file isn't statable" do
+ @resource.expects(:stat).returns nil
+ @sel.retrieve.should == :absent
+ end
+
+ it "should retrieve nil for #{param} if there is no SELinux support" do
+ stat = stub 'stat', :ftype => "foo"
+ @resource.expects(:stat).returns stat
+ @sel.expects(:get_selinux_current_context).with("/my/file").returns nil
+ @sel.retrieve.should be_nil
+ end
+
+ it "should retrieve #{param} if a SELinux context is found with a range" do
+ stat = stub 'stat', :ftype => "foo"
+ @resource.expects(:stat).returns stat
+ @sel.expects(:get_selinux_current_context).with("/my/file").returns "user_u:role_r:type_t:s0"
+ expectedresult = case param
+ when :seluser then "user_u"
+ when :selrole then "role_r"
+ when :seltype then "type_t"
+ when :selrange then "s0"
+ end
+ @sel.retrieve.should == expectedresult
+ end
+
+ it "should retrieve #{param} if a SELinux context is found without a range" do
+ stat = stub 'stat', :ftype => "foo"
+ @resource.expects(:stat).returns stat
+ @sel.expects(:get_selinux_current_context).with("/my/file").returns "user_u:role_r:type_t"
+ expectedresult = case param
+ when :seluser then "user_u"
+ when :selrole then "role_r"
+ when :seltype then "type_t"
+ when :selrange then nil
+ end
+ @sel.retrieve.should == expectedresult
+ end
+
+ it "should handle no default gracefully" do
+ @sel.expects(:get_selinux_default_context).with("/my/file").returns nil
+ @sel.default.must be_nil
+ end
+
+ it "should be able to detect matchpathcon defaults" do
+ @sel.expects(:get_selinux_default_context).with("/my/file").returns "user_u:role_r:type_t:s0"
+ expectedresult = case param
+ when :seluser then "user_u"
+ when :selrole then "role_r"
+ when :seltype then "type_t"
+ when :selrange then "s0"
+ end
+ @sel.default.must == expectedresult
+ end
+
+ 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
+ end
+ end
+end
+
diff --git a/spec/unit/type/selboolean.rb b/spec/unit/type/selboolean.rb
new file mode 100755
index 000000000..6efec49ca
--- /dev/null
+++ b/spec/unit/type/selboolean.rb
@@ -0,0 +1,45 @@
+#!/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") }
+
+describe Puppet::Type.type(:selboolean), "when validating attributes" do
+ [:name, :persistent].each do |param|
+ it "should have a #{param} parameter" do
+ Puppet::Type.type(:selboolean).attrtype(param).should == :param
+ end
+ end
+
+ it "should have a value property" do
+ Puppet::Type.type(:selboolean).attrtype(:value).should == :property
+ end
+end
+
+describe Puppet::Type.type(:selboolean), "when validating values" do
+ before do
+ @class = Puppet::Type.type(:selboolean)
+
+ @provider_class = stub 'provider_class', :name => "fake", :suitable? => true, :supports_parameter? => true
+ @class.stubs(:defaultprovider).returns(@provider_class)
+ @class.stubs(:provider).returns(@provider_class)
+
+ @provider = stub 'provider', :class => @provider_class, :clear => nil
+ @provider_class.stubs(:new).returns(@provider)
+ end
+
+ it "should support :on as a value to :value" do
+ Puppet::Type.type(:selboolean).create(:name => "yay", :value => :on)
+ end
+
+ it "should support :off as a value to :value" do
+ Puppet::Type.type(:selboolean).create(:name => "yay", :value => :off)
+ end
+
+ it "should support :true as a value to :persistent" do
+ Puppet::Type.type(:selboolean).create(:name => "yay", :value => :on, :persistent => :true)
+ end
+
+ it "should support :false as a value to :persistent" do
+ Puppet::Type.type(:selboolean).create(:name => "yay", :value => :on, :persistent => :false)
+ end
+end
+
diff --git a/spec/unit/type/selmodule.rb b/spec/unit/type/selmodule.rb
new file mode 100755
index 000000000..f14bea9d3
--- /dev/null
+++ b/spec/unit/type/selmodule.rb
@@ -0,0 +1,18 @@
+#!/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") }
+
+describe Puppet::Type.type(:selmodule), "when validating attributes" do
+ [:name, :selmoduledir, :selmodulepath].each do |param|
+ it "should have a #{param} parameter" do
+ Puppet::Type.type(:selmodule).attrtype(param).should == :param
+ end
+ end
+
+ [:ensure, :syncversion].each do |param|
+ it "should have a #{param} property" do
+ Puppet::Type.type(:selmodule).attrtype(param).should == :property
+ end
+ end
+end
+
diff --git a/spec/unit/type/user.rb b/spec/unit/type/user.rb
index d16d752f9..1271753d4 100755
--- a/spec/unit/type/user.rb
+++ b/spec/unit/type/user.rb
@@ -2,55 +2,184 @@
require File.dirname(__FILE__) + '/../../spec_helper'
-module UserTestFunctions
- def mkuser(name)
- user = nil;
- lambda {
- user = Puppet::Type.type(:user).create(
- :name => name,
- :comment => "Puppet Testing User",
- :gid => Puppet::Util::SUIDManager.gid,
- :shell => "/bin/sh",
- :home => "/home/%s" % name
- ) }.should_not raise_error
- user.should_not be_nil
- user
- end
-
- def test_provider_class(klass)
- klass.should_not be_nil
- klass.should be_an_instance_of(Class)
- superclasses = []
- while klass = klass.superclass
- superclasses << klass
- end
- superclasses.should include(Puppet::Provider)
- end
-end
-
-describe Puppet::Type.type(:user) do
+user = Puppet::Type.type(:user)
- include UserTestFunctions
+describe user do
+ before do
+ @provider = stub 'provider'
+ @resource = stub 'resource', :resource => nil, :provider => @provider, :line => nil, :file => nil
+ end
it "should have a default provider inheriting from Puppet::Provider" do
- test_provider_class Puppet::Type.type(:user).defaultprovider
+ user.defaultprovider.ancestors.should be_include(Puppet::Provider)
end
it "should be able to create a instance" do
- mkuser "123testuser1"
+ user.create(:name => "foo").should_not be_nil
end
-end
-describe Puppet::Type.type(:user), "instances" do
+ it "should have an allows_duplicates feature" do
+ user.provider_feature(:allows_duplicates).should_not be_nil
+ end
- include UserTestFunctions
+ it "should have an manages_homedir feature" do
+ user.provider_feature(:manages_homedir).should_not be_nil
+ end
- it "should have a valid provider" do
- user = mkuser "123testuser2"
- user.provider.should_not be_nil
- test_provider_class user.provider.class
+ it "should have an manages_passwords feature" do
+ user.provider_feature(:manages_passwords).should_not be_nil
end
-end
+ describe "instances" do
+ it "should have a valid provider" do
+ user.create(:name => "foo").provider.class.ancestors.should be_include(Puppet::Provider)
+ end
+ end
+
+ [:ensure, :uid, :gid, :home, :comment, :shell, :password, :groups].each do |property|
+ it "should have a %s property" % property do
+ user.attrclass(property).ancestors.should be_include(Puppet::Property)
+ end
+
+ it "should have documentation for its %s property" % property do
+ user.attrclass(property).doc.should be_instance_of(String)
+ end
+ end
+
+ describe "when retrieving all current values" do
+ before do
+ @user = user.create(:name => "foo", :uid => 10, :gid => 10)
+ @properties = {}
+ end
+ it "should return a hash containing values for all set properties" do
+ values = @user.retrieve
+ [@user.property(:uid), @user.property(:gid)].each { |property| values.should be_include(property) }
+ end
+
+ it "should set all values to :absent if the user is absent" do
+ @user.property(:ensure).expects(:retrieve).returns :absent
+ @user.property(:uid).expects(:retrieve).never
+ @user.retrieve[@user.property(:uid)].should == :absent
+ end
+
+ it "should include the result of retrieving each property's current value if the user is present" do
+ @user.property(:ensure).expects(:retrieve).returns :present
+ @user.property(:uid).expects(:retrieve).returns 15
+ @user.retrieve[@user.property(:uid)].should == 15
+ end
+ end
+
+ describe "when managing the ensure property" do
+ before do
+ @ensure = user.attrclass(:ensure).new(:resource => @resource)
+ end
+
+ 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
+
+ it "should call :create on the provider when asked to sync to the :present state" do
+ @provider.expects(:create)
+ @ensure.should = :present
+ @ensure.sync
+ end
+
+ it "should call :delete on the provider when asked to sync to the :absent state" do
+ @provider.expects(:delete)
+ @ensure.should = :absent
+ @ensure.sync
+ end
+ describe "and determining the current state" do
+ it "should return :present when the provider indicates the user exists" do
+ @provider.expects(:exists?).returns true
+ @ensure.retrieve.should == :present
+ end
+
+ it "should return :absent when the provider indicates the user does not exist" do
+ @provider.expects(:exists?).returns false
+ @ensure.retrieve.should == :absent
+ end
+ end
+ end
+
+ describe "when managing the uid property" do
+ it "should convert number-looking strings into actual numbers" do
+ uid = user.attrclass(:uid).new(:resource => @resource)
+ uid.should = "50"
+ uid.should.must == 50
+ end
+
+ it "should support UIDs as numbers" do
+ uid = user.attrclass(:uid).new(:resource => @resource)
+ uid.should = 50
+ uid.should.must == 50
+ end
+
+ it "should :absent as a value" do
+ uid = user.attrclass(:uid).new(:resource => @resource)
+ uid.should = :absent
+ uid.should.must == :absent
+ end
+ end
+
+ describe "when managing the gid" do
+ it "should :absent as a value" do
+ gid = user.attrclass(:gid).new(:resource => @resource)
+ gid.should = :absent
+ gid.should.must == :absent
+ end
+
+ it "should convert number-looking strings into actual numbers" do
+ gid = user.attrclass(:gid).new(:resource => @resource)
+ gid.should = "50"
+ gid.should.must == 50
+ end
+
+ it "should support GIDs specified as integers" do
+ gid = user.attrclass(:gid).new(:resource => @resource)
+ gid.should = 50
+ gid.should.must == 50
+ end
+
+ it "should support groups specified by name" do
+ gid = user.attrclass(:gid).new(:resource => @resource)
+ gid.should = "foo"
+ gid.should.must == "foo"
+ end
+
+ describe "when syncing" do
+ before do
+ @gid = user.attrclass(:gid).new(:resource => @resource, :should => %w{foo bar})
+ end
+
+ it "should use the first found, specified group as the desired value and send it to the provider" do
+ Puppet::Util.expects(:gid).with("foo").returns nil
+ Puppet::Util.expects(:gid).with("bar").returns 500
+
+ @provider.expects(:gid=).with 500
+
+ @gid.sync
+ end
+ end
+ end
+
+ describe "when managing passwords" do
+ before do
+ @password = user.attrclass(:password).new(:resource => @resource, :should => "mypass")
+ end
+
+ it "should not include the password in the change log when adding the password" do
+ @password.change_to_s(:absent, "mypass").should_not be_include("mypass")
+ end
+
+ it "should not include the password in the change log when changing the password" do
+ @password.change_to_s("other", "mypass").should_not be_include("mypass")
+ end
+ end
+end
diff --git a/spec/unit/util/log.rb b/spec/unit/util/log.rb
new file mode 100755
index 000000000..aa00602a9
--- /dev/null
+++ b/spec/unit/util/log.rb
@@ -0,0 +1,153 @@
+#!/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/util/log'
+
+describe Puppet::Util::Log do
+ describe "instances" do
+ before do
+ Puppet::Util::Log.stubs(:newmessage)
+ end
+
+ [:level, :message, :time, :remote].each do |attr|
+ it "should have a %s attribute" % attr do
+ log = Puppet::Util::Log.new :level => :notice, :message => "A test message"
+ log.should respond_to(attr)
+ log.should respond_to(attr.to_s + "=")
+ end
+ end
+
+ it "should fail if created without a level" do
+ lambda { Puppet::Util::Log.new(:message => "A test message") }.should raise_error(ArgumentError)
+ end
+
+ it "should fail if created without a message" do
+ lambda { Puppet::Util::Log.new(:level => :notice) }.should raise_error(ArgumentError)
+ end
+
+ it "should make available the level passed in at initialization" do
+ Puppet::Util::Log.new(:level => :notice, :message => "A test message").level.should == :notice
+ end
+
+ it "should make available the message passed in at initialization" do
+ Puppet::Util::Log.new(:level => :notice, :message => "A test message").message.should == "A test message"
+ end
+
+ # LAK:NOTE I don't know why this behavior is here, I'm just testing what's in the code,
+ # at least at first.
+ it "should always convert messages to strings" do
+ Puppet::Util::Log.new(:level => :notice, :message => :foo).message.should == "foo"
+ end
+
+ it "should convert the level to a symbol if it's passed in as a string" do
+ Puppet::Util::Log.new(:level => "notice", :message => :foo).level.should == :notice
+ end
+
+ it "should fail if the level is not a symbol or string" do
+ lambda { Puppet::Util::Log.new(:level => 50, :message => :foo) }.should raise_error(ArgumentError)
+ end
+
+ it "should fail if the provided level is not valid" do
+ Puppet::Util::Log.expects(:validlevel?).with(:notice).returns false
+ lambda { Puppet::Util::Log.new(:level => :notice, :message => :foo) }.should raise_error(ArgumentError)
+ end
+
+ it "should set its time to the initialization time" do
+ time = mock 'time'
+ Time.expects(:now).returns time
+ Puppet::Util::Log.new(:level => "notice", :message => :foo).time.should equal(time)
+ end
+
+ it "should make available any passed-in tags" do
+ log = Puppet::Util::Log.new(:level => "notice", :message => :foo, :tags => %w{foo bar})
+ log.tags.should be_include("foo")
+ log.tags.should be_include("bar")
+ end
+
+ it "should use an passed-in source" do
+ Puppet::Util::Log.any_instance.expects(:source=).with "foo"
+ Puppet::Util::Log.new(:level => "notice", :message => :foo, :source => "foo")
+ end
+
+ it "should default to 'Puppet' as its source" do
+ Puppet::Util::Log.new(:level => "notice", :message => :foo).source.should == "Puppet"
+ end
+
+ it "should register itself with Log" do
+ Puppet::Util::Log.expects(:newmessage)
+ Puppet::Util::Log.new(:level => "notice", :message => :foo)
+ end
+
+ it "should have a method for determining if a tag is present" do
+ Puppet::Util::Log.new(:level => "notice", :message => :foo).should respond_to(:tagged?)
+ end
+
+ it "should match a tag if any of the tags are equivalent to the passed tag as a string" do
+ Puppet::Util::Log.new(:level => "notice", :message => :foo, :tags => %w{one two}).should be_tagged(:one)
+ end
+
+ it "should tag itself with its log level" do
+ Puppet::Util::Log.new(:level => "notice", :message => :foo).should be_tagged(:notice)
+ end
+
+ it "should return its message when converted to a string" do
+ Puppet::Util::Log.new(:level => "notice", :message => :foo).to_s.should == "foo"
+ end
+
+ it "should include its time, source, level, and message when prepared for reporting" do
+ log = Puppet::Util::Log.new(:level => "notice", :message => :foo)
+ report = log.to_report
+ report.should be_include("notice")
+ report.should be_include("foo")
+ report.should be_include(log.source)
+ report.should be_include(log.time.to_s)
+ end
+
+ it "should have a method for indicating whether it was created by a resource" do
+ Puppet::Util::Log.new(:level => "notice", :message => :foo).should respond_to(:objectsource?)
+ end
+
+ describe "when setting a source" do
+ it "should mark itself as from a Puppet resource if its source is a Puppet resource" do
+ file = Puppet::Type.type(:file).create :path => "/testing/object/source/in/logs"
+ Puppet::Util::Log.new(:level => "notice", :message => :foo, :source => file).should be_objectsource
+ end
+
+ it "should use the resource's path when its source is a resource" do
+ # Use a different path, so we don't use 'clear', which is deprecated in master
+ file = Puppet::Type.type(:file).create :path => "/testing/object/source/in/logs/with/path"
+ file.expects(:path).returns "mypath"
+ Puppet::Util::Log.new(:level => "notice", :message => :foo, :source => file).source.should == "mypath"
+ end
+
+ it "should mark itself as from a Puppet resource if its source is a Puppet parameter" do
+ file = Puppet::Type.type(:file).create :path => "/testing/object/source/in/logs/with/parameters", :mode => "500"
+ mode = file.property(:mode)
+ Puppet::Util::Log.new(:level => "notice", :message => :foo, :source => mode).should be_objectsource
+ end
+
+ it "should use the resource's path when its source is a Puppet parameter" do
+ # Use a different path, so we don't use 'clear', which is deprecated in master
+ file = Puppet::Type.type(:file).create :path => "/testing/object/source/in/logs/with/path/in/parameters", :mode => "500"
+ mode = file.property(:mode)
+ mode.expects(:path).returns "mypath"
+ Puppet::Util::Log.new(:level => "notice", :message => :foo, :source => mode).source.should == "mypath"
+ end
+
+ it "should acquire its source's tags if its source has any" do
+ file = Puppet::Type.type(:file).create :path => "/testing/object/source/in/logs/with/tags"
+ file.tag("foo")
+ file.tag("bar")
+ log = Puppet::Util::Log.new(:level => "notice", :message => :foo, :source => file)
+
+ log.should be_tagged("foo")
+ log.should be_tagged("bar")
+ end
+
+ it "should not set objectsource if the source is not a Parameter or Resource" do
+ Puppet::Util::Log.new(:level => "notice", :message => :foo, :source => "mysource").should_not be_objectsource
+ end
+ end
+ end
+end
diff --git a/spec/unit/util/metric.rb b/spec/unit/util/metric.rb
new file mode 100755
index 000000000..3501aac90
--- /dev/null
+++ b/spec/unit/util/metric.rb
@@ -0,0 +1,95 @@
+#!/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/util/metric'
+
+describe Puppet::Util::Metric do
+ before do
+ @metric = Puppet::Util::Metric.new("foo")
+ end
+
+ it "should be aliased to Puppet::Metric" do
+ Puppet::Util::Metric.should equal(Puppet::Metric)
+ end
+
+ [:type, :name, :value, :label, :basedir].each do |name|
+ it "should have a #{name} attribute" do
+ @metric.should respond_to(name)
+ @metric.should respond_to(name.to_s + "=")
+ end
+ end
+
+ it "should default to the :rrdir as the basedir "do
+ Puppet.settings.expects(:value).with(:rrddir).returns "myrrd"
+ @metric.basedir.should == "myrrd"
+ end
+
+ it "should use any provided basedir" do
+ @metric.basedir = "foo"
+ @metric.basedir.should == "foo"
+ end
+
+ it "should require a name at initialization" do
+ lambda { Puppet::Util::Metric.new }.should raise_error(ArgumentError)
+ end
+
+ it "should always convert its name to a string" do
+ Puppet::Util::Metric.new(:foo).name.should == "foo"
+ end
+
+ it "should support a label" do
+ Puppet::Util::Metric.new("foo", "mylabel").label.should == "mylabel"
+ end
+
+ it "should autogenerate a label if none is provided" do
+ Puppet::Util::Metric.new("foo_bar").label.should == "Foo bar"
+ end
+
+ it "should have a method for adding values" do
+ @metric.should respond_to(:newvalue)
+ end
+
+ it "should have a method for returning values" do
+ @metric.should respond_to(:values)
+ end
+
+ it "should require a name and value for its values" do
+ lambda { @metric.newvalue }.should raise_error(ArgumentError)
+ end
+
+ it "should support a label for values" do
+ @metric.newvalue(:foo, 10, "label")
+ @metric.values[0][1].should == "label"
+ end
+
+ it "should autogenerate value labels if none is provided" do
+ @metric.newvalue("foo_bar", 10)
+ @metric.values[0][1].should == "Foo bar"
+ end
+
+ it "should return its values sorted by label" do
+ @metric.newvalue(:foo, 10, "b")
+ @metric.newvalue(:bar, 10, "a")
+
+ @metric.values.should == [[:bar, "a", 10], [:foo, "b", 10]]
+ end
+
+ it "should use an array indexer method to retrieve individual values" do
+ @metric.newvalue(:foo, 10)
+ @metric[:foo].should == 10
+ end
+
+ it "should return nil if the named value cannot be found" do
+ @metric[:foo].should be_nil
+ end
+
+ # LAK: I'm not taking the time to develop these tests right now.
+ # I expect they should actually be extracted into a separate class
+ # anyway.
+ it "should be able to graph metrics using RRDTool"
+
+ it "should be able to create a new RRDTool database"
+
+ it "should be able to store metrics into an RRDTool database"
+end
diff --git a/spec/unit/util/posix.rb b/spec/unit/util/posix.rb
new file mode 100755
index 000000000..95a5608bd
--- /dev/null
+++ b/spec/unit/util/posix.rb
@@ -0,0 +1,256 @@
+#!/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/util/posix'
+
+class PosixTest
+ include Puppet::Util::POSIX
+end
+
+describe Puppet::Util::POSIX do
+ before do
+ @posix = PosixTest.new
+ end
+
+ [:group, :gr].each do |name|
+ it "should return :gid as the field for %s" % name do
+ @posix.idfield(name).should == :gid
+ end
+
+ it "should return :getgrgid as the id method for %s" % name do
+ @posix.methodbyid(name).should == :getgrgid
+ end
+
+ it "should return :getgrnam as the name method for %s" % name do
+ @posix.methodbyname(name).should == :getgrnam
+ end
+ end
+
+ [:user, :pw, :passwd].each do |name|
+ it "should return :uid as the field for %s" % name do
+ @posix.idfield(name).should == :uid
+ end
+
+ it "should return :getpwuid as the id method for %s" % name do
+ @posix.methodbyid(name).should == :getpwuid
+ end
+
+ it "should return :getpwnam as the name method for %s" % name do
+ @posix.methodbyname(name).should == :getpwnam
+ end
+ end
+
+ describe "when retrieving a posix field" do
+ before do
+ @thing = stub 'thing', :field => "asdf"
+ end
+
+ it "should fail if no id was passed" do
+ lambda { @posix.get_posix_field("asdf", "bar", nil) }.should raise_error(Puppet::DevError)
+ end
+
+ describe "and the id is an integer" do
+ it "should log an error and return nil if the specified id is greater than the maximum allowed ID" do
+ Puppet.settings.expects(:value).with(:maximum_uid).returns 100
+ Puppet.expects(:err)
+
+ @posix.get_posix_field("asdf", "bar", 200).should be_nil
+ end
+
+ it "should use the method return by :methodbyid and return the specified field" do
+ Etc.expects(:getgrgid).returns @thing
+
+ @thing.expects(:field).returns "myval"
+
+ @posix.get_posix_field(:gr, :field, 200).should == "myval"
+ end
+
+ it "should return nil if the method throws an exception" do
+ Etc.expects(:getgrgid).raises ArgumentError
+
+ @thing.expects(:field).never
+
+ @posix.get_posix_field(:gr, :field, 200).should be_nil
+ end
+ end
+
+ describe "and the id is not an integer" do
+ it "should use the method return by :methodbyid and return the specified field" do
+ Etc.expects(:getgrnam).returns @thing
+
+ @thing.expects(:field).returns "myval"
+
+ @posix.get_posix_field(:gr, :field, "asdf").should == "myval"
+ end
+
+ it "should return nil if the method throws an exception" do
+ Etc.expects(:getgrnam).raises ArgumentError
+
+ @thing.expects(:field).never
+
+ @posix.get_posix_field(:gr, :field, "asdf").should be_nil
+ end
+ end
+ end
+
+ describe "when returning the gid" do
+ before do
+ @posix.stubs(:get_posix_field)
+ end
+
+ describe "and the group is an integer" do
+ it "should convert integers specified as a string into an integer" do
+ @posix.expects(:get_posix_field).with(:group, :name, 100)
+
+ @posix.gid("100")
+ end
+
+ it "should look up the name for the group" do
+ @posix.expects(:get_posix_field).with(:group, :name, 100)
+
+ @posix.gid(100)
+ end
+
+ it "should return nil if the group cannot be found" do
+ @posix.expects(:get_posix_field).once.returns nil
+ @posix.expects(:search_posix_field).never
+
+ @posix.gid(100).should be_nil
+ end
+
+ it "should use the found name to look up the id" do
+ @posix.expects(:get_posix_field).with(:group, :name, 100).returns "asdf"
+ @posix.expects(:get_posix_field).with(:group, :gid, "asdf").returns 100
+
+ @posix.gid(100).should == 100
+ end
+
+ # LAK: This is because some platforms have a broken Etc module that always return
+ # the same group.
+ it "should use :search_posix_field if the discovered id does not match the passed-in id" do
+ @posix.expects(:get_posix_field).with(:group, :name, 100).returns "asdf"
+ @posix.expects(:get_posix_field).with(:group, :gid, "asdf").returns 50
+
+ @posix.expects(:search_posix_field).with(:group, :gid, 100).returns "asdf"
+
+ @posix.gid(100).should == "asdf"
+ end
+ end
+
+ describe "and the group is a string" do
+ it "should look up the gid for the group" do
+ @posix.expects(:get_posix_field).with(:group, :gid, "asdf")
+
+ @posix.gid("asdf")
+ end
+
+ it "should return nil if the group cannot be found" do
+ @posix.expects(:get_posix_field).once.returns nil
+ @posix.expects(:search_posix_field).never
+
+ @posix.gid("asdf").should be_nil
+ end
+
+ it "should use the found gid to look up the nam" do
+ @posix.expects(:get_posix_field).with(:group, :gid, "asdf").returns 100
+ @posix.expects(:get_posix_field).with(:group, :name, 100).returns "asdf"
+
+ @posix.gid("asdf").should == 100
+ end
+
+ it "should use :search_posix_field if the discovered name does not match the passed-in name" do
+ @posix.expects(:get_posix_field).with(:group, :gid, "asdf").returns 100
+ @posix.expects(:get_posix_field).with(:group, :name, 100).returns "boo"
+
+ @posix.expects(:search_posix_field).with(:group, :gid, "asdf").returns "asdf"
+
+ @posix.gid("asdf").should == "asdf"
+ end
+ end
+ end
+
+ describe "when returning the uid" do
+ before do
+ @posix.stubs(:get_posix_field)
+ end
+
+ describe "and the group is an integer" do
+ it "should convert integers specified as a string into an integer" do
+ @posix.expects(:get_posix_field).with(:passwd, :name, 100)
+
+ @posix.uid("100")
+ end
+
+ it "should look up the name for the group" do
+ @posix.expects(:get_posix_field).with(:passwd, :name, 100)
+
+ @posix.uid(100)
+ end
+
+ it "should return nil if the group cannot be found" do
+ @posix.expects(:get_posix_field).once.returns nil
+ @posix.expects(:search_posix_field).never
+
+ @posix.uid(100).should be_nil
+ end
+
+ it "should use the found name to look up the id" do
+ @posix.expects(:get_posix_field).with(:passwd, :name, 100).returns "asdf"
+ @posix.expects(:get_posix_field).with(:passwd, :uid, "asdf").returns 100
+
+ @posix.uid(100).should == 100
+ end
+
+ # LAK: This is because some platforms have a broken Etc module that always return
+ # the same group.
+ it "should use :search_posix_field if the discovered id does not match the passed-in id" do
+ @posix.expects(:get_posix_field).with(:passwd, :name, 100).returns "asdf"
+ @posix.expects(:get_posix_field).with(:passwd, :uid, "asdf").returns 50
+
+ @posix.expects(:search_posix_field).with(:passwd, :uid, 100).returns "asdf"
+
+ @posix.uid(100).should == "asdf"
+ end
+ end
+
+ describe "and the group is a string" do
+ it "should look up the uid for the group" do
+ @posix.expects(:get_posix_field).with(:passwd, :uid, "asdf")
+
+ @posix.uid("asdf")
+ end
+
+ it "should return nil if the group cannot be found" do
+ @posix.expects(:get_posix_field).once.returns nil
+ @posix.expects(:search_posix_field).never
+
+ @posix.uid("asdf").should be_nil
+ end
+
+ it "should use the found uid to look up the nam" do
+ @posix.expects(:get_posix_field).with(:passwd, :uid, "asdf").returns 100
+ @posix.expects(:get_posix_field).with(:passwd, :name, 100).returns "asdf"
+
+ @posix.uid("asdf").should == 100
+ end
+
+ it "should use :search_posix_field if the discovered name does not match the passed-in name" do
+ @posix.expects(:get_posix_field).with(:passwd, :uid, "asdf").returns 100
+ @posix.expects(:get_posix_field).with(:passwd, :name, 100).returns "boo"
+
+ @posix.expects(:search_posix_field).with(:passwd, :uid, "asdf").returns "asdf"
+
+ @posix.uid("asdf").should == "asdf"
+ end
+ end
+ end
+
+ it "should be able to iteratively search for posix values" do
+ @posix.should respond_to(:search_posix_field)
+ end
+
+ describe "when searching for posix values iteratively" do
+ it "should iterate across all of the structs returned by Etc and return the appropriate field from the first matching value"
+ end
+end
diff --git a/spec/unit/util/selinux.rb b/spec/unit/util/selinux.rb
new file mode 100644
index 000000000..515c3a273
--- /dev/null
+++ b/spec/unit/util/selinux.rb
@@ -0,0 +1,174 @@
+#!/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/util/selinux'
+include Puppet::Util::SELinux
+
+describe Puppet::Util::SELinux do
+
+ describe "selinux_support?" do
+ it "should return :true if this system has SELinux enabled" do
+ FileTest.expects(:exists?).with("/selinux/enforce").returns true
+ 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_support?.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
+ get_selinux_current_context("/foo").should be_nil
+ end
+
+ 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"]
+ 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
+ self.expects(:selinux_support?).returns true
+ self.expects(:execpipe).with("/usr/bin/stat -c %C /foo").yields ["(null)\n"]
+ get_selinux_current_context("/foo").should be_nil
+ end
+ end
+
+ describe "get_selinux_default_context" do
+ it "should return nil if no SELinux support" do
+ self.expects(:selinux_support?).returns false
+ get_selinux_default_context("/foo").should be_nil
+ end
+
+ it "should return nil if matchpathcon is not executable" do
+ self.expects(:selinux_support?).returns true
+ FileTest.expects(:executable?).with("/usr/sbin/matchpathcon").returns false
+ get_selinux_default_context("/foo").should be_nil
+ end
+
+ 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 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"
+ end
+
+ it "should return nil if an exception is raised calling matchpathcon" 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')
+ get_selinux_default_context("/foo").should be_nil
+ end
+ end
+
+ describe "parse_selinux_context" do
+ it "should return nil if no context is passed" do
+ parse_selinux_context(:seluser, nil).should be_nil
+ end
+
+ it "should return nil if the context is 'unlabeled'" do
+ parse_selinux_context(:seluser, "unlabeled").should be_nil
+ end
+
+ it "should return the user type when called with :seluser" do
+ parse_selinux_context(:seluser, "user_u:role_r:type_t:s0").should == "user_u"
+ end
+
+ it "should return the role type when called with :selrole" do
+ parse_selinux_context(:selrole, "user_u:role_r:type_t:s0").should == "role_r"
+ end
+
+ it "should return the type type when called with :seltype" do
+ parse_selinux_context(:seltype, "user_u:role_r:type_t:s0").should == "type_t"
+ end
+
+ it "should return nil for :selrange when no range is returned" do
+ parse_selinux_context(:selrange, "user_u:role_r:type_t").should be_nil
+ end
+
+ it "should return the range type when called with :selrange" do
+ parse_selinux_context(:selrange, "user_u:role_r:type_t:s0").should == "s0"
+ end
+
+ describe "with a variety of SELinux range formats" do
+ ['s0', 's0:c3', 's0:c3.c123', 's0:c3,c5,c8', 'TopSecret', 'TopSecret,Classified', 'Patient_Record'].each do |range|
+ it "should parse range '#{range}'" do
+ parse_selinux_context(:selrange, "user_u:role_r:type_t:#{range}").should == range
+ end
+ end
+ end
+ end
+
+ describe "set_selinux_context" do
+ it "should return nil if there is no SELinux support" do
+ self.expects(:selinux_support?).returns false
+ set_selinux_context("/foo", "user_u:role_r:type_t:s0").should be_nil
+ end
+
+ it "should use chcon 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
+ 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
+ self.expects(:selinux_support?).returns true
+ self.expects(:execute).with(["/usr/bin/chcon","-h","-u","user_u","/foo"]).returns 0
+ set_selinux_context("/foo", "user_u", :seluser).should be_true
+ end
+
+ it "should use chcon 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
+ set_selinux_context("/foo", "role_r", :selrole).should be_true
+ end
+
+ it "should use chcon 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
+ set_selinux_context("/foo", "type_t", :seltype).should be_true
+ end
+
+ it "should use chcon 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
+ set_selinux_context("/foo", "s0:c3,c5", :selrange).should be_true
+ end
+ end
+
+ describe "set_selinux_default_context" do
+ it "should return nil if there is no SELinux support" do
+ self.expects(:selinux_support?).returns false
+ set_selinux_default_context("/foo").should be_nil
+ end
+
+ it "should return nil if no default context exists" do
+ self.expects(:get_selinux_default_context).with("/foo").returns nil
+ set_selinux_default_context("/foo").should be_nil
+ end
+
+ it "should do nothing and return nil if the current context matches the default context" do
+ self.expects(:get_selinux_default_context).with("/foo").returns "user_u:role_r:type_t"
+ self.expects(:get_selinux_current_context).with("/foo").returns "user_u:role_r:type_t"
+ set_selinux_default_context("/foo").should be_nil
+ end
+
+ it "should set and return the default context if current and default do not match" do
+ self.expects(:get_selinux_default_context).with("/foo").returns "user_u:role_r:type_t"
+ self.expects(:get_selinux_current_context).with("/foo").returns "olduser_u:role_r:type_t"
+ self.expects(:set_selinux_context).with("/foo", "user_u:role_r:type_t").returns true
+ set_selinux_default_context("/foo").should == "user_u:role_r:type_t"
+ end
+ end
+
+end
diff --git a/spec/unit/util/settings.rb b/spec/unit/util/settings.rb
index 0faa92c68..a333c513e 100755
--- a/spec/unit/util/settings.rb
+++ b/spec/unit/util/settings.rb
@@ -254,6 +254,12 @@ describe Puppet::Util::Settings do
@settings.value(:one, "env").should == "envval"
end
+ it "should interpolate found values using the current environment" do
+ @settings.setdefaults :main, :myval => ["$environment/foo", "mydocs"]
+
+ @settings.value(:myval, "myenv").should == "myenv/foo"
+ end
+
it "should return values in a specified environment before values in the main or name sections" do
text = "[env]\none = envval\n[main]\none = mainval\n[myname]\none = nameval\n"
file = "/some/file"
@@ -760,6 +766,7 @@ describe Puppet::Util::Settings do
end
it "should return false if a config param is not found" do
+ @settings.stubs :puts
@settings.stubs(:value).with(:configprint).returns("something")
@settings.stubs(:include?).with("something").returns(false)
@settings.print_configs.should be_false
@@ -767,6 +774,10 @@ describe Puppet::Util::Settings do
end
describe "when genconfig is true" do
+ before do
+ @settings.stubs :puts
+ end
+
it "should call to_config" do
@settings.stubs(:value).with(:genconfig).returns(true)
@settings.expects(:to_config)
@@ -781,6 +792,10 @@ describe Puppet::Util::Settings do
end
describe "when genmanifest is true" do
+ before do
+ @settings.stubs :puts
+ end
+
it "should call to_config" do
@settings.stubs(:value).with(:genmanifest).returns(true)
@settings.expects(:to_manifest)
diff --git a/spec/unit/util/user_attr.rb b/spec/unit/util/user_attr.rb
new file mode 100644
index 000000000..57787b1a6
--- /dev/null
+++ b/spec/unit/util/user_attr.rb
@@ -0,0 +1,47 @@
+#!/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/util/user_attr'
+
+describe UserAttr do
+ before do
+ user_attr = ["foo::::type=role", "bar::::type=normal;profile=foobar"]
+ File.stubs(:readlines).returns(user_attr)
+ end
+
+ describe "when getting attributes by name" do
+ it "should return nil if there is no entry for that name" do
+ UserAttr.get_attributes_by_name('baz').should == nil
+ end
+
+ it "should return a hash if there is an entry in /etc/user_attr" do
+ UserAttr.get_attributes_by_name('foo').class.should == Hash
+ end
+
+ it "should return a hash with the name value from /etc/user_attr" do
+ UserAttr.get_attributes_by_name('foo')[:name].should == 'foo'
+ end
+
+ #this test is contrived
+ #there are a bunch of possible parameters that could be in the hash
+ #the role/normal is just a the convention of the file
+ describe "when the name is a role" do
+ it "should contain :type = role" do
+ UserAttr.get_attributes_by_name('foo')[:type].should == 'role'
+ end
+ end
+
+ describe "when the name is not a role" do
+ it "should contain :type = normal" do
+ UserAttr.get_attributes_by_name('bar')[:type].should == 'normal'
+ end
+ end
+
+ describe "when the name has more attributes" do
+ it "should contain all the attributes" do
+ UserAttr.get_attributes_by_name('bar')[:profile].should == 'foobar'
+ end
+ end
+ end
+end