summaryrefslogtreecommitdiffstats
path: root/spec
diff options
context:
space:
mode:
authorMax Martin <max@puppetlabs.com>2011-03-30 13:00:56 -0700
committerMax Martin <max@puppetlabs.com>2011-03-30 13:00:56 -0700
commit9d17809e5b240aa80d2c30f4d9625d4812802b8f (patch)
treef2c9101dbf36c9fcbf51454c9baca9a7d92cb667 /spec
parent76b3ee6822f52b100c45cd8921f13739f12ddf38 (diff)
parentf5170fc2dbcbb4202b9b08e8944aa35f7a7bf7b8 (diff)
downloadpuppet-9d17809e5b240aa80d2c30f4d9625d4812802b8f.tar.gz
puppet-9d17809e5b240aa80d2c30f4d9625d4812802b8f.tar.xz
puppet-9d17809e5b240aa80d2c30f4d9625d4812802b8f.zip
Merge branch '2.6.next' into 2.6.x
* 2.6.next: (23 commits) (#5908) Add support for new update-rc.d disable API (#6862) Add a default subject for the mail_patches rake task Fixed #6256 - Creation of rrd directory. (#5477) Allow watch_file to watch non-existent files, especially site.pp (#5221) Add test for fix to fileset with trailing separator (#5221) Fix fileset path absoluteness checking with trailing slash (#4769) Fix negative timeout support for newer rubies Fixed #6562 - Minor kick documentation fix (#6658) Propagate ENC connection errors to the agent (#4884) Remove typo from spec test (#4884) Modify tests to pass on non-OS X systems (#4884) Revise new exec tests, add a few more (4576) - if ENC declares invalid class, it is logged at warning. (#4884) Add an shell provider for execs (#4884) Fix Test::Unit exec tests (#4884) Break the exec type out to have a posix provider (#4884) Add consistent path validation and behavior (#4884) Add expand_path to requiring the spec_helper (#4884) Autorequire shared behaviors and method to silence warnings (#4884) Fix whitespace ...
Diffstat (limited to 'spec')
-rwxr-xr-xspec/integration/transaction_spec.rb24
-rw-r--r--spec/lib/puppet_spec/verbose.rb9
-rw-r--r--spec/shared_behaviours/path_parameters.rb185
-rw-r--r--spec/spec_helper.rb6
-rw-r--r--spec/unit/application/master_spec.rb4
-rwxr-xr-xspec/unit/file_serving/fileset_spec.rb8
-rwxr-xr-xspec/unit/indirector/exec_spec.rb5
-rw-r--r--spec/unit/parameter/path_spec.rb24
-rwxr-xr-xspec/unit/parser/compiler_spec.rb3
-rwxr-xr-xspec/unit/parser/lexer_spec.rb12
-rwxr-xr-xspec/unit/provider/exec/posix_spec.rb120
-rw-r--r--spec/unit/provider/exec/shell_spec.rb50
-rwxr-xr-xspec/unit/provider/service/debian_spec.rb16
-rw-r--r--spec/unit/resource/type_collection_spec.rb31
-rwxr-xr-xspec/unit/type/cron_spec.rb484
-rwxr-xr-xspec/unit/type/exec_spec.rb739
-rwxr-xr-xspec/unit/type_spec.rb2
-rwxr-xr-xspec/unit/util/loadedfile_spec.rb7
-rwxr-xr-xspec/unit/util/rdoc/parser_spec.rb3
19 files changed, 1565 insertions, 167 deletions
diff --git a/spec/integration/transaction_spec.rb b/spec/integration/transaction_spec.rb
index d5478d7a7..2c12b3d5f 100755
--- a/spec/integration/transaction_spec.rb
+++ b/spec/integration/transaction_spec.rb
@@ -107,29 +107,23 @@ describe Puppet::Transaction do
file1 = tmpfile("file1")
file2 = tmpfile("file2")
- file = Puppet::Type.type(:file).new(
-
- :path => path,
-
+ file = Puppet::Type.type(:file).new(
+ :path => path,
:ensure => "file"
)
- exec1 = Puppet::Type.type(:exec).new(
-
- :path => ENV["PATH"],
+ exec1 = Puppet::Type.type(:exec).new(
+ :path => ENV["PATH"],
:command => "touch #{file1}",
:refreshonly => true,
-
- :subscribe => Puppet::Resource.new(:file, path)
+ :subscribe => Puppet::Resource.new(:file, path)
)
- exec2 = Puppet::Type.type(:exec).new(
-
- :path => ENV["PATH"],
- :command => "touch #{file2}",
+ exec2 = Puppet::Type.type(:exec).new(
+ :path => ENV["PATH"],
+ :command => "touch #{file2}",
:refreshonly => true,
-
- :subscribe => Puppet::Resource.new(:file, path)
+ :subscribe => Puppet::Resource.new(:file, path)
)
catalog = mk_catalog(file, exec1, exec2)
diff --git a/spec/lib/puppet_spec/verbose.rb b/spec/lib/puppet_spec/verbose.rb
new file mode 100644
index 000000000..d9834f2d7
--- /dev/null
+++ b/spec/lib/puppet_spec/verbose.rb
@@ -0,0 +1,9 @@
+# Support code for running stuff with warnings disabled.
+module Kernel
+ def with_verbose_disabled
+ verbose, $VERBOSE = $VERBOSE, nil
+ result = yield
+ $VERBOSE = verbose
+ return result
+ end
+end
diff --git a/spec/shared_behaviours/path_parameters.rb b/spec/shared_behaviours/path_parameters.rb
new file mode 100644
index 000000000..b5a907900
--- /dev/null
+++ b/spec/shared_behaviours/path_parameters.rb
@@ -0,0 +1,185 @@
+# In order to use this correctly you must define a method to get an instance
+# of the type being tested, so that this code can remain generic:
+#
+# it_should_behave_like "all path parameters", :path do
+# def instance(path)
+# Puppet::Type.type(:example).new(
+# :name => 'foo', :require => 'bar', :path_param => path
+# )
+# end
+#
+# That method will be invoked for each test to create the instance that we
+# subsequently test through the system; you should ensure that the minimum of
+# possible attributes are set to keep the tests clean.
+#
+# You must also pass the symbolic name of the parameter being tested to the
+# block, and optionally can pass a hash of additional options to the block.
+#
+# The known options are:
+# :array :: boolean, does this support arrays of paths, default true.
+
+shared_examples_for "all pathname parameters with arrays" do |win32|
+ path_types = {
+ "unix absolute" => "/foo/bar",
+ "unix relative" => "foo/bar",
+ "win32 absolute" => %q{\foo\bar},
+ "win32 relative" => %q{foo\bar},
+ "drive absolute" => %q{c:\foo\bar},
+ "drive relative" => %q{c:foo\bar}
+ }
+
+ describe "when given an array of paths" do
+ (1..path_types.length).each do |n|
+ path_types.keys.combination(n) do |set|
+ data = path_types.collect { |k, v| set.member?(k) ? v : nil } .compact
+ reject = true
+ only_absolute = set.find { |k| k =~ /relative/ } .nil?
+ only_unix = set.reject { |k| k =~ /unix/ } .length == 0
+
+ if only_absolute and (only_unix or win32) then
+ reject = false
+ end
+
+ it "should #{reject ? 'reject' : 'accept'} #{set.join(", ")}" do
+ if reject then
+ expect { instance(data) }.
+ should raise_error Puppet::Error, /fully qualified/
+ else
+ instance = instance(data)
+ instance[@param].should == data
+ end
+ end
+
+ it "should #{reject ? 'reject' : 'accept'} #{set.join(", ")} doubled" do
+ if reject then
+ expect { instance(data + data) }.
+ should raise_error Puppet::Error, /fully qualified/
+ else
+ instance = instance(data + data)
+ instance[@param].should == (data + data)
+ end
+ end
+ end
+ end
+ end
+end
+
+
+shared_examples_for "all path parameters" do |param, options|
+ # Extract and process options to the block.
+ options ||= {}
+ array = options[:array].nil? ? true : options.delete(:array)
+ if options.keys.length > 0 then
+ fail "unknown options for 'all path parameters': " +
+ options.keys.sort.join(', ')
+ end
+
+ def instance(path)
+ fail "we didn't implement the 'instance(path)' method in the it_should_behave_like block"
+ end
+
+ ########################################################################
+ # The actual testing code...
+ before :all do
+ @param = param
+ end
+
+ before :each do
+ @file_separator = File::SEPARATOR
+ end
+ after :each do
+ with_verbose_disabled do
+ verbose, $VERBOSE = $VERBOSE, nil
+ File::SEPARATOR = @file_separator
+ $VERBOSE = verbose
+ end
+ end
+
+ describe "on a Unix-like platform it" do
+ before :each do
+ with_verbose_disabled do
+ File::SEPARATOR = '/'
+ end
+ Puppet.features.stubs(:microsoft_windows?).returns(false)
+ Puppet.features.stubs(:posix?).returns(true)
+ end
+
+ if array then
+ it_should_behave_like "all pathname parameters with arrays", false
+ end
+
+ it "should accept a fully qualified path" do
+ path = File.join('', 'foo')
+ instance = instance(path)
+ instance[@param].should == path
+ end
+
+ it "should give a useful error when the path is not absolute" do
+ path = 'foo'
+ expect { instance(path) }.
+ should raise_error Puppet::Error, /fully qualified/
+ end
+
+ { "Unix" => '/', "Win32" => '\\' }.each do |style, slash|
+ %w{q Q a A z Z c C}.sort.each do |drive|
+ it "should reject drive letter '#{drive}' with #{style} path separators" do
+ path = "#{drive}:#{slash}Program Files"
+ expect { instance(path) }.
+ should raise_error Puppet::Error, /fully qualified/
+ end
+ end
+ end
+ end
+
+ describe "on a Windows-like platform it" do
+ before :each do
+ with_verbose_disabled do
+ File::SEPARATOR = '\\'
+ end
+ Puppet.features.stubs(:microsoft_windows?).returns(true)
+ Puppet.features.stubs(:posix?).returns(false)
+ end
+
+ if array then
+ it_should_behave_like "all pathname parameters with arrays", true
+ end
+
+ it "should accept a fully qualified path" do
+ path = File.join('', 'foo')
+ instance = instance(path)
+ instance[@param].should == path
+ end
+
+ it "should give a useful error when the path is not absolute" do
+ path = 'foo'
+ expect { instance(path) }.
+ should raise_error Puppet::Error, /fully qualified/
+ end
+
+ it "also accepts Unix style path separators" do
+ path = '/Program Files'
+ instance = instance(path)
+ instance[@param].should == path
+ end
+
+ { "Unix" => '/', "Win32" => '\\' }.each do |style, slash|
+ %w{q Q a A z Z c C}.sort.each do |drive|
+ it "should accept drive letter '#{drive}' with #{style} path separators " do
+ path = "#{drive}:#{slash}Program Files"
+ instance = instance(path)
+ instance[@param].should == path
+ end
+ end
+ end
+
+ { "UNC paths" => %q{\\foo\bar},
+ "unparsed local paths" => %q{\\?\c:\foo},
+ "unparsed UNC paths" => %q{\\?\foo\bar}
+ }.each do |name, path|
+ it "should accept #{name} as absolute" do
+ instance = instance(path)
+ instance[@param].should == path
+ end
+ end
+ end
+end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index ae4edb2d9..505a8f973 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -23,10 +23,16 @@ end
module PuppetTest
end
+require 'pathname'
+require 'lib/puppet_spec/verbose'
require 'lib/puppet_spec/files'
require 'monkey_patches/alias_should_to_must'
require 'monkey_patches/publicize_methods'
+Pathname.glob("#{dir}/shared_behaviours/**/*.rb") do |behaviour|
+ require behaviour.relative_path_from(Pathname.new(dir))
+end
+
RSpec.configure do |config|
config.mock_with :mocha
diff --git a/spec/unit/application/master_spec.rb b/spec/unit/application/master_spec.rb
index 074249a4d..d99b22ded 100644
--- a/spec/unit/application/master_spec.rb
+++ b/spec/unit/application/master_spec.rb
@@ -176,8 +176,8 @@ describe Puppet::Application::Master do
lambda { @master.setup }.should raise_error(SystemExit)
end
- it "should tell Puppet.settings to use :main,:ssl and :master category" do
- Puppet.settings.expects(:use).with(:main,:master,:ssl)
+ it "should tell Puppet.settings to use :main,:ssl,:master and :metrics category" do
+ Puppet.settings.expects(:use).with(:main,:master,:ssl,:metrics)
@master.setup
end
diff --git a/spec/unit/file_serving/fileset_spec.rb b/spec/unit/file_serving/fileset_spec.rb
index ecc77812c..149c68c4a 100755
--- a/spec/unit/file_serving/fileset_spec.rb
+++ b/spec/unit/file_serving/fileset_spec.rb
@@ -13,6 +13,14 @@ describe Puppet::FileServing::Fileset, " when initializing" do
proc { Puppet::FileServing::Fileset.new("some/file") }.should raise_error(ArgumentError)
end
+ it "should not fail if the path is fully qualified, with a trailing separator" do
+ path = "/some/path/with/trailing/separator"
+ path_with_separator = "#{path}#{File::SEPARATOR}"
+ File.stubs(:lstat).with(path).returns stub('stat')
+ fileset = Puppet::FileServing::Fileset.new(path_with_separator)
+ fileset.path.should == path
+ end
+
it "should fail if its path does not exist" do
File.expects(:lstat).with("/some/file").returns nil
proc { Puppet::FileServing::Fileset.new("/some/file") }.should raise_error(ArgumentError)
diff --git a/spec/unit/indirector/exec_spec.rb b/spec/unit/indirector/exec_spec.rb
index acad1ea93..de37f2775 100755
--- a/spec/unit/indirector/exec_spec.rb
+++ b/spec/unit/indirector/exec_spec.rb
@@ -47,10 +47,9 @@ describe Puppet::Indirector::Exec do
@searcher.find(@request).should be_nil
end
- it "should return nil and log an error if there's an execution failure" do
+ it "should raise an exception if there's an execution failure" do
@searcher.expects(:execute).with(%w{/echo foo}).raises(Puppet::ExecutionFailure.new("message"))
- Puppet.expects(:err)
- @searcher.find(@request).should be_nil
+ lambda {@searcher.find(@request)}.should raise_exception(Puppet::Error, 'Failed to find foo via exec: message')
end
end
diff --git a/spec/unit/parameter/path_spec.rb b/spec/unit/parameter/path_spec.rb
new file mode 100644
index 000000000..08a26de33
--- /dev/null
+++ b/spec/unit/parameter/path_spec.rb
@@ -0,0 +1,24 @@
+#!/usr/bin/env ruby
+require File.expand_path(File.join(File.dirname(__FILE__), '../../spec_helper'))
+
+require 'puppet/parameter/path'
+
+[false, true].each do |arrays|
+ describe "Puppet::Parameter::Path with arrays #{arrays}" do
+ it_should_behave_like "all path parameters", :path, :array => arrays do
+ # The new type allows us a test that is guaranteed to go direct to our
+ # validation code, without passing through any "real type" overrides or
+ # whatever on the way.
+ Puppet::newtype(:test_puppet_parameter_path) do
+ newparam(:path, :parent => Puppet::Parameter::Path, :arrays => arrays) do
+ isnamevar
+ accept_arrays arrays
+ end
+ end
+
+ def instance(path)
+ Puppet::Type.type(:test_puppet_parameter_path).new(:path => path)
+ end
+ end
+ end
+end
diff --git a/spec/unit/parser/compiler_spec.rb b/spec/unit/parser/compiler_spec.rb
index 687f2ecb9..261cfdec1 100755
--- a/spec/unit/parser/compiler_spec.rb
+++ b/spec/unit/parser/compiler_spec.rb
@@ -581,12 +581,11 @@ describe Puppet::Parser::Compiler do
@scope.expects(:find_hostclass).with("notfound").returns(nil)
@compiler.evaluate_classes(%w{notfound}, @scope)
end
- # I wish it would fail
it "should log when it can't find class" do
klasses = {'foo'=>nil}
@node.classes = klasses
@compiler.topscope.stubs(:find_hostclass).with('foo').returns(nil)
- Puppet.expects(:info).with('Could not find class foo for testnode')
+ Puppet.expects(:warning).with('Could not find class foo for testnode')
@compiler.compile
end
end
diff --git a/spec/unit/parser/lexer_spec.rb b/spec/unit/parser/lexer_spec.rb
index 4ef242cf5..d144504c5 100755
--- a/spec/unit/parser/lexer_spec.rb
+++ b/spec/unit/parser/lexer_spec.rb
@@ -679,3 +679,15 @@ describe "Puppet::Parser::Lexer in the old tests when lexing example files" do
end
end
end
+
+describe "when trying to lex an non-existent file" do
+ include PuppetSpec::Files
+
+ it "should return an empty list of tokens" do
+ lexer = Puppet::Parser::Lexer.new
+ lexer.file = nofile = tmpfile('lexer')
+ File.exists?(nofile).should == false
+
+ lexer.fullscan.should == [[false,false]]
+ end
+end
diff --git a/spec/unit/provider/exec/posix_spec.rb b/spec/unit/provider/exec/posix_spec.rb
new file mode 100755
index 000000000..d02099250
--- /dev/null
+++ b/spec/unit/provider/exec/posix_spec.rb
@@ -0,0 +1,120 @@
+#!/usr/bin/env ruby
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+provider_class = Puppet::Type.type(:exec).provider(:posix)
+
+describe provider_class do
+ before :each do
+ @resource = Puppet::Resource.new(:exec, 'foo')
+ @provider = provider_class.new(@resource)
+ end
+
+ ["posix", "microsoft_windows"].each do |feature|
+ describe "when in #{feature} environment" do
+ before :each do
+ if feature == "microsoft_windows"
+ Puppet.features.stubs(:microsoft_windows?).returns(true)
+ Puppet.features.stubs(:posix?).returns(false)
+ else
+ Puppet.features.stubs(:posix?).returns(true)
+ Puppet.features.stubs(:microsoft_windows?).returns(false)
+ end
+ end
+
+ describe "#validatecmd" do
+ it "should fail if no path is specified and the command is not fully qualified" do
+ lambda { @provider.validatecmd("foo") }.should raise_error(
+ Puppet::Error,
+ "'foo' is not qualified and no path was specified. Please qualify the command or specify a path."
+ )
+ end
+
+ it "should pass if a path is given" do
+ @provider.resource[:path] = ['/bogus/bin']
+ @provider.validatecmd("../foo")
+ end
+
+ it "should pass if command is fully qualifed" do
+ @provider.resource[:path] = ['/bogus/bin']
+ @provider.validatecmd("/bin/blah/foo")
+ end
+ end
+
+ describe "#run" do
+ it "should fail if no path is specified and command does not exist" do
+ lambda { @provider.run("foo") }.should raise_error(ArgumentError, "Could not find command 'foo'")
+ end
+
+ it "should fail if the command isn't in the path" do
+ @provider.resource[:path] = ['/bogus/bin']
+ lambda { @provider.run("foo") }.should raise_error(ArgumentError, "Could not find command 'foo'")
+ end
+
+ it "should fail if the command isn't executable" do
+ @provider.resource[:path] = ['/bogus/bin']
+ File.stubs(:exists?).with("foo").returns(true)
+
+ lambda { @provider.run("foo") }.should raise_error(ArgumentError, "'foo' is not executable")
+ end
+
+ it "should not be able to execute shell builtins" do
+ @provider.resource[:path] = ['/bin']
+ lambda { @provider.run("cd ..") }.should raise_error(ArgumentError, "Could not find command 'cd'")
+ end
+
+ it "should execute the command if the command given includes arguments or subcommands" do
+ @provider.resource[:path] = ['/bogus/bin']
+ File.stubs(:exists?).returns(false)
+ File.stubs(:exists?).with("foo").returns(true)
+ File.stubs(:executable?).with("foo").returns(true)
+
+ Puppet::Util.expects(:execute).with() { |command, arguments| (command == ['foo bar --sillyarg=true --blah']) && (arguments.is_a? Hash) }
+ @provider.run("foo bar --sillyarg=true --blah")
+ end
+
+ it "should fail if quoted command doesn't exist" do
+ @provider.resource[:path] = ['/bogus/bin']
+ File.stubs(:exists?).returns(false)
+ File.stubs(:exists?).with("foo").returns(true)
+ File.stubs(:executable?).with("foo").returns(true)
+
+ lambda { @provider.run('"foo bar --sillyarg=true --blah"') }.should raise_error(ArgumentError, "Could not find command 'foo bar --sillyarg=true --blah'")
+ end
+
+ it "should execute the command if it finds it in the path and is executable" do
+ @provider.resource[:path] = ['/bogus/bin']
+ File.stubs(:exists?).with("foo").returns(true)
+ File.stubs(:executable?).with("foo").returns(true)
+ Puppet::Util.expects(:execute).with() { |command, arguments| (command == ['foo']) && (arguments.is_a? Hash) }
+
+ @provider.run("foo")
+ end
+
+ if feature == "microsoft_windows"
+ [".exe", ".ps1", ".bat", ".com", ""].each do |extension|
+ it "should check file extension #{extension} when it can't find the executable" do
+ @provider.resource[:path] = ['/bogus/bin']
+ File.stubs(:exists?).returns(false)
+ File.stubs(:exists?).with("/bogus/bin/foo#{extension}").returns(true)
+ File.stubs(:executable?).with("foo").returns(true)
+ Puppet::Util.expects(:execute).with() { |command, arguments| (command == ['foo']) && (arguments.is_a? Hash) }
+
+ @provider.run("foo")
+ end
+ end
+ end
+
+ it "should warn if you're overriding something in environment" do
+ @provider.resource[:environment] = ['WHATEVER=/something/else', 'WHATEVER=/foo']
+ File.stubs(:exists?).returns(false)
+ File.stubs(:exists?).with("foo").returns(true)
+ File.stubs(:executable?).with("foo").returns(true)
+
+ Puppet::Util.expects(:execute).with() { |command, arguments| (command == ['foo']) && (arguments.is_a? Hash) }
+ @provider.run("foo")
+ @logs.map {|l| "#{l.level}: #{l.message}" }.should == ["warning: Overriding environment setting 'WHATEVER' with '/foo'"]
+ end
+ end
+ end
+ end
+end
diff --git a/spec/unit/provider/exec/shell_spec.rb b/spec/unit/provider/exec/shell_spec.rb
new file mode 100644
index 000000000..4bae354c9
--- /dev/null
+++ b/spec/unit/provider/exec/shell_spec.rb
@@ -0,0 +1,50 @@
+#!/usr/bin/env ruby
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+provider_class = Puppet::Type.type(:exec).provider(:shell)
+
+describe provider_class do
+ before :each do
+ @resource = Puppet::Resource.new(:exec, 'foo')
+ @provider = provider_class.new(@resource)
+ end
+
+ describe "#run" do
+ it "should be able to run builtin shell commands" do
+ output, status = @provider.run("if [ 1 = 1 ]; then echo 'blah'; fi")
+ status.exitstatus.should == 0
+ output.should == "blah\n"
+ end
+
+ it "should be able to run commands with single quotes in them" do
+ output, status = @provider.run("echo 'foo bar'")
+ status.exitstatus.should == 0
+ output.should == "foo bar\n"
+ end
+
+ it "should be able to run commands with double quotes in them" do
+ output, status = @provider.run('echo "foo bar"')
+ status.exitstatus.should == 0
+ output.should == "foo bar\n"
+ end
+
+ it "should be able to run multiple commands separated by a semicolon" do
+ output, status = @provider.run("echo 'foo' ; echo 'bar'")
+ status.exitstatus.should == 0
+ output.should == "foo\nbar\n"
+ end
+
+ it "should be able to read values from the environment parameter" do
+ @resource[:environment] = "FOO=bar"
+ output, status = @provider.run("echo $FOO")
+ status.exitstatus.should == 0
+ output.should == "bar\n"
+ end
+ end
+
+ describe "#validatecmd" do
+ it "should always return true because builtins don't need path or to be fully qualified" do
+ @provider.validatecmd('whateverdoesntmatter').should == true
+ end
+ end
+end
diff --git a/spec/unit/provider/service/debian_spec.rb b/spec/unit/provider/service/debian_spec.rb
index 8dee2ee94..440d4491b 100755
--- a/spec/unit/provider/service/debian_spec.rb
+++ b/spec/unit/provider/service/debian_spec.rb
@@ -52,8 +52,20 @@ describe provider_class do
end
describe "when disabling" do
- it "should call update-rc.d twice" do
- @provider.expects(:update_rc).twice
+ it "should be able to disable services with newer sysv-rc versions" do
+ @provider.stubs(:`).with("dpkg --compare-versions $(dpkg-query -W --showformat '${Version}' sysv-rc) ge 2.88 ; echo $?").returns "0"
+
+ @provider.expects(:update_rc).with(@resource[:name], "disable")
+
+ @provider.disable
+ end
+
+ it "should be able to enable services with older sysv-rc versions" do
+ @provider.stubs(:`).with("dpkg --compare-versions $(dpkg-query -W --showformat '${Version}' sysv-rc) ge 2.88 ; echo $?").returns "1"
+
+ @provider.expects(:update_rc).with("-f", @resource[:name], "remove")
+ @provider.expects(:update_rc).with(@resource[:name], "stop", "00", "1", "2", "3", "4", "5", "6", ".")
+
@provider.disable
end
end
diff --git a/spec/unit/resource/type_collection_spec.rb b/spec/unit/resource/type_collection_spec.rb
index ff4c22234..cf7039a51 100644
--- a/spec/unit/resource/type_collection_spec.rb
+++ b/spec/unit/resource/type_collection_spec.rb
@@ -6,6 +6,7 @@ require 'puppet/resource/type_collection'
require 'puppet/resource/type'
describe Puppet::Resource::TypeCollection do
+ include PuppetSpec::Files
before do
@instance = Puppet::Resource::Type.new(:hostclass, "foo")
@code = Puppet::Resource::TypeCollection.new("env")
@@ -276,7 +277,7 @@ describe Puppet::Resource::TypeCollection do
end
end
-
+
it "should not look in the local scope for classes when the name is qualified" do
@loader = Puppet::Resource::TypeCollection.new("env")
@loader.add Puppet::Resource::Type.new(:hostclass, "foo::bar")
@@ -386,16 +387,11 @@ describe Puppet::Resource::TypeCollection do
describe "when performing initial import" do
before do
- @parser = stub 'parser', :file= => nil, :string => nil, :parse => nil
+ @parser = stub 'parser'
Puppet::Parser::Parser.stubs(:new).returns @parser
@code = Puppet::Resource::TypeCollection.new("env")
end
- it "should create a new parser instance" do
- Puppet::Parser::Parser.expects(:new).returns @parser
- @code.perform_initial_import
- end
-
it "should set the parser's string to the 'code' setting and parse if code is available" do
Puppet.settings[:code] = "my code"
@parser.expects(:string=).with "my code"
@@ -404,26 +400,27 @@ describe Puppet::Resource::TypeCollection do
end
it "should set the parser's file to the 'manifest' setting and parse if no code is available and the manifest is available" do
- File.stubs(:expand_path).with("/my/file").returns "/my/file"
- File.expects(:exist?).with("/my/file").returns true
- Puppet.settings[:manifest] = "/my/file"
- @parser.expects(:file=).with "/my/file"
+ filename = tmpfile('myfile')
+ File.open(filename, 'w'){|f| }
+ Puppet.settings[:manifest] = filename
+ @parser.expects(:file=).with filename
@parser.expects(:parse)
@code.perform_initial_import
end
- it "should not attempt to load a manifest if none is present" do
- File.stubs(:expand_path).with("/my/file").returns "/my/file"
- File.expects(:exist?).with("/my/file").returns false
- Puppet.settings[:manifest] = "/my/file"
- @parser.expects(:file=).never
- @parser.expects(:parse).never
+ it "should pass the manifest file to the parser even if it does not exist on disk" do
+ filename = tmpfile('myfile')
+ Puppet.settings[:code] = ""
+ Puppet.settings[:manifest] = filename
+ @parser.expects(:file=).with(filename).once
+ @parser.expects(:parse).once
@code.perform_initial_import
end
it "should fail helpfully if there is an error importing" do
File.stubs(:exist?).returns true
@parser.expects(:parse).raises ArgumentError
+ @parser.stubs(:file=)
lambda { @code.perform_initial_import }.should raise_error(Puppet::Error)
end
end
diff --git a/spec/unit/type/cron_spec.rb b/spec/unit/type/cron_spec.rb
index 03817d20e..f985cdd09 100755
--- a/spec/unit/type/cron_spec.rb
+++ b/spec/unit/type/cron_spec.rb
@@ -4,30 +4,478 @@ Dir.chdir(File.dirname(__FILE__)) { (s = lambda { |f| File.exist?(f) ? require(f
describe Puppet::Type.type(:cron) do
before do
- @cron = Puppet::Type.type(:cron).new( :name => "foo" )
- end
+ @class = Puppet::Type.type(:cron)
+
+ # Init a fake provider
+ @provider_class = stub 'provider_class', :ancestors => [], :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, :clean => nil
+ @provider.stubs(:is_a?).returns false
+ @provider_class.stubs(:new).returns @provider
- it "it should accept an :environment that looks like a path" do
- lambda do
- @cron[:environment] = 'PATH=/bin:/usr/bin:/usr/sbin'
- end.should_not raise_error
+ @cron = @class.new( :name => "foo" )
end
- it "should not accept environment variables that do not contain '='" do
- lambda do
- @cron[:environment] = "INVALID"
- end.should raise_error(Puppet::Error)
+ it "should have :name be its namevar" do
+ @class.key_attributes.should == [:name]
end
- it "should accept empty environment variables that do not contain '='" do
- lambda do
- @cron[:environment] = "MAILTO="
- end.should_not raise_error(Puppet::Error)
+ describe "when validating attributes" do
+
+ [:name, :provider].each do |param|
+ it "should have a #{param} parameter" do
+ @class.attrtype(param).should == :param
+ end
+ end
+
+ [:command, :special, :minute, :hour, :weekday, :month, :monthday, :environment, :user, :target].each do |property|
+ it "should have a #{property} property" do
+ @class.attrtype(property).should == :property
+ end
+ end
+
+ [:command, :minute, :hour, :weekday, :month, :monthday].each do |cronparam|
+ it "should have #{cronparam} of type CronParam" do
+ @class.attrclass(cronparam).ancestors.should include CronParam
+ end
+ end
+
end
- it "should accept 'absent'" do
- lambda do
- @cron[:environment] = 'absent'
- end.should_not raise_error(Puppet::Error)
+
+ describe "when validating attribute" do
+
+ describe "ensure" do
+ it "should support present as a value for ensure" do
+ proc { @class.new(:name => 'foo', :ensure => :present) }.should_not raise_error
+ end
+
+ it "should support absent as a value for ensure" do
+ proc { @class.new(:name => 'foo', :ensure => :present) }.should_not raise_error
+ end
+ end
+
+ describe "minute" do
+
+ it "should support absent" do
+ proc { @class.new(:name => 'foo', :minute => 'absent') }.should_not raise_error
+ end
+
+ it "should support *" do
+ proc { @class.new(:name => 'foo', :minute => '*') }.should_not raise_error
+ end
+
+ it "should translate absent to :absent" do
+ @class.new(:name => 'foo', :minute => 'absent')[:minute].should == :absent
+ end
+
+ it "should translate * to :absent" do
+ @class.new(:name => 'foo', :minute => '*')[:minute].should == :absent
+ end
+
+ it "should support valid single values" do
+ proc { @class.new(:name => 'foo', :minute => '0') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :minute => '1') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :minute => '59') }.should_not raise_error
+ end
+
+ it "should not support non numeric characters" do
+ proc { @class.new(:name => 'foo', :minute => 'z59') }.should raise_error(Puppet::Error)
+ proc { @class.new(:name => 'foo', :minute => '5z9') }.should raise_error(Puppet::Error)
+ proc { @class.new(:name => 'foo', :minute => '59z') }.should raise_error(Puppet::Error)
+ end
+
+ it "should not support single values out of range" do
+
+ proc { @class.new(:name => 'foo', :minute => '-1') }.should raise_error(Puppet::Error)
+ proc { @class.new(:name => 'foo', :minute => '60') }.should raise_error(Puppet::Error)
+ proc { @class.new(:name => 'foo', :minute => '61') }.should raise_error(Puppet::Error)
+ proc { @class.new(:name => 'foo', :minute => '120') }.should raise_error(Puppet::Error)
+ end
+
+ it "should support valid multiple values" do
+ proc { @class.new(:name => 'foo', :minute => ['0','1','59'] ) }.should_not raise_error
+ proc { @class.new(:name => 'foo', :minute => ['40','30','20'] ) }.should_not raise_error
+ proc { @class.new(:name => 'foo', :minute => ['10','30','20'] ) }.should_not raise_error
+ end
+
+ it "should not support multiple values if at least one is invalid" do
+ # one invalid
+ proc { @class.new(:name => 'foo', :minute => ['0','1','60'] ) }.should raise_error(Puppet::Error)
+ proc { @class.new(:name => 'foo', :minute => ['0','120','59'] ) }.should raise_error(Puppet::Error)
+ proc { @class.new(:name => 'foo', :minute => ['-1','1','59'] ) }.should raise_error(Puppet::Error)
+ # two invalid
+ proc { @class.new(:name => 'foo', :minute => ['0','61','62'] ) }.should raise_error(Puppet::Error)
+ # all invalid
+ proc { @class.new(:name => 'foo', :minute => ['-1','61','62'] ) }.should raise_error(Puppet::Error)
+ end
+
+ it "should support valid step syntax" do
+ proc { @class.new(:name => 'foo', :minute => '*/2' ) }.should_not raise_error
+ proc { @class.new(:name => 'foo', :minute => '10-16/2' ) }.should_not raise_error
+ end
+
+ it "should not support invalid steps" do
+ proc { @class.new(:name => 'foo', :minute => '*/A' ) }.should raise_error(Puppet::Error)
+ proc { @class.new(:name => 'foo', :minute => '*/2A' ) }.should raise_error(Puppet::Error)
+ # As it turns out cron does not complaining about steps that exceed the valid range
+ # proc { @class.new(:name => 'foo', :minute => '*/120' ) }.should raise_error(Puppet::Error)
+ end
+
+ end
+
+ describe "hour" do
+
+ it "should support absent" do
+ proc { @class.new(:name => 'foo', :hour => 'absent') }.should_not raise_error
+ end
+
+ it "should support *" do
+ proc { @class.new(:name => 'foo', :hour => '*') }.should_not raise_error
+ end
+
+ it "should translate absent to :absent" do
+ @class.new(:name => 'foo', :hour => 'absent')[:hour].should == :absent
+ end
+
+ it "should translate * to :absent" do
+ @class.new(:name => 'foo', :hour => '*')[:hour].should == :absent
+ end
+
+ it "should support valid single values" do
+ proc { @class.new(:name => 'foo', :hour => '0') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :hour => '11') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :hour => '12') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :hour => '13') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :hour => '23') }.should_not raise_error
+ end
+
+ it "should not support non numeric characters" do
+ proc { @class.new(:name => 'foo', :hour => 'z15') }.should raise_error(Puppet::Error)
+ proc { @class.new(:name => 'foo', :hour => '1z5') }.should raise_error(Puppet::Error)
+ proc { @class.new(:name => 'foo', :hour => '15z') }.should raise_error(Puppet::Error)
+ end
+
+ it "should not support single values out of range" do
+ proc { @class.new(:name => 'foo', :hour => '-1') }.should raise_error(Puppet::Error)
+ proc { @class.new(:name => 'foo', :hour => '24') }.should raise_error(Puppet::Error)
+ proc { @class.new(:name => 'foo', :hour => '120') }.should raise_error(Puppet::Error)
+ end
+
+ it "should support valid multiple values" do
+ proc { @class.new(:name => 'foo', :hour => ['0','1','23'] ) }.should_not raise_error
+ proc { @class.new(:name => 'foo', :hour => ['5','16','14'] ) }.should_not raise_error
+ proc { @class.new(:name => 'foo', :hour => ['16','13','9'] ) }.should_not raise_error
+ end
+
+ it "should not support multiple values if at least one is invalid" do
+ # one invalid
+ proc { @class.new(:name => 'foo', :hour => ['0','1','24'] ) }.should raise_error(Puppet::Error)
+ proc { @class.new(:name => 'foo', :hour => ['0','-1','5'] ) }.should raise_error(Puppet::Error)
+ proc { @class.new(:name => 'foo', :hour => ['-1','1','23'] ) }.should raise_error(Puppet::Error)
+ # two invalid
+ proc { @class.new(:name => 'foo', :hour => ['0','25','26'] ) }.should raise_error(Puppet::Error)
+ # all invalid
+ proc { @class.new(:name => 'foo', :hour => ['-1','24','120'] ) }.should raise_error(Puppet::Error)
+ end
+
+ it "should support valid step syntax" do
+ proc { @class.new(:name => 'foo', :hour => '*/2' ) }.should_not raise_error
+ proc { @class.new(:name => 'foo', :hour => '10-18/4' ) }.should_not raise_error
+ end
+
+ it "should not support invalid steps" do
+ proc { @class.new(:name => 'foo', :hour => '*/A' ) }.should raise_error(Puppet::Error)
+ proc { @class.new(:name => 'foo', :hour => '*/2A' ) }.should raise_error(Puppet::Error)
+ # As it turns out cron does not complaining about steps that exceed the valid range
+ # proc { @class.new(:name => 'foo', :hour => '*/26' ) }.should raise_error(Puppet::Error)
+ end
+
+ end
+
+ describe "weekday" do
+
+ it "should support absent" do
+ proc { @class.new(:name => 'foo', :weekday => 'absent') }.should_not raise_error
+ end
+
+ it "should support *" do
+ proc { @class.new(:name => 'foo', :weekday => '*') }.should_not raise_error
+ end
+
+ it "should translate absent to :absent" do
+ @class.new(:name => 'foo', :weekday => 'absent')[:weekday].should == :absent
+ end
+
+ it "should translate * to :absent" do
+ @class.new(:name => 'foo', :weekday => '*')[:weekday].should == :absent
+ end
+
+ it "should support valid numeric weekdays" do
+ proc { @class.new(:name => 'foo', :weekday => '0') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :weekday => '1') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :weekday => '6') }.should_not raise_error
+ # According to http://www.manpagez.com/man/5/crontab 7 is also valid (Sunday)
+ proc { @class.new(:name => 'foo', :weekday => '7') }.should_not raise_error
+ end
+
+ it "should support valid weekdays as words (3 character version)" do
+ proc { @class.new(:name => 'foo', :weekday => 'Monday') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :weekday => 'Tuesday') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :weekday => 'Wednesday') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :weekday => 'Thursday') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :weekday => 'Friday') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :weekday => 'Saturday') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :weekday => 'Sunday') }.should_not raise_error
+ end
+
+ it "should support valid weekdays as words (3 character version)" do
+ proc { @class.new(:name => 'foo', :weekday => 'Mon') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :weekday => 'Tue') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :weekday => 'Wed') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :weekday => 'Thu') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :weekday => 'Fri') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :weekday => 'Sat') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :weekday => 'Sun') }.should_not raise_error
+ end
+
+ it "should not support numeric values out of range" do
+ proc { @class.new(:name => 'foo', :weekday => '-1') }.should raise_error(Puppet::Error)
+ proc { @class.new(:name => 'foo', :weekday => '8') }.should raise_error(Puppet::Error)
+ end
+
+ it "should not support invalid weekday names" do
+ proc { @class.new(:name => 'foo', :weekday => 'Sar') }.should raise_error(Puppet::Error)
+ end
+
+ it "should support valid multiple values" do
+ proc { @class.new(:name => 'foo', :weekday => ['0','1','6'] ) }.should_not raise_error
+ proc { @class.new(:name => 'foo', :weekday => ['Mon','Wed','Friday'] ) }.should_not raise_error
+ end
+
+ it "should not support multiple values if at least one is invalid" do
+ # one invalid
+ proc { @class.new(:name => 'foo', :weekday => ['0','1','8'] ) }.should raise_error(Puppet::Error)
+ proc { @class.new(:name => 'foo', :weekday => ['Mon','Fii','Sat'] ) }.should raise_error(Puppet::Error)
+ # two invalid
+ proc { @class.new(:name => 'foo', :weekday => ['Mos','Fii','Sat'] ) }.should raise_error(Puppet::Error)
+ # all invalid
+ proc { @class.new(:name => 'foo', :weekday => ['Mos','Fii','Saa'] ) }.should raise_error(Puppet::Error)
+ proc { @class.new(:name => 'foo', :weekday => ['-1','8','11'] ) }.should raise_error(Puppet::Error)
+ end
+
+ it "should support valid step syntax" do
+ proc { @class.new(:name => 'foo', :weekday => '*/2' ) }.should_not raise_error
+ proc { @class.new(:name => 'foo', :weekday => '0-4/2' ) }.should_not raise_error
+ end
+
+ it "should not support invalid steps" do
+ proc { @class.new(:name => 'foo', :weekday => '*/A' ) }.should raise_error(Puppet::Error)
+ proc { @class.new(:name => 'foo', :weekday => '*/2A' ) }.should raise_error(Puppet::Error)
+ # As it turns out cron does not complaining about steps that exceed the valid range
+ # proc { @class.new(:name => 'foo', :weekday => '*/9' ) }.should raise_error(Puppet::Error)
+ end
+
+ end
+
+ describe "month" do
+
+ it "should support absent" do
+ proc { @class.new(:name => 'foo', :month => 'absent') }.should_not raise_error
+ end
+
+ it "should support *" do
+ proc { @class.new(:name => 'foo', :month => '*') }.should_not raise_error
+ end
+
+ it "should translate absent to :absent" do
+ @class.new(:name => 'foo', :month => 'absent')[:month].should == :absent
+ end
+
+ it "should translate * to :absent" do
+ @class.new(:name => 'foo', :month => '*')[:month].should == :absent
+ end
+
+ it "should support valid numeric values" do
+ proc { @class.new(:name => 'foo', :month => '1') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :month => '12') }.should_not raise_error
+ end
+
+ it "should support valid months as words" do
+ proc { @class.new(:name => 'foo', :month => 'January') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :month => 'February') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :month => 'March') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :month => 'April') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :month => 'May') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :month => 'June') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :month => 'July') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :month => 'August') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :month => 'September') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :month => 'October') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :month => 'November') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :month => 'December') }.should_not raise_error
+ end
+
+ it "should support valid months as words (3 character short version)" do
+ proc { @class.new(:name => 'foo', :month => 'Jan') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :month => 'Feb') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :month => 'Mar') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :month => 'Apr') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :month => 'May') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :month => 'Jun') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :month => 'Jul') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :month => 'Aug') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :month => 'Sep') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :month => 'Oct') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :month => 'Nov') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :month => 'Dec') }.should_not raise_error
+ end
+
+ it "should not support numeric values out of range" do
+ proc { @class.new(:name => 'foo', :month => '-1') }.should raise_error(Puppet::Error)
+ proc { @class.new(:name => 'foo', :month => '0') }.should raise_error(Puppet::Error)
+ proc { @class.new(:name => 'foo', :month => '13') }.should raise_error(Puppet::Error)
+ end
+
+ it "should not support words that are not valid months" do
+ proc { @class.new(:name => 'foo', :month => 'Jal') }.should raise_error(Puppet::Error)
+ end
+
+ it "should not support single values out of range" do
+
+ proc { @class.new(:name => 'foo', :month => '-1') }.should raise_error(Puppet::Error)
+ proc { @class.new(:name => 'foo', :month => '60') }.should raise_error(Puppet::Error)
+ proc { @class.new(:name => 'foo', :month => '61') }.should raise_error(Puppet::Error)
+ proc { @class.new(:name => 'foo', :month => '120') }.should raise_error(Puppet::Error)
+ end
+
+ it "should support valid multiple values" do
+ proc { @class.new(:name => 'foo', :month => ['1','9','12'] ) }.should_not raise_error
+ proc { @class.new(:name => 'foo', :month => ['Jan','March','Jul'] ) }.should_not raise_error
+ end
+
+ it "should not support multiple values if at least one is invalid" do
+ # one invalid
+ proc { @class.new(:name => 'foo', :month => ['0','1','12'] ) }.should raise_error(Puppet::Error)
+ proc { @class.new(:name => 'foo', :month => ['1','13','10'] ) }.should raise_error(Puppet::Error)
+ proc { @class.new(:name => 'foo', :month => ['Jan','Feb','Jxx'] ) }.should raise_error(Puppet::Error)
+ # two invalid
+ proc { @class.new(:name => 'foo', :month => ['Jan','Fex','Jux'] ) }.should raise_error(Puppet::Error)
+ # all invalid
+ proc { @class.new(:name => 'foo', :month => ['-1','0','13'] ) }.should raise_error(Puppet::Error)
+ proc { @class.new(:name => 'foo', :month => ['Jax','Fex','Aux'] ) }.should raise_error(Puppet::Error)
+ end
+
+ it "should support valid step syntax" do
+ proc { @class.new(:name => 'foo', :month => '*/2' ) }.should_not raise_error
+ proc { @class.new(:name => 'foo', :month => '1-12/3' ) }.should_not raise_error
+ end
+
+ it "should not support invalid steps" do
+ proc { @class.new(:name => 'foo', :month => '*/A' ) }.should raise_error(Puppet::Error)
+ proc { @class.new(:name => 'foo', :month => '*/2A' ) }.should raise_error(Puppet::Error)
+ # As it turns out cron does not complaining about steps that exceed the valid range
+ # proc { @class.new(:name => 'foo', :month => '*/13' ) }.should raise_error(Puppet::Error)
+ end
+
+ end
+
+ describe "monthday" do
+
+ it "should support absent" do
+ proc { @class.new(:name => 'foo', :monthday => 'absent') }.should_not raise_error
+ end
+
+ it "should support *" do
+ proc { @class.new(:name => 'foo', :monthday => '*') }.should_not raise_error
+ end
+
+ it "should translate absent to :absent" do
+ @class.new(:name => 'foo', :monthday => 'absent')[:monthday].should == :absent
+ end
+
+ it "should translate * to :absent" do
+ @class.new(:name => 'foo', :monthday => '*')[:monthday].should == :absent
+ end
+
+ it "should support valid single values" do
+ proc { @class.new(:name => 'foo', :monthday => '1') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :monthday => '30') }.should_not raise_error
+ proc { @class.new(:name => 'foo', :monthday => '31') }.should_not raise_error
+ end
+
+ it "should not support non numeric characters" do
+ proc { @class.new(:name => 'foo', :monthday => 'z23') }.should raise_error(Puppet::Error)
+ proc { @class.new(:name => 'foo', :monthday => '2z3') }.should raise_error(Puppet::Error)
+ proc { @class.new(:name => 'foo', :monthday => '23z') }.should raise_error(Puppet::Error)
+ end
+
+ it "should not support single values out of range" do
+ proc { @class.new(:name => 'foo', :monthday => '-1') }.should raise_error(Puppet::Error)
+ proc { @class.new(:name => 'foo', :monthday => '0') }.should raise_error(Puppet::Error)
+ proc { @class.new(:name => 'foo', :monthday => '32') }.should raise_error(Puppet::Error)
+ end
+
+ it "should support valid multiple values" do
+ proc { @class.new(:name => 'foo', :monthday => ['1','23','31'] ) }.should_not raise_error
+ proc { @class.new(:name => 'foo', :monthday => ['31','23','1'] ) }.should_not raise_error
+ proc { @class.new(:name => 'foo', :monthday => ['1','31','23'] ) }.should_not raise_error
+ end
+
+ it "should not support multiple values if at least one is invalid" do
+ # one invalid
+ proc { @class.new(:name => 'foo', :monthday => ['1','23','32'] ) }.should raise_error(Puppet::Error)
+ proc { @class.new(:name => 'foo', :monthday => ['-1','12','23'] ) }.should raise_error(Puppet::Error)
+ proc { @class.new(:name => 'foo', :monthday => ['13','32','30'] ) }.should raise_error(Puppet::Error)
+ # two invalid
+ proc { @class.new(:name => 'foo', :monthday => ['-1','0','23'] ) }.should raise_error(Puppet::Error)
+ # all invalid
+ proc { @class.new(:name => 'foo', :monthday => ['-1','0','32'] ) }.should raise_error(Puppet::Error)
+ end
+
+ it "should support valid step syntax" do
+ proc { @class.new(:name => 'foo', :monthday => '*/2' ) }.should_not raise_error
+ proc { @class.new(:name => 'foo', :monthday => '10-16/2' ) }.should_not raise_error
+ end
+
+ it "should not support invalid steps" do
+ proc { @class.new(:name => 'foo', :monthday => '*/A' ) }.should raise_error(Puppet::Error)
+ proc { @class.new(:name => 'foo', :monthday => '*/2A' ) }.should raise_error(Puppet::Error)
+ # As it turns out cron does not complaining about steps that exceed the valid range
+ # proc { @class.new(:name => 'foo', :monthday => '*/32' ) }.should raise_error(Puppet::Error)
+ end
+
+ end
+
+ describe "environment" do
+
+ it "it should accept an :environment that looks like a path" do
+ lambda do
+ @cron[:environment] = 'PATH=/bin:/usr/bin:/usr/sbin'
+ end.should_not raise_error
+ end
+
+ it "should not accept environment variables that do not contain '='" do
+ lambda do
+ @cron[:environment] = "INVALID"
+ end.should raise_error(Puppet::Error)
+ end
+
+ it "should accept empty environment variables that do not contain '='" do
+ lambda do
+ @cron[:environment] = "MAILTO="
+ end.should_not raise_error(Puppet::Error)
+ end
+
+ it "should accept 'absent'" do
+ lambda do
+ @cron[:environment] = 'absent'
+ end.should_not raise_error(Puppet::Error)
+ end
+
+ end
+
end
end
diff --git a/spec/unit/type/exec_spec.rb b/spec/unit/type/exec_spec.rb
index e04cfc065..e155506b0 100755
--- a/spec/unit/type/exec_spec.rb
+++ b/spec/unit/type/exec_spec.rb
@@ -1,162 +1,689 @@
#!/usr/bin/env ruby
-
require File.dirname(__FILE__) + '/../../spec_helper'
describe Puppet::Type.type(:exec) do
-
- def create_resource(command, output, exitstatus, returns = 0)
- @user_name = 'some_user_name'
+ def exec_tester(command, exitstatus = 0, rest = {})
+ @user_name = 'some_user_name'
@group_name = 'some_group_name'
Puppet.features.stubs(:root?).returns(true)
- @execer = Puppet::Type.type(:exec).new(:name => command, :path => @example_path, :user => @user_name, :group => @group_name, :returns => returns)
- status = stub "process"
- status.stubs(:exitstatus).returns(exitstatus)
+ output = rest.delete(:output) || ''
+ tries = rest[:tries] || 1
+
+ args = {
+ :name => command,
+ :path => @example_path,
+ :user => @user_name,
+ :group => @group_name,
+ :logoutput => false,
+ :loglevel => :err,
+ :returns => 0
+ }.merge(rest)
+
+ exec = Puppet::Type.type(:exec).new(args)
- Puppet::Util::SUIDManager.expects(:run_and_capture).with([command], @user_name, @group_name).returns([output, status])
+ status = stub "process", :exitstatus => exitstatus
+ Puppet::Util::SUIDManager.expects(:run_and_capture).times(tries).
+ with([command], @user_name, @group_name).returns([output, status])
+
+ return exec
end
- def create_logging_resource(command, output, exitstatus, logoutput, loglevel, returns = 0)
- create_resource(command, output, exitstatus, returns)
- @execer[:logoutput] = logoutput
- @execer[:loglevel] = loglevel
+ before do
+ @command = Puppet.features.posix? ? '/bin/true whatever' : '"C:/Program Files/something.exe" whatever'
end
- def expect_output(output, loglevel)
- output.split(/\n/).each do |line|
- @execer.property(:returns).expects(loglevel).with(line)
+ describe "when not stubbing the provider" do
+ before do
+ @executable = Puppet.features.posix? ? '/bin/true' : 'C:/Program Files/something.exe'
+ File.stubs(:exists?).returns false
+ File.stubs(:exists?).with(@executable).returns true
+ File.stubs(:exists?).with('/bin/false').returns true
+ @example_path = Puppet.features.posix? ? %w{/usr/bin /bin} : [ "C:/Program Files/something/bin", "C:/Ruby/bin" ]
+ File.stubs(:exists?).with(File.join(@example_path[0],"true")).returns true
+ File.stubs(:exists?).with(File.join(@example_path[0],"false")).returns true
+ end
+
+ it "should return :executed_command as its event" do
+ resource = Puppet::Type.type(:exec).new :command => @command
+ resource.parameter(:returns).event.name.should == :executed_command
+ end
+
+ describe "when execing" do
+ it "should use the 'run_and_capture' method to exec" do
+ exec_tester("true").refresh.should == :executed_command
+ end
+
+ it "should report a failure" do
+ proc { exec_tester('false', 1).refresh }.
+ should raise_error(Puppet::Error, /^false returned 1 instead of/)
+ end
+
+ it "should not report a failure if the exit status is specified in a returns array" do
+ proc { exec_tester("false", 1, :returns => [0, 1]).refresh }.should_not raise_error
+ end
+
+ it "should report a failure if the exit status is not specified in a returns array" do
+ proc { exec_tester('false', 1, :returns => [0, 100]).refresh }.
+ should raise_error(Puppet::Error, /^false returned 1 instead of/)
+ end
+
+ it "should log the output on success" do
+ output = "output1\noutput2\n"
+ exec_tester('false', 0, :output => output, :logoutput => true).refresh
+ output.split("\n").each do |line|
+ log = @logs.shift
+ log.level.should == :err
+ log.message.should == line
+ end
+ end
+
+ it "should log the output on failure" do
+ output = "output1\noutput2\n"
+ proc { exec_tester('false', 1, :output => output, :logoutput => true).refresh }.
+ should raise_error(Puppet::Error)
+
+ output.split("\n").each do |line|
+ log = @logs.shift
+ log.level.should == :err
+ log.message.should == line
+ end
+ end
+ end
+
+ describe "when logoutput=>on_failure is set" do
+ it "should log the output on failure" do
+ output = "output1\noutput2\n"
+ proc { exec_tester('false', 1, :output => output, :logoutput => :on_failure).refresh }.
+ should raise_error(Puppet::Error, /^false returned 1 instead of/)
+
+ output.split("\n").each do |line|
+ log = @logs.shift
+ log.level.should == :err
+ log.message.should == line
+ end
+ end
+
+ it "should log the output on failure when returns is specified as an array" do
+ output = "output1\noutput2\n"
+
+ proc {
+ exec_tester('false', 1, :output => output, :returns => [0, 100],
+ :logoutput => :on_failure).refresh
+ }.should raise_error(Puppet::Error, /^false returned 1 instead of/)
+
+ output.split("\n").each do |line|
+ log = @logs.shift
+ log.level.should == :err
+ log.message.should == line
+ end
+ end
+
+ it "shouldn't log the output on success" do
+ exec_tester('true', 0, :output => "a\nb\nc\n", :logoutput => :on_failure).refresh
+ @logs.should == []
+ end
+ end
+
+ it "shouldn't log the output on success when non-zero exit status is in a returns array" do
+ exec_tester("true", 100, :output => "a\n", :logoutput => :on_failure, :returns => [1, 100]).refresh
+ @logs.should == []
+ end
+
+ describe " when multiple tries are set," do
+ it "should repeat the command attempt 'tries' times on failure and produce an error" do
+ tries = 5
+ resource = exec_tester("false", 1, :tries => tries, :try_sleep => 0)
+ proc { resource.refresh }.should raise_error(Puppet::Error)
+ end
end
end
- before do
- @executable = Puppet.features.posix? ? '/bin/true' : 'C:/Program Files/something.exe'
- @command = Puppet.features.posix? ? '/bin/true whatever' : '"C:/Program Files/something.exe" whatever'
- File.stubs(:exists?).returns false
- File.stubs(:exists?).with(@executable).returns true
- @example_path = Puppet.features.posix? ? %w{/usr/bin /bin} : [ "C:/Program Files/something/bin", "C:/Ruby/bin" ]
- File.stubs(:exists?).with(File.join(@example_path[0],"true")).returns true
- File.stubs(:exists?).with(File.join(@example_path[0],"false")).returns true
+ it "should be able to autorequire files mentioned in the command" do
+ catalog = Puppet::Resource::Catalog.new
+ tmp = Puppet::Type.type(:file).new(:name => "/bin/foo")
+ catalog.add_resource tmp
+ execer = Puppet::Type.type(:exec).new(:name => "/bin/foo")
+ catalog.add_resource execer
+
+ catalog.relationship_graph.dependencies(execer).should == [tmp]
end
- it "should return :executed_command as its event" do
- resource = Puppet::Type.type(:exec).new :command => @command
- resource.parameter(:returns).event.name.should == :executed_command
+ describe "when handling the path parameter" do
+ expect = %w{one two three four}
+ { "an array" => expect,
+ "a colon separated list" => "one:two:three:four",
+ "a semi-colon separated list" => "one;two;three;four",
+ "both array and colon lists" => ["one", "two:three", "four"],
+ "both array and semi-colon lists" => ["one", "two;three", "four"],
+ "colon and semi-colon lists" => ["one:two", "three;four"]
+ }.each do |test, input|
+ it "should accept #{test}" do
+ type = Puppet::Type.type(:exec).new(:name => @command, :path => input)
+ type[:path].should == expect
+ end
+ end
end
- describe "when execing" do
+ describe "when setting user" do
+ it "should fail if we are not root" do
+ Puppet.features.stubs(:root?).returns(false)
+ expect { Puppet::Type.type(:exec).new(:name => @command, :user => 'input') }.
+ should raise_error Puppet::Error, /Parameter user failed/
+ end
- it "should use the 'run_and_capture' method to exec" do
- command = "true"
- create_resource(command, "", 0)
+ ['one', 2, 'root', 4294967295, 4294967296].each do |value|
+ it "should accept '#{value}' as user if we are root" do
+ Puppet.features.stubs(:root?).returns(true)
+ type = Puppet::Type.type(:exec).new(:name => @command, :user => value)
+ type[:user].should == value
+ end
+ end
+ end
- @execer.refresh.should == :executed_command
+ describe "when setting group" do
+ shared_examples_for "exec[:group]" do
+ ['one', 2, 'wheel', 4294967295, 4294967296].each do |value|
+ it "should accept '#{value}' without error or judgement" do
+ type = Puppet::Type.type(:exec).new(:name => @command, :group => value)
+ type[:group].should == value
+ end
+ end
end
- it "should report a failure" do
- command = "false"
- create_resource(command, "", 1)
+ describe "when running as root" do
+ before :each do Puppet.features.stubs(:root?).returns(true) end
+ it_behaves_like "exec[:group]"
+ end
+
+ describe "when not running as root" do
+ before :each do Puppet.features.stubs(:root?).returns(false) end
+ it_behaves_like "exec[:group]"
+ end
+ end
+
+ describe "when setting cwd" do
+ it_should_behave_like "all path parameters", :cwd, :array => false do
+ def instance(path)
+ Puppet::Type.type(:exec).new(:name => '/bin/true', :cwd => path)
+ end
+ end
+ end
+
+ shared_examples_for "all exec command parameters" do |param|
+ { "relative" => "example", "absolute" => "/bin/example" }.sort.each do |name, command|
+ describe "if command is #{name}" do
+ before :each do
+ @param = param
+ end
- proc { @execer.refresh }.should raise_error(Puppet::Error)
+ def test(command, valid)
+ if @param == :name then
+ instance = Puppet::Type.type(:exec).new()
+ else
+ instance = Puppet::Type.type(:exec).new(:name => "/bin/true")
+ end
+ if valid then
+ instance.provider.expects(:validatecmd).returns(true)
+ else
+ instance.provider.expects(:validatecmd).raises(Puppet::Error, "from a stub")
+ end
+ instance[@param] = command
+ end
+
+ it "should work if the provider calls the command valid" do
+ expect { test(command, true) }.should_not raise_error
+ end
+
+ it "should fail if the provider calls the command invalid" do
+ expect { test(command, false) }.
+ should raise_error Puppet::Error, /Parameter #{@param} failed: from a stub/
+ end
+ end
end
+ end
+
+ shared_examples_for "all exec command parameters that take arrays" do |param|
+ describe "when given an array of inputs" do
+ before :each do
+ @test = Puppet::Type.type(:exec).new(:name => "/bin/true")
+ end
- it "should not report a failure if the exit status is specified in a returns array" do
- command = "false"
- create_resource(command, "", 1, [0,1])
- proc { @execer.refresh }.should_not raise_error(Puppet::Error)
+ it "should accept the array when all commands return valid" do
+ input = %w{one two three}
+ @test.provider.expects(:validatecmd).times(input.length).returns(true)
+ @test[param] = input
+ @test[param].should == input
+ end
+
+ it "should reject the array when any commands return invalid" do
+ input = %w{one two three}
+ @test.provider.expects(:validatecmd).with(input.first).returns(false)
+ input[1..-1].each do |cmd|
+ @test.provider.expects(:validatecmd).with(cmd).returns(true)
+ end
+ @test[param] = input
+ @test[param].should == input
+ end
+
+ it "should reject the array when all commands return invalid" do
+ input = %w{one two three}
+ @test.provider.expects(:validatecmd).times(input.length).returns(false)
+ @test[param] = input
+ @test[param].should == input
+ end
end
+ end
- it "should report a failure if the exit status is not specified in a returns array" do
- command = "false"
- create_resource(command, "", 1, [0,100])
- proc { @execer.refresh }.should raise_error(Puppet::Error)
+ describe "when setting refresh" do
+ it_should_behave_like "all exec command parameters", :refresh
+ end
+
+ describe "for simple parameters" do
+ before :each do
+ @exec = Puppet::Type.type(:exec).new(:name => '/bin/true')
end
- it "should log the output on success" do
- #Puppet::Util::Log.newdestination :console
- command = "false"
- output = "output1\noutput2\n"
- create_logging_resource(command, output, 0, true, :err)
- expect_output(output, :err)
- @execer.refresh
+ describe "when setting env" do
+ it "should issue a deprecation warning" do
+ expect { @exec[:env] = 'foo=bar' }.should_not raise_error
+ @logs.first.message.should =~ /deprecate.*environment/
+ end
+
+ it "should update the value of env" do
+ data = ['foo=bar']
+ @exec[:env] = data
+ @exec[:env].should == data
+ end
+
+ it "should forward to environment" do
+ data = ['foo=bar']
+ @exec[:env] = data
+ @exec[:environment].should == data
+ end
+
+ it "should not override environment if both are set" do
+ pending "can't fix: too disruptive for 2.6, removed in 2.7"
+ # ...so this test is here to validate that we know about the problem.
+ # This ensures correct order of evaluation to trigger the bug; don't
+ # count on this happening in the constructor. --daniel 2011-03-01
+ @exec[:environment] = 'environment=true'
+ @exec[:env] = 'env=true'
+
+ @exec[:environment].should == "environment=true"
+ end
end
- it "should log the output on failure" do
- #Puppet::Util::Log.newdestination :console
- command = "false"
- output = "output1\noutput2\n"
- create_logging_resource(command, output, 1, true, :err)
- expect_output(output, :err)
+ describe "when setting environment" do
+ { "single values" => "foo=bar",
+ "multiple values" => ["foo=bar", "baz=quux"],
+ }.each do |name, data|
+ it "should accept #{name}" do
+ @exec[:environment] = data
+ @exec[:environment].should == data
+ end
+ end
- proc { @execer.refresh }.should raise_error(Puppet::Error)
+ { "single values" => "foo",
+ "only values" => ["foo", "bar"],
+ "any values" => ["foo=bar", "baz"]
+ }.each do |name, data|
+ it "should reject #{name} without assignment" do
+ expect { @exec[:environment] = data }.
+ should raise_error Puppet::Error, /Invalid environment setting/
+ end
+ end
end
+ describe "when setting timeout" do
+ [0, 0.1, 1, 10, 4294967295].each do |valid|
+ it "should accept '#{valid}' as valid" do
+ @exec[:timeout] = valid
+ @exec[:timeout].should == valid
+ end
+
+ it "should accept '#{valid}' in an array as valid" do
+ @exec[:timeout] = [valid]
+ @exec[:timeout].should == valid
+ end
+ end
+
+ ['1/2', '', 'foo', '5foo'].each do |invalid|
+ it "should reject '#{invalid}' as invalid" do
+ expect { @exec[:timeout] = invalid }.
+ should raise_error Puppet::Error, /The timeout must be a number/
+ end
+
+ it "should reject '#{invalid}' in an array as invalid" do
+ expect { @exec[:timeout] = [invalid] }.
+ should raise_error Puppet::Error, /The timeout must be a number/
+ end
+ end
+
+ it "should fail if timeout is exceeded" do
+ File.stubs(:exists?).with('/bin/sleep').returns(true)
+ File.stubs(:exists?).with('sleep').returns(false)
+ sleep_exec = Puppet::Type.type(:exec).new(:name => 'sleep 1', :path => ['/bin'], :timeout => '0.2')
+ lambda { sleep_exec.refresh }.should raise_error Puppet::Error, "Command exceeded timeout"
+ end
+
+ it "should convert timeout to a float" do
+ resource = Puppet::Type.type(:exec).new :command => "/bin/false", :timeout => "12"
+ resource[:timeout].should be_a(Float)
+ resource[:timeout].should == 12.0
+ end
+
+ it "should munge negative timeouts to 0.0" do
+ resource = Puppet::Type.type(:exec).new :command => "/bin/false", :timeout => "-12.0"
+ resource.parameter(:timeout).value.should be_a(Float)
+ resource.parameter(:timeout).value.should == 0.0
+ end
+ end
+
+ describe "when setting tries" do
+ [1, 10, 4294967295].each do |valid|
+ it "should accept '#{valid}' as valid" do
+ @exec[:tries] = valid
+ @exec[:tries].should == valid
+ end
+
+ if "REVISIT: too much test log spam" == "a good thing" then
+ it "should accept '#{valid}' in an array as valid" do
+ pending "inconsistent, but this is not supporting arrays, unlike timeout"
+ @exec[:tries] = [valid]
+ @exec[:tries].should == valid
+ end
+ end
+ end
+
+ [-3.5, -1, 0, 0.2, '1/2', '1_000_000', '+12', '', 'foo'].each do |invalid|
+ it "should reject '#{invalid}' as invalid" do
+ expect { @exec[:tries] = invalid }.
+ should raise_error Puppet::Error, /Tries must be an integer/
+ end
+
+ if "REVISIT: too much test log spam" == "a good thing" then
+ it "should reject '#{invalid}' in an array as invalid" do
+ pending "inconsistent, but this is not supporting arrays, unlike timeout"
+ expect { @exec[:tries] = [invalid] }.
+ should raise_error Puppet::Error, /Tries must be an integer/
+ end
+ end
+ end
+ end
+
+ describe "when setting try_sleep" do
+ [0, 0.2, 1, 10, 4294967295].each do |valid|
+ it "should accept '#{valid}' as valid" do
+ @exec[:try_sleep] = valid
+ @exec[:try_sleep].should == valid
+ end
+
+ if "REVISIT: too much test log spam" == "a good thing" then
+ it "should accept '#{valid}' in an array as valid" do
+ pending "inconsistent, but this is not supporting arrays, unlike timeout"
+ @exec[:try_sleep] = [valid]
+ @exec[:try_sleep].should == valid
+ end
+ end
+ end
+
+ { -3.5 => "cannot be a negative number",
+ -1 => "cannot be a negative number",
+ '1/2' => 'must be a number',
+ '1_000_000' => 'must be a number',
+ '+12' => 'must be a number',
+ '' => 'must be a number',
+ 'foo' => 'must be a number',
+ }.each do |invalid, error|
+ it "should reject '#{invalid}' as invalid" do
+ expect { @exec[:try_sleep] = invalid }.
+ should raise_error Puppet::Error, /try_sleep #{error}/
+ end
+
+ if "REVISIT: too much test log spam" == "a good thing" then
+ it "should reject '#{invalid}' in an array as invalid" do
+ pending "inconsistent, but this is not supporting arrays, unlike timeout"
+ expect { @exec[:try_sleep] = [invalid] }.
+ should raise_error Puppet::Error, /try_sleep #{error}/
+ end
+ end
+ end
+ end
+
+ describe "when setting refreshonly" do
+ [:true, :false].each do |value|
+ it "should accept '#{value}'" do
+ @exec[:refreshonly] = value
+ @exec[:refreshonly].should == value
+ end
+ end
+
+ [1, 0, "1", "0", "yes", "y", "no", "n"].each do |value|
+ it "should reject '#{value}'" do
+ expect { @exec[:refreshonly] = value }.
+ should raise_error(Puppet::Error,
+ /Invalid value #{value.inspect}\. Valid values are true, false/
+ )
+ end
+ end
+ end
+
+ describe "when setting creates" do
+ it_should_behave_like "all path parameters", :creates, :array => true do
+ def instance(path)
+ Puppet::Type.type(:exec).new(:name => '/bin/true', :creates => path)
+ end
+ end
+ end
end
- describe "when logoutput=>on_failure is set" do
+ describe "when setting unless" do
+ it_should_behave_like "all exec command parameters", :unless
+ it_should_behave_like "all exec command parameters that take arrays", :unless
+ end
- it "should log the output on failure" do
- #Puppet::Util::Log.newdestination :console
- command = "false"
- output = "output1\noutput2\n"
- create_logging_resource(command, output, 1, :on_failure, :err)
- expect_output(output, :err)
+ describe "when setting onlyif" do
+ it_should_behave_like "all exec command parameters", :onlyif
+ it_should_behave_like "all exec command parameters that take arrays", :onlyif
+ end
- proc { @execer.refresh }.should raise_error(Puppet::Error)
+ describe "#check" do
+ before :each do
+ @test = Puppet::Type.type(:exec).new(:name => "/bin/true")
end
- it "should log the output on failure when returns is specified as an array" do
- #Puppet::Util::Log.newdestination :console
- command = "false"
- output = "output1\noutput2\n"
- create_logging_resource(command, output, 1, :on_failure, :err, [0, 100])
- expect_output(output, :err)
+ describe ":refreshonly" do
+ { :true => false, :false => true }.each do |input, result|
+ it "should return '#{result}' when given '#{input}'" do
+ @test[:refreshonly] = input
+ @test.check_all_attributes.should == result
+ end
+ end
+ end
+
+ describe ":creates" do
+ before :all do
+ @exist = "/"
+ @unexist = "/this/path/should/never/exist"
+ while FileTest.exist?(@unexist) do @unexist += "/foo" end
+ end
+
+ context "with a single item" do
+ it "should run when the item does not exist" do
+ @test[:creates] = @unexist
+ @test.check_all_attributes.should == true
+ end
+
+ it "should not run when the item exists" do
+ @test[:creates] = @exist
+ @test.check_all_attributes.should == false
+ end
+ end
+
+ context "with an array with one item" do
+ it "should run when the item does not exist" do
+ @test[:creates] = [@unexist]
+ @test.check_all_attributes.should == true
+ end
+
+ it "should not run when the item exists" do
+ @test[:creates] = [@exist]
+ @test.check_all_attributes.should == false
+ end
+ end
+
+ context "with an array with multiple items" do
+ it "should run when all items do not exist" do
+ @test[:creates] = [@unexist] * 3
+ @test.check_all_attributes.should == true
+ end
+
+ it "should not run when one item exists" do
+ @test[:creates] = [@unexist, @exist, @unexist]
+ @test.check_all_attributes.should == false
+ end
- proc { @execer.refresh }.should raise_error(Puppet::Error)
+ it "should not run when all items exist" do
+ @test[:creates] = [@exist] * 3
+ end
+ end
end
- it "shouldn't log the output on success" do
- #Puppet::Util::Log.newdestination :console
- command = "true"
- output = "output1\noutput2\n"
- create_logging_resource(command, output, 0, :on_failure, :err)
- @execer.property(:returns).expects(:err).never
- @execer.refresh
+ { :onlyif => { :pass => false, :fail => true },
+ :unless => { :pass => true, :fail => false },
+ }.each do |param, sense|
+ describe ":#{param}" do
+ before :each do
+ @pass = "/magic/pass"
+ @fail = "/magic/fail"
+
+ @pass_status = stub('status', :exitstatus => sense[:pass] ? 0 : 1)
+ @fail_status = stub('status', :exitstatus => sense[:fail] ? 0 : 1)
+
+ @test.provider.stubs(:checkexe).returns(true)
+ [true, false].each do |check|
+ @test.provider.stubs(:run).with(@pass, check).
+ returns(['test output', @pass_status])
+ @test.provider.stubs(:run).with(@fail, check).
+ returns(['test output', @fail_status])
+ end
+ end
+
+ context "with a single item" do
+ it "should run if the command exits non-zero" do
+ @test[param] = @fail
+ @test.check_all_attributes.should == true
+ end
+
+ it "should not run if the command exits zero" do
+ @test[param] = @pass
+ @test.check_all_attributes.should == false
+ end
+ end
+
+ context "with an array with a single item" do
+ it "should run if the command exits non-zero" do
+ @test[param] = [@fail]
+ @test.check_all_attributes.should == true
+ end
+
+ it "should not run if the command exits zero" do
+ @test[param] = [@pass]
+ @test.check_all_attributes.should == false
+ end
+ end
+
+ context "with an array with multiple items" do
+ it "should run if all the commands exits non-zero" do
+ @test[param] = [@fail] * 3
+ @test.check_all_attributes.should == true
+ end
+
+ it "should not run if one command exits zero" do
+ @test[param] = [@pass, @fail, @pass]
+ @test.check_all_attributes.should == false
+ end
+
+ it "should not run if all command exits zero" do
+ @test[param] = [@pass] * 3
+ @test.check_all_attributes.should == false
+ end
+ end
+ end
end
end
- it "shouldn't log the output on success when non-zero exit status is in a returns array" do
- #Puppet::Util::Log.newdestination :console
- command = "true"
- output = "output1\noutput2\n"
- create_logging_resource(command, output, 100, :on_failure, :err, [1,100])
- @execer.property(:returns).expects(:err).never
- @execer.refresh
+ describe "#retrieve" do
+ before :each do
+ @exec_resource = Puppet::Type.type(:exec).new(:name => "/bogus/cmd")
+ end
+
+ it "should return :notrun when check_all_attributes returns true" do
+ @exec_resource.stubs(:check_all_attributes).returns true
+ @exec_resource.retrieve[:returns].should == :notrun
+ end
+
+ it "should return default exit code 0 when check_all_attributes returns false" do
+ @exec_resource.stubs(:check_all_attributes).returns false
+ @exec_resource.retrieve[:returns].should == ['0']
+ end
+
+ it "should return the specified exit code when check_all_attributes returns false" do
+ @exec_resource.stubs(:check_all_attributes).returns false
+ @exec_resource[:returns] = 42
+ @exec_resource.retrieve[:returns].should == ["42"]
+ end
end
- describe " when multiple tries are set," do
+ describe "#output" do
+ before :each do
+ @exec_resource = Puppet::Type.type(:exec).new(:name => "/bogus/cmd")
+ end
+
+ it "should return the provider's run output" do
+ provider = stub 'provider'
+ status = stubs "process_status"
+ status.stubs(:exitstatus).returns("0")
+ provider.expects(:run).returns(["silly output", status])
+ @exec_resource.stubs(:provider).returns(provider)
- it "should repeat the command attempt 'tries' times on failure and produce an error" do
- Puppet.features.stubs(:root?).returns(true)
- command = "false"
- user = "user"
- group = "group"
- tries = 5
- retry_exec = Puppet::Type.type(:exec).new(:name => command, :path => %w{/usr/bin /bin}, :user => user, :group => group, :returns => 0, :tries => tries, :try_sleep => 0)
- status = stub "process"
- status.stubs(:exitstatus).returns(1)
- Puppet::Util::SUIDManager.expects(:run_and_capture).with([command], user, group).times(tries).returns(["", status])
- proc { retry_exec.refresh }.should raise_error(Puppet::Error)
+ @exec_resource.refresh
+ @exec_resource.output.should == 'silly output'
end
end
- it "should be able to autorequire files mentioned in the command" do
- catalog = Puppet::Resource::Catalog.new
- catalog.add_resource Puppet::Type.type(:file).new(:name => @executable)
- @execer = Puppet::Type.type(:exec).new(:name => @command)
- catalog.add_resource @execer
+ describe "#refresh" do
+ before :each do
+ @exec_resource = Puppet::Type.type(:exec).new(:name => "/bogus/cmd")
+ end
+
+ it "should call provider run with the refresh parameter if it is set" do
+ provider = stub 'provider'
+ @exec_resource.stubs(:provider).returns(provider)
+ @exec_resource.stubs(:[]).with(:refresh).returns('/myother/bogus/cmd')
+ provider.expects(:run).with('/myother/bogus/cmd')
- rels = @execer.autorequire
- rels[0].should be_instance_of(Puppet::Relationship)
- rels[0].target.should equal(@execer)
+ @exec_resource.refresh
+ end
+
+ it "should call provider run with the specified command if the refresh parameter is not set" do
+ provider = stub 'provider'
+ status = stubs "process_status"
+ status.stubs(:exitstatus).returns("0")
+ provider.expects(:run).with('/bogus/cmd').returns(["silly output", status])
+ @exec_resource.stubs(:provider).returns(provider)
+
+ @exec_resource.refresh
+ end
+
+ it "should not run the provider if check_all_attributes is false" do
+ @exec_resource.stubs(:check_all_attributes).returns false
+ provider = stub 'provider'
+ provider.expects(:run).never
+ @exec_resource.stubs(:provider).returns(provider)
+
+ @exec_resource.refresh
+ end
end
end
diff --git a/spec/unit/type_spec.rb b/spec/unit/type_spec.rb
index 6d9d0b234..9b1f20500 100755
--- a/spec/unit/type_spec.rb
+++ b/spec/unit/type_spec.rb
@@ -1,6 +1,6 @@
#!/usr/bin/env ruby
-require File.dirname(__FILE__) + '/../spec_helper'
+require File.expand_path(File.join(File.dirname(__FILE__), '/../spec_helper'))
describe Puppet::Type do
it "should include the Cacher module" do
diff --git a/spec/unit/util/loadedfile_spec.rb b/spec/unit/util/loadedfile_spec.rb
index 3bc26a421..c6fd625fc 100755
--- a/spec/unit/util/loadedfile_spec.rb
+++ b/spec/unit/util/loadedfile_spec.rb
@@ -6,6 +6,7 @@ require 'tempfile'
require 'puppet/util/loadedfile'
describe Puppet::Util::LoadedFile do
+ include PuppetSpec::Files
before(:each) do
@f = Tempfile.new('loadedfile_test')
@f.puts "yayness"
@@ -18,6 +19,12 @@ describe Puppet::Util::LoadedFile do
@fake_now = Time.now + (2 * Puppet[:filetimeout])
end
+ it "should accept files that don't exist" do
+ nofile = tmpfile('testfile')
+ File.exists?(nofile).should == false
+ lambda{ Puppet::Util::LoadedFile.new(nofile) }.should_not raise_error
+ end
+
it "should recognize when the file has not changed" do
# Use fake "now" so that we can be sure changed? actually checks, without sleeping
# for Puppet[:filetimeout] seconds.
diff --git a/spec/unit/util/rdoc/parser_spec.rb b/spec/unit/util/rdoc/parser_spec.rb
index b4453ae86..6ae28b40a 100755
--- a/spec/unit/util/rdoc/parser_spec.rb
+++ b/spec/unit/util/rdoc/parser_spec.rb
@@ -20,8 +20,9 @@ describe RDoc::Parser do
@parser.stubs(:scan_top_level)
parser = stub 'parser'
Puppet::Parser::Parser.stubs(:new).returns(parser)
- parser.expects(:parse)
+ parser.expects(:parse).at_least_once
parser.expects(:file=).with("module/manifests/init.pp")
+ parser.expects(:file=).with("/dev/null/manifests/site.pp")
@parser.scan
end