[Pkg-puppet-devel] [SCM] Puppet packaging for Debian branch, experimental, updated. debian/2.6.8-1-844-g7ec39d5

Max Martin max at puppetlabs.com
Tue May 10 08:07:49 UTC 2011


The following commit has been merged in the experimental branch:
commit 66d0b16c8a0a55dd79b1b0f0e639f107e552d9ab
Merge: 36f4dc5e1527fc46f097080c12bb1ee5c3d46714 3875b5ba9014a6ba540e51e0ffb411d58aa521e4
Author: Max Martin <max at puppetlabs.com>
Date:   Wed Mar 23 14:32:59 2011 -0700

    Merge branch '2.6.next' into next
    
    * 2.6.next:
      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
      (#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
      (#4884) Get rid of open3 require since it wasn't being used
      (#5814) Improved cron type specs
      (#5814) cron_spec shouldn't depend on cron provider
    
    Manually Resolved Conflicts:
    	lib/puppet/util/command_line/puppetrun
    	spec/spec_helper.rb
    	spec/unit/type/exec_spec.rb
    	spec/unit/type_spec.rb
    	test/ral/type/exec.rb

diff --combined lib/puppet/type/exec.rb
index ae57950,4458bf0..773df2b
--- a/lib/puppet/type/exec.rb
+++ b/lib/puppet/type/exec.rb
@@@ -23,17 -23,15 +23,15 @@@ module Puppe
        you are doing a lot of work with `exec`, please at least notify
        us at Puppet Labs what you are doing, and hopefully we can work with
        you to get a native resource type for the work you are doing.
-       
-       **Autorequires:** If Puppet is managing an exec's cwd or the executable file used in an exec's command, the exec resource will autorequire those files. If Puppet is managing the user that an exec should run as, the exec resource will autorequire that user."
  
-     require 'open3'
+       **Autorequires:** If Puppet is managing an exec's cwd or the executable file used in an exec's command, the exec resource will autorequire those files. If Puppet is managing the user that an exec should run as, the exec resource will autorequire that user."
  
      # Create a new check mechanism.  It's basically just a parameter that
      # provides one extra 'check' method.
-     def self.newcheck(name, &block)
+     def self.newcheck(name, options = {}, &block)
        @checks ||= {}
  
-       check = newparam(name, &block)
+       check = newparam(name, options, &block)
        @checks[name] = check
      end
  
@@@ -65,9 -63,11 +63,11 @@@
  
        # First verify that all of our checks pass.
        def retrieve
-         # Default to somethinng
- 
-         if @resource.check
+         # We need to return :notrun to trigger evaluation; when that isn't
+         # true, we *LIE* about what happened and return a "success" for the
+         # value, which causes us to be treated as in_sync?, which means we
+         # don't actually execute anything.  I think. --daniel 2011-03-10
+         if @resource.check_all_attributes
            return :notrun
          else
            return self.should
@@@ -89,7 -89,7 +89,7 @@@
            tries.times do |try|
              # Only add debug messages for tries > 1 to reduce log spam.
              debug("Exec try #{try+1}/#{tries}") if tries > 1
-             @output, @status = @resource.run(self.resource[:command])
+             @output, @status = provider.run(self.resource[:command])
              break if self.should.include?(@status.exitstatus.to_s)
              if try_sleep > 0 and tries > 1
                debug("Sleeping for #{try_sleep} seconds between tries")
@@@ -139,7 -139,7 +139,7 @@@
      newparam(:path) do
        desc "The search path used for command execution.
          Commands must be fully qualified if no path is specified.  Paths
-         can be specified as an array or as a colon-separated list."
+         can be specified as an array or as a colon separated list."
  
        # Support both arrays and colon-separated fields.
        def value=(*values)
@@@ -176,21 -176,9 +176,9 @@@
        # Validation is handled by the SUIDManager class.
      end
  
-     newparam(:cwd) do
+     newparam(:cwd, :parent => Puppet::Parameter::Path) do
        desc "The directory from which to run the command.  If
          this directory does not exist, the command will fail."
- 
-       validate do |dir|
-         unless dir =~ /^#{File::SEPARATOR}/
-           self.fail("CWD must be a fully qualified path")
-         end
-       end
- 
-       munge do |dir|
-         dir = dir[0] if dir.is_a?(Array)
- 
-         dir
-       end
      end
  
      newparam(:logoutput) do
@@@ -209,10 -197,19 +197,10 @@@
          for refreshing."
  
        validate do |command|
-         @resource.validatecmd(command)
+         provider.validatecmd(command)
        end
      end
  
 -    newparam(:env) do
 -      desc "This parameter is deprecated. Use 'environment' instead."
 -
 -      munge do |value|
 -        warning "'env' is deprecated on exec; use 'environment' instead."
 -        resource[:environment] = value
 -      end
 -    end
 -
      newparam(:environment) do
        desc "Any additional environment variables you want to set for a
          command.  Note that if you use this to set PATH, it will override
@@@ -324,7 -321,7 +312,7 @@@
        end
      end
  
-     newcheck(:creates) do
+     newcheck(:creates, :parent => Puppet::Parameter::Path) do
        desc "A file that this command creates.  If this
          parameter is provided, then the command will only be run
          if the specified file does not exist:
@@@ -337,19 -334,7 +325,7 @@@
  
          "
  
-       # FIXME if they try to set this and fail, then we should probably
-       # fail the entire exec, right?
-       validate do |files|
-         files = [files] unless files.is_a? Array
- 
-         files.each do |file|
-           self.fail("'creates' must be set to a fully qualified path") unless file
- 
-           unless file =~ %r{^#{File::SEPARATOR}}
-             self.fail "'creates' files must be fully qualified."
-           end
-         end
-       end
+       accept_arrays
  
        # If the file exists, return false (i.e., don't run the command),
        # else return true
@@@ -377,15 -362,15 +353,15 @@@
        validate do |cmds|
          cmds = [cmds] unless cmds.is_a? Array
  
-         cmds.each do |cmd|
-           @resource.validatecmd(cmd)
+         cmds.each do |command|
+           provider.validatecmd(command)
          end
        end
  
        # Return true if the command does not return 0.
        def check(value)
          begin
-           output, status = @resource.run(value, true)
+           output, status = provider.run(value, true)
          rescue Timeout::Error
            err "Check #{value.inspect} exceeded timeout"
            return false
@@@ -419,15 -404,15 +395,15 @@@
        validate do |cmds|
          cmds = [cmds] unless cmds.is_a? Array
  
-         cmds.each do |cmd|
-           @resource.validatecmd(cmd)
+         cmds.each do |command|
+           provider.validatecmd(command)
          end
        end
  
        # Return true if the command returns 0.
        def check(value)
          begin
-           output, status = @resource.run(value, true)
+           output, status = provider.run(value, true)
          rescue Timeout::Error
            err "Check #{value.inspect} exceeded timeout"
            return false
@@@ -441,7 -426,7 +417,7 @@@
      @isomorphic = false
  
      validate do
-       validatecmd(self[:command])
+       provider.validatecmd(self[:command])
      end
  
      # FIXME exec should autorequire any exec that 'creates' our cwd
@@@ -494,7 -479,7 +470,7 @@@
      # Verify that we pass all of the checks.  The argument determines whether
      # we skip the :refreshonly check, which is necessary because we now check
      # within refresh
-     def check(refreshing = false)
+     def check_all_attributes(refreshing = false)
        self.class.checks.each { |check|
          next if refreshing and check == :refreshonly
          if @parameters.include?(check)
@@@ -509,32 -494,6 +485,6 @@@
        true
      end
  
-     # Verify that we have the executable
-     def checkexe(cmd)
-       exe = extractexe(cmd)
- 
-       if self[:path]
-         if Puppet.features.posix? and !File.exists?(exe)
-           withenv :PATH => self[:path].join(File::PATH_SEPARATOR) do
-             exe = which(exe) || raise(ArgumentError,"Could not find command '#{exe}'")
-           end
-         elsif Puppet.features.microsoft_windows? and !File.exists?(exe)
-           self[:path].each do |path|
-             [".exe", ".ps1", ".bat", ".com", ""].each do |extension|
-               file = File.join(path, exe+extension)
-               return if File.exists?(file)
-             end
-           end
-         end
-       end
- 
-       raise ArgumentError, "Could not find executable '#{exe}'" unless FileTest.exists?(exe)
-       unless FileTest.executable?(exe)
-         raise ArgumentError,
-           "'#{exe}' is not executable"
-       end
-     end
- 
      def output
        if self.property(:returns).nil?
          return nil
@@@ -545,98 -504,13 +495,13 @@@
  
      # Run the command, or optionally run a separately-specified command.
      def refresh
-       if self.check(true)
+       if self.check_all_attributes(true)
          if cmd = self[:refresh]
-           self.run(cmd)
+           provider.run(cmd)
          else
            self.property(:returns).sync
          end
        end
      end
- 
-     # Run a command.
-     def run(command, check = false)
-       output = nil
-       status = nil
- 
-       dir = nil
- 
-       checkexe(command)
- 
-       if dir = self[:cwd]
-         unless File.directory?(dir)
-           if check
-             dir = nil
-           else
-             self.fail "Working directory '#{dir}' does not exist"
-           end
-         end
-       end
- 
-       dir ||= Dir.pwd
- 
-       if check
-         debug "Executing check '#{command}'"
-       else
-         debug "Executing '#{command}'"
-       end
-       begin
-         # Do our chdir
-         Dir.chdir(dir) do
-           environment = {}
- 
-           environment[:PATH] = self[:path].join(":") if self[:path]
- 
-           if envlist = self[:environment]
-             envlist = [envlist] unless envlist.is_a? Array
-             envlist.each do |setting|
-               if setting =~ /^(\w+)=((.|\n)+)$/
-                 name = $1
-                 value = $2
-                 if environment.include? name
-                   warning(
-                   "Overriding environment setting '#{name}' with '#{value}'"
-                   )
-                 end
-                 environment[name] = value
-               else
-                 warning "Cannot understand environment setting #{setting.inspect}"
-               end
-             end
-           end
- 
-           withenv environment do
-             Timeout::timeout(self[:timeout]) do
-               output, status = Puppet::Util::SUIDManager.run_and_capture(
-                 [command], self[:user], self[:group]
-               )
-             end
-             # The shell returns 127 if the command is missing.
-             if status.exitstatus == 127
-               raise ArgumentError, output
-             end
-           end
-         end
-       rescue Errno::ENOENT => detail
-         self.fail detail.to_s
-       end
- 
-       return output, status
-     end
- 
-     def validatecmd(cmd)
-       exe = extractexe(cmd)
-       # if we're not fully qualified, require a path
-       self.fail "'#{cmd}' is not qualified and no path was specified. Please qualify the command or specify a path." if File.expand_path(exe) != exe and self[:path].nil?
-     end
- 
-     def extractexe(cmd)
-       # easy case: command was quoted
-       if cmd =~ /^"([^"]+)"/
-         $1
-       else
-         cmd.split(/ /)[0]
-       end
-     end
    end
  end
diff --combined spec/integration/transaction_spec.rb
index b5080b5,2c12b3d..ff15e59
--- a/spec/integration/transaction_spec.rb
+++ b/spec/integration/transaction_spec.rb
@@@ -1,6 -1,6 +1,6 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
  
  require 'puppet_spec/files'
  require 'puppet/transaction'
@@@ -107,29 -107,23 +107,23 @@@ describe Puppet::Transaction d
      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 --combined spec/spec_helper.rb
index d7f546b,505a8f9..1347042
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@@ -6,6 -6,7 +6,6 @@@ dir = File.expand_path(File.dirname(__F
  $LOAD_PATH.unshift("#{dir}/")
  $LOAD_PATH.unshift("#{dir}/lib") # a spec-specific test lib dir
  $LOAD_PATH.unshift("#{dir}/../lib")
 -$LOAD_PATH.unshift("#{dir}/../test/lib")
  
  # Don't want puppet getting the command line arguments for rake or autotest
  ARGV.clear
@@@ -19,15 -20,52 +19,21 @@@ module PuppetSpe
    FIXTURE_DIR = File.join(dir = File.expand_path(File.dirname(__FILE__)), "fixtures") unless defined?(FIXTURE_DIR)
  end
  
 -module PuppetTest
 -end
 -
+ require 'pathname'
+ require 'lib/puppet_spec/verbose'
  require 'lib/puppet_spec/files'
 +require 'lib/puppet_spec/fixtures'
  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
 +  include PuppetSpec::Fixtures
  
 -  config.after :each do
 -    Puppet.settings.clear
 -    Puppet::Node::Environment.clear
 -    Puppet::Util::Storage.clear
 -    Puppet::Util::ExecutionStub.reset
 -
 -    if defined?($tmpfiles)
 -      $tmpfiles.each do |file|
 -        file = File.expand_path(file)
 -        if Puppet.features.posix? and file !~ /^\/tmp/ and file !~ /^\/var\/folders/
 -          puts "Not deleting tmpfile #{file} outside of /tmp or /var/folders"
 -          next
 -        elsif Puppet.features.microsoft_windows?
 -          tempdir = File.expand_path(File.join(Dir::LOCAL_APPDATA, "Temp"))
 -          if file !~ /^#{tempdir}/
 -            puts "Not deleting tmpfile #{file} outside of #{tempdir}"
 -            next
 -          end
 -        end
 -        if FileTest.exist?(file)
 -          system("chmod -R 755 '#{file}'")
 -          system("rm -rf '#{file}'")
 -        end
 -      end
 -      $tmpfiles.clear
 -    end
 -
 -    @logs.clear
 -    Puppet::Util::Log.close_all
 -  end
 +  config.mock_with :mocha
  
    config.before :each do
      # these globals are set by Application
@@@ -44,19 -82,7 +50,19 @@@
      Puppet.settings[:bindaddress] = "127.0.0.1"
  
      @logs = []
 -    Puppet::Util::Log.newdestination(@logs)
 +    Puppet::Util::Log.newdestination(Puppet::Test::LogCollector.new(@logs))
 +  end
 +
 +  config.after :each do
 +    Puppet.settings.clear
 +    Puppet::Node::Environment.clear
 +    Puppet::Util::Storage.clear
 +    Puppet::Util::ExecutionStub.reset
 +
 +    PuppetSpec::Files.cleanup
 +
 +    @logs.clear
 +    Puppet::Util::Log.close_all
    end
  end
  
diff --combined spec/unit/indirector/exec_spec.rb
index c6726d4,de37f27..d4fb224
--- a/spec/unit/indirector/exec_spec.rb
+++ b/spec/unit/indirector/exec_spec.rb
@@@ -1,6 -1,6 +1,6 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
  
  require 'puppet/indirector/exec'
  
@@@ -47,10 -47,9 +47,9 @@@ describe Puppet::Indirector::Exec d
      @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 --combined spec/unit/type/cron_spec.rb
index 4d224c6,f985cdd..5466b4d
--- a/spec/unit/type/cron_spec.rb
+++ b/spec/unit/type/cron_spec.rb
@@@ -1,33 -1,481 +1,481 @@@
  #!/usr/bin/env ruby
  
 -Dir.chdir(File.dirname(__FILE__)) { (s = lambda { |f| File.exist?(f) ? require(f) : Dir.chdir("..") { s.call(f) } }).call("spec/spec_helper.rb") }
 +require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
  
  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 --combined spec/unit/type/exec_spec.rb
index e980ec5,07ad1df..a1ffb16
--- a/spec/unit/type/exec_spec.rb
+++ b/spec/unit/type/exec_spec.rb
@@@ -1,162 -1,677 +1,648 @@@
  #!/usr/bin/env ruby
 -require File.dirname(__FILE__) + '/../../spec_helper'
 +
 +require File.expand_path(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)
+ 
+     status = stub "process", :exitstatus => exitstatus
+     Puppet::Util::SUIDManager.expects(:run_and_capture).times(tries).
+       with([command], @user_name, @group_name).returns([output, status])
  
-     Puppet::Util::SUIDManager.expects(:run_and_capture).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
+ 
+   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
  
-   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 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
+ 
+     ['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
  
-   describe "when execing" do
+   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
+ 
+     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
+ 
+         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 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 use the 'run_and_capture' method to exec" do
-       command = "true"
-       create_resource(command, "", 0)
+       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
  
-       @execer.refresh.should == :executed_command
+       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" do
-       command = "false"
-       create_resource(command, "", 1)
+   describe "when setting refresh" do
+     it_should_behave_like "all exec command parameters", :refresh
+   end
  
-       proc { @execer.refresh }.should raise_error(Puppet::Error)
+   describe "for simple parameters" do
+     before :each do
+       @exec = 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)
 -    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
 -
+     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
+ 
+       { "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
+       [-3.5, -1, 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', '1_000_000', '+12', '', 'foo'].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
      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 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
  
-     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 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
  
-     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 refreshonly" do
+       [:true, :false].each do |value|
+         it "should accept '#{value}'" do
+           @exec[:refreshonly] = value
+           @exec[:refreshonly].should == value
+         end
+       end
  
-       proc { @execer.refresh }.should raise_error(Puppet::Error)
+       [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
  
-       proc { @execer.refresh }.should raise_error(Puppet::Error)
+         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
+ 
+         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 --combined test/ral/type/exec.rb
index 829b1a0,dd42ae6..0831d46
--- a/test/ral/type/exec.rb
+++ b/test/ral/type/exec.rb
@@@ -1,6 -1,6 +1,6 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../../lib/puppettest'
 +require File.expand_path(File.dirname(__FILE__) + '/../../lib/puppettest')
  
  require 'puppettest'
  
@@@ -34,10 -34,8 +34,8 @@@ class TestExec < Test::Unit::TestCas
      assert_nothing_raised {
  
        command = Puppet::Type.type(:exec).new(
- 
          :command => "echo",
- 
-         :path => "/usr/bin:/bin:/usr/sbin:/sbin"
+         :path    => "/usr/bin:/bin:/usr/sbin:/sbin"
        )
      }
      assert_nothing_raised {
@@@ -48,10 -46,8 +46,8 @@@
      assert_nothing_raised {
  
        command = Puppet::Type.type(:exec).new(
- 
          :command => "/bin/echo",
- 
-         :path => "/usr/bin:/bin:/usr/sbin:/sbin"
+         :path    => "/usr/bin:/bin:/usr/sbin:/sbin"
        )
      }
    end
@@@ -60,30 -56,24 +56,24 @@@
      assert_nothing_raised {
  
        command = Puppet::Type.type(:exec).new(
- 
          :command => "mkdir /this/directory/does/not/exist",
-         :path => "/usr/bin:/bin:/usr/sbin:/sbin",
- 
+         :path    => "/usr/bin:/bin:/usr/sbin:/sbin",
          :returns => 1
        )
      }
      assert_nothing_raised {
  
        command = Puppet::Type.type(:exec).new(
- 
          :command => "touch /etc",
-         :path => "/usr/bin:/bin:/usr/sbin:/sbin",
- 
+         :path    => "/usr/bin:/bin:/usr/sbin:/sbin",
          :returns => 1
        )
      }
      assert_nothing_raised {
  
        command = Puppet::Type.type(:exec).new(
- 
          :command => "thiscommanddoesnotexist",
-         :path => "/usr/bin:/bin:/usr/sbin:/sbin",
- 
+         :path    => "/usr/bin:/bin:/usr/sbin:/sbin",
          :returns => 127
        )
      }
@@@ -98,11 -88,9 +88,9 @@@
      assert_nothing_raised {
  
        command = Puppet::Type.type(:exec).new(
- 
          :command => "pwd",
-         :cwd => dir,
-         :path => "/usr/bin:/bin:/usr/sbin:/sbin",
- 
+         :cwd     => dir,
+         :path    => "/usr/bin:/bin:/usr/sbin:/sbin",
          :returns => 0
        )
      }
@@@ -117,11 -105,9 +105,9 @@@
      @@tmpfiles.push tmpfile
      trans = nil
  
-       file = Puppet::Type.type(:file).new(
- 
-         :path => tmpfile,
- 
-         :content => "yay"
+     file = Puppet::Type.type(:file).new(
+       :path    => tmpfile,
+       :content => "yay"
      )
      # Get the file in sync
      assert_apply(file)
@@@ -129,13 -115,10 +115,10 @@@
      # Now make an exec
      maker = tempfile
      assert_nothing_raised {
- 
        cmd = Puppet::Type.type(:exec).new(
- 
-         :command => "touch #{maker}",
-         :path => "/usr/bin:/bin:/usr/sbin:/sbin",
-         :subscribe => file,
- 
+         :command     => "touch #{maker}",
+         :path        => "/usr/bin:/bin:/usr/sbin:/sbin",
+         :subscribe   => file,
          :refreshonly => true
        )
      }
@@@ -143,7 -126,7 +126,7 @@@
      assert(cmd, "did not make exec")
  
      assert_nothing_raised do
-       assert(! cmd.check, "Check passed when refreshonly is set")
+       assert(! cmd.check_all_attributes, "Check passed when refreshonly is set")
      end
  
      assert_events([], file, cmd)
@@@ -158,25 -141,22 +141,22 @@@
    def test_refreshonly
      cmd = true
      assert_nothing_raised {
- 
        cmd = Puppet::Type.type(:exec).new(
- 
-         :command => "pwd",
-         :path => "/usr/bin:/bin:/usr/sbin:/sbin",
- 
+         :command     => "pwd",
+         :path        => "/usr/bin:/bin:/usr/sbin:/sbin",
          :refreshonly => true
        )
      }
  
      # Checks should always fail when refreshonly is enabled
-     assert(!cmd.check, "Check passed with refreshonly true")
+     assert(!cmd.check_all_attributes, "Check passed with refreshonly true")
  
      # Now make sure it passes if we pass in "true"
-     assert(cmd.check(true), "Check failed with refreshonly true while refreshing")
+     assert(cmd.check_all_attributes(true), "Check failed with refreshonly true while refreshing")
  
      # Now set it to false
      cmd[:refreshonly] = false
-     assert(cmd.check, "Check failed with refreshonly false")
+     assert(cmd.check_all_attributes, "Check failed with refreshonly false")
    end
  
    def test_creates
@@@ -186,10 -166,8 +166,8 @@@
      assert_nothing_raised {
  
        exec = Puppet::Type.type(:exec).new(
- 
          :command => "touch #{file}",
-         :path => "/usr/bin:/bin:/usr/sbin:/sbin",
- 
+         :path    => "/usr/bin:/bin:/usr/sbin:/sbin",
          :creates => file
        )
      }
@@@ -206,21 -184,15 +184,15 @@@
      sh = %x{which sh}
      File.open(exe, "w") { |f| f.puts "#!#{sh}\necho yup" }
  
- 
-       file = Puppet::Type.type(:file).new(
- 
-         :path => oexe,
-         :source => exe,
- 
-         :mode => 0755
+     file = Puppet::Type.type(:file).new(
+       :path => oexe,
+       :source => exe,
+       :mode => 0755
      )
  
- 
-       exec = Puppet::Type.type(:exec).new(
- 
-         :command => oexe,
- 
-         :require => Puppet::Resource.new(:file, oexe)
+     exec = Puppet::Type.type(:exec).new(
+       :command => oexe,
+       :require => Puppet::Resource.new(:file, oexe)
      )
  
      comp = mk_catalog("Testing", file, exec)
@@@ -236,47 -208,36 +208,36 @@@
      File.open(exe, "w") { |f| f.puts "#!#{sh}\necho yup" }
  
  
-       file = Puppet::Type.type(:file).new(
- 
-         :path => oexe,
-         :source => exe,
- 
-         :mode => 755
+     file = Puppet::Type.type(:file).new(
+       :path => oexe,
+       :source => exe,
+       :mode => 755
      )
  
      basedir = File.dirname(oexe)
  
-       baseobj = Puppet::Type.type(:file).new(
- 
-         :path => basedir,
-         :source => exe,
- 
-         :mode => 755
+     baseobj = Puppet::Type.type(:file).new(
+       :path   => basedir,
+       :source => exe,
+       :mode   => 755
      )
  
  
-       ofile = Puppet::Type.type(:file).new(
- 
-         :path => exe,
- 
-         :mode => 755
+     ofile = Puppet::Type.type(:file).new(
+       :path => exe,
+       :mode => 755
      )
  
  
-       exec = Puppet::Type.type(:exec).new(
- 
-         :command => oexe,
-         :path => ENV["PATH"],
- 
-         :cwd => basedir
+     exec = Puppet::Type.type(:exec).new(
+       :command => oexe,
+       :path => ENV["PATH"],
+       :cwd => basedir
      )
  
- 
-       cat = Puppet::Type.type(:exec).new(
- 
-         :command => "cat #{exe} #{oexe}",
- 
-         :path => ENV["PATH"]
+     cat = Puppet::Type.type(:exec).new(
+       :command => "cat #{exe} #{oexe}",
+       :path => ENV["PATH"]
      )
  
      catalog = mk_catalog(file, baseobj, ofile, exec, cat)
@@@ -311,11 -272,9 +272,9 @@@
      assert_nothing_raised {
  
        exec = Puppet::Type.type(:exec).new(
- 
          :command => "touch #{bfile}",
-         :onlyif => "test -f #{afile}",
- 
-         :path => ENV['PATH']
+         :onlyif  => "test -f #{afile}",
+         :path    => ENV['PATH']
        )
      }
  
@@@ -333,12 -292,9 +292,9 @@@
  
      exec = nil
      assert_nothing_raised {
- 
        exec = Puppet::Type.type(:exec).new(
- 
          :command => "touch #{bfile}",
          :unless => "test -f #{afile}",
- 
          :path => ENV['PATH']
        )
      }
@@@ -417,13 -373,10 +373,10 @@@
    def test_logoutput
      exec = nil
      assert_nothing_raised {
- 
        exec = Puppet::Type.type(:exec).new(
- 
-         :title => "logoutputesting",
-         :path => "/usr/bin:/bin",
-         :command => "echo logoutput is false",
- 
+         :title     => "logoutputesting",
+         :path      => "/usr/bin:/bin",
+         :command   => "echo logoutput is false",
          :logoutput => false
        )
      }
@@@ -453,24 -406,19 +406,19 @@@
      assert_nothing_raised {
  
        exec = Puppet::Type.type(:exec).new(
- 
-         :title => "mkdir",
-         :path => "/usr/bin:/bin",
+         :title   => "mkdir",
+         :path    => "/usr/bin:/bin",
          :creates => basedir,
- 
          :command => "mkdir #{basedir}; touch #{path}"
- 
        )
      }
  
      assert_nothing_raised {
  
        file = Puppet::Type.type(:file).new(
- 
-         :path => basedir,
+         :path    => basedir,
          :recurse => true,
-         :mode => "755",
- 
+         :mode    => "755",
          :require => Puppet::Resource.new("exec", "mkdir")
        )
      }
@@@ -507,12 -455,9 +455,9 @@@
      file = tempfile
  
      assert_nothing_raised {
- 
        exec1 = Puppet::Type.type(:exec).new(
- 
-         :title => "one",
-         :path => ENV["PATH"],
- 
+         :title   => "one",
+         :path    => ENV["PATH"],
          :command => "mkdir #{dir}"
        )
      }
@@@ -520,12 -465,10 +465,10 @@@
      assert_nothing_raised("Could not create exec w/out existing cwd") {
  
        exec2 = Puppet::Type.type(:exec).new(
- 
-         :title => "two",
-         :path => ENV["PATH"],
+         :title   => "two",
+         :path    => ENV["PATH"],
          :command => "touch #{file}",
- 
-         :cwd => dir
+         :cwd     => dir
        )
      }
  
@@@ -555,11 -498,8 +498,8 @@@
      test = "test -f #{file}"
  
      assert_nothing_raised {
- 
        exec = Puppet::Type.type(:exec).new(
- 
-         :path => ENV["PATH"],
- 
+         :path    => ENV["PATH"],
          :command => "touch #{file}"
        )
      }
@@@ -569,7 -509,7 +509,7 @@@
      }
  
      assert_nothing_raised {
-       assert(exec.check, "Check did not pass")
+       assert(exec.check_all_attributes, "Check did not pass")
      }
  
      assert_nothing_raised {
@@@ -582,13 -522,13 +522,13 @@@
      }
  
      assert_nothing_raised {
-       assert(exec.check, "Check did not pass")
+       assert(exec.check_all_attributes, "Check did not pass")
      }
  
      assert_apply(exec)
  
      assert_nothing_raised {
-       assert(! exec.check, "Check passed")
+       assert(! exec.check_all_attributes, "Check passed")
      }
    end
  
@@@ -597,25 -537,62 +537,21 @@@
      return if Facter.value(:operatingsystem) == "Solaris"
  
        exec = Puppet::Type.type(:exec).new(
- 
          :command => "echo true",
-         :path => ENV["PATH"],
- 
-         :onlyif => "/bin/nosuchthingexists"
-           )
+         :path    => ENV["PATH"],
+         :onlyif  => "/bin/nosuchthingexists"
+       )
  
      assert_raise(ArgumentError, "Missing command did not raise error") {
-       exec.run("/bin/nosuchthingexists")
+       exec.provider.run("/bin/nosuchthingexists")
      }
    end
  
    def test_environmentparam
  
      exec = Puppet::Type.newexec(
- 
-       :command => "echo $environmenttest",
-       :path => ENV["PATH"],
- 
+       :command     => "echo $environmenttest",
+       :path        => ENV["PATH"],
        :environment => "environmenttest=yayness"
      )
  
@@@ -623,7 -600,7 +559,7 @@@
  
      output = status = nil
      assert_nothing_raised {
-       output, status = exec.run("echo $environmenttest")
+       output, status = exec.provider.run("echo $environmenttest")
      }
  
      assert_equal("yayness\n", output)
@@@ -636,7 -613,7 +572,7 @@@ and stuff
  
    output = status = nil
    assert_nothing_raised {
-     output, status = exec.run('echo "$environmenttest"')
+     output, status = exec.provider.run('echo "$environmenttest"')
      }
      assert_equal("a list of things\nand stuff\n", output)
  
@@@ -647,36 -624,20 +583,20 @@@
  
      output = status = nil
      assert_nothing_raised {
-       output, status = exec.run('echo "$funtest" "$yaytest"')
+       output, status = exec.provider.run('echo "$funtest" "$yaytest"')
      }
      assert_equal("A B\n", output)
    end
  
-   def test_timeout
-     exec = Puppet::Type.type(:exec).new(:command => "sleep 1", :path => ENV["PATH"], :timeout => "0.2")
-     time = Time.now
- 
-     assert_raise(Timeout::Error) {
-       exec.run("sleep 1")
-     }
-     Puppet.info "#{Time.now.to_f - time.to_f} seconds, vs a timeout of #{exec[:timeout]}"
- 
- 
-     assert_apply(exec)
-   end
- 
    # Testing #470
    def test_run_as_created_user
      exec = nil
      if Process.uid == 0
        user = "nosuchuser"
        assert_nothing_raised("Could not create exec with non-existent user") do
- 
          exec = Puppet::Type.type(:exec).new(
- 
            :command => "/bin/echo yay",
- 
-           :user => user
+           :user    => user
          )
        end
      end
@@@ -686,10 -647,8 +606,8 @@@
      assert_nothing_raised("Could not create exec with non-existent user") do
  
        exec = Puppet::Type.type(:exec).new(
- 
          :command => "/bin/echo yay",
- 
-         :group => group
+         :group   => group
        )
      end
    end
@@@ -716,12 -675,10 +634,10 @@@
      file = tempfile
      maker = tempfile
  
-       exec = Puppet::Type.type(:exec).new(
- 
-         :title => "maker",
-         :command => "touch #{maker}",
- 
-         :path => ENV["PATH"]
+     exec = Puppet::Type.type(:exec).new(
+       :title   => "maker",
+       :command => "touch #{maker}",
+       :path    => ENV["PATH"]
      )
  
      # Make sure it runs normally
@@@ -758,12 -715,10 +674,10 @@@
      refresher = tempfile
      maker = tempfile
  
-       exec = Puppet::Type.type(:exec).new(
- 
-         :title => "maker",
-         :command => "touch #{maker}",
- 
-         :path => ENV["PATH"]
+     exec = Puppet::Type.type(:exec).new(
+       :title => "maker",
+       :command => "touch #{maker}",
+       :path => ENV["PATH"]
      )
  
      # Call refresh normally
@@@ -801,4 -756,3 +715,3 @@@
      end
    end
  end
- 

-- 
Puppet packaging for Debian



More information about the Pkg-puppet-devel mailing list