diff --git a/spec/unit/type/yumrepo_spec.rb b/spec/unit/type/yumrepo_spec.rb index 3e2a7b06c..1ce12cf28 100644 --- a/spec/unit/type/yumrepo_spec.rb +++ b/spec/unit/type/yumrepo_spec.rb @@ -1,247 +1,243 @@ #!/usr/bin/env rspec require 'spec_helper' describe Puppet::Type.type(:yumrepo) do + include PuppetSpec::Files describe "When validating attributes" do it "should have a 'name' parameter'" do Puppet::Type.type(:yumrepo).new(:name => "puppetlabs")[:name].should == "puppetlabs" end [:baseurl, :cost, :descr, :enabled, :enablegroups, :exclude, :failovermethod, :gpgcheck, :gpgkey, :http_caching, :include, :includepkgs, :keepalive, :metadata_expire, :mirrorlist, :priority, :protect, :proxy, :proxy_username, :proxy_password, :timeout, :sslcacert, :sslverify, :sslclientcert, :sslclientkey].each do |param| it "should have a '#{param}' parameter" do Puppet::Type.type(:yumrepo).attrtype(param).should == :property end end end describe "When validating attribute values" do [:cost, :enabled, :enablegroups, :failovermethod, :gpgcheck, :http_caching, :keepalive, :metadata_expire, :priority, :protect, :timeout].each do |param| it "should support :absent as a value to '#{param}' parameter" do Puppet::Type.type(:yumrepo).new(:name => "puppetlabs.repo", param => :absent) end end [:cost, :enabled, :enablegroups, :gpgcheck, :keepalive, :metadata_expire, :priority, :protect, :timeout].each do |param| it "should fail if '#{param}' is not a number" do lambda { Puppet::Type.type(:yumrepo).new(:name => "puppetlabs", param => "notanumber") }.should raise_error end end [:enabled, :enabledgroups, :gpgcheck, :keepalive, :protect].each do |param| it "should fail if '#{param}' does not have one of the following values (0|1)" do lambda { Puppet::Type.type(:yumrepo).new(:name => "puppetlabs", param => "2") }.should raise_error end end it "should fail if 'failovermethod' does not have one of the following values (roundrobin|priority)" do lambda { Puppet::Type.type(:yumrepo).new(:name => "puppetlabs", :failovermethod => "notavalidvalue") }.should raise_error end it "should fail if 'http_caching' does not have one of the following values (packages|all|none)" do lambda { Puppet::Type.type(:yumrepo).new(:name => "puppetlabs", :http_caching => "notavalidvalue") }.should raise_error end it "should fail if 'sslverify' does not have one of the following values (True|False)" do lambda { Puppet::Type.type(:yumrepo).new(:name => "puppetlabs", :sslverify => "notavalidvalue") }.should raise_error end it "should succeed if 'sslverify' has one of the following values (True|False)" do Puppet::Type.type(:yumrepo).new(:name => "puppetlabs", :sslverify => "True")[:sslverify].should == "True" Puppet::Type.type(:yumrepo).new(:name => "puppetlabs", :sslverify => "False")[:sslverify].should == "False" end end # these tests were ported from the old spec/unit/type/yumrepo_spec.rb, pretty much verbatim describe "When manipulating config file" do def make_repo(name, hash={}) hash[:name] = name Puppet::Type.type(:yumrepo).new(hash) end def all_sections(inifile) sections = [] inifile.each_section { |section| sections << section.name } sections.sort end def create_data_files() File.open(File.join(@yumdir, "fedora.repo"), "w") do |f| f.print(FEDORA_REPO_FILE) end File.open(File.join(@yumdir, "fedora-devel.repo"), "w") do |f| f.print(FEDORA_DEVEL_REPO_FILE) end end before(:each) do - @yumdir = Dir.mktmpdir("yumrepo_spec_tmpdir") + @yumdir = tmpdir("yumrepo_spec_tmpdir") @yumconf = File.join(@yumdir, "yum.conf") File.open(@yumconf, "w") do |f| f.print "[main]\nreposdir=#{@yumdir} /no/such/dir\n" end Puppet::Type.type(:yumrepo).yumconf = @yumconf # It needs to be reset each time, otherwise the cache is used. Puppet::Type.type(:yumrepo).inifile = nil end - after(:each) do - FileUtils.rm_rf(@yumdir) - end - - it "should be able to create a valid config file" do values = { :descr => "Fedora Core $releasever - $basearch - Base", :baseurl => "http://example.com/yum/$releasever/$basearch/os/", :enabled => "1", :gpgcheck => "1", :includepkgs => "absent", :gpgkey => "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora", :proxy => "http://proxy.example.com:80/", :proxy_username => "username", :proxy_password => "password" } repo = make_repo("base", values) catalog = Puppet::Resource::Catalog.new # Stop Puppet from doing a bunch of magic; might want to think about a util for specs that handles this catalog.host_config = false catalog.add_resource(repo) catalog.apply inifile = Puppet::Type.type(:yumrepo).read sections = all_sections(inifile) sections.should == ['base', 'main'] text = inifile["base"].format text.should == EXPECTED_CONTENTS_FOR_CREATED_FILE end # Modify one existing section it "should be able to modify an existing config file" do create_data_files devel = make_repo("development", { :descr => "New description" }) current_values = devel.retrieve devel[:name].should == "development" current_values[devel.property(:descr)].should == 'Fedora Core $releasever - Development Tree' devel.property(:descr).should == 'New description' catalog = Puppet::Resource::Catalog.new # Stop Puppet from doing a bunch of magic; might want to think about a util for specs that handles this catalog.host_config = false catalog.add_resource(devel) catalog.apply inifile = Puppet::Type.type(:yumrepo).read inifile['development']['name'].should == 'New description' inifile['base']['name'].should == 'Fedora Core $releasever - $basearch - Base' inifile['base']['exclude'].should == "foo\n bar\n baz" all_sections(inifile).should == ['base', 'development', 'main'] end # Delete mirrorlist by setting it to :absent and enable baseurl it "should support 'absent' value" do create_data_files baseurl = 'http://example.com/' devel = make_repo( "development", { :mirrorlist => 'absent', :baseurl => baseurl }) devel.retrieve catalog = Puppet::Resource::Catalog.new # Stop Puppet from doing a bunch of magic; might want to think about a util for specs that handles this catalog.host_config = false catalog.add_resource(devel) catalog.apply inifile = Puppet::Type.type(:yumrepo).read sec = inifile["development"] sec["mirrorlist"].should == nil sec["baseurl"].should == baseurl end end end EXPECTED_CONTENTS_FOR_CREATED_FILE = <<'EOF' [base] name=Fedora Core $releasever - $basearch - Base baseurl=http://example.com/yum/$releasever/$basearch/os/ enabled=1 gpgcheck=1 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora proxy=http://proxy.example.com:80/ proxy_username=username proxy_password=password EOF FEDORA_REPO_FILE = < exitstatus) end # utility methods to help us test some private methods without being quite so verbose def call_exec_posix(command, arguments, stdin, stdout, stderr) Puppet::Util::Execution.send(:execute_posix, command, arguments, stdin, stdout, stderr) end def call_exec_windows(command, arguments, stdin, stdout, stderr) Puppet::Util::Execution.send(:execute_windows, command, arguments, stdin, stdout, stderr) end - # utility method for cloning the ENV object. Because it is not ACTUALLY a Hash instance, - # we can't use the built-in #clone method, and because Ruby 1.8.5 doesn't support some of - # the newer constructors for the Hash object, this slightly hacky syntax was the best I - # could come up with. At least it's isolated to one line of code :) - def clone_env() - ENV.inject(Hash.new) {|result,entry| result[entry[0]] = entry[1] ; result } - end - describe "execution methods" do let(:pid) { 5501 } let(:process_handle) { 0xDEADBEEF } let(:thread_handle) { 0xCAFEBEEF } let(:proc_info_stub) { stub 'processinfo', :process_handle => process_handle, :thread_handle => thread_handle, :process_id => pid} let(:null_file) { Puppet.features.microsoft_windows? ? 'NUL' : '/dev/null' } def stub_process_wait(exitstatus) if Puppet.features.microsoft_windows? Puppet::Util::Windows::Process.stubs(:wait_process).with(process_handle).returns(exitstatus) Process.stubs(:CloseHandle).with(process_handle) Process.stubs(:CloseHandle).with(thread_handle) else Process.stubs(:waitpid2).with(pid).returns([pid, stub('child_status', :exitstatus => exitstatus)]) end end describe "#execute_posix (stubs)", :unless => Puppet.features.microsoft_windows? do before :each do # Most of the things this method does are bad to do during specs. :/ Kernel.stubs(:fork).returns(pid).yields Process.stubs(:setsid) Kernel.stubs(:exec) Puppet::Util::SUIDManager.stubs(:change_user) Puppet::Util::SUIDManager.stubs(:change_group) $stdin.stubs(:reopen) $stdout.stubs(:reopen) $stderr.stubs(:reopen) @stdin = File.open(null_file, 'r') @stdout = Tempfile.new('stdout') @stderr = File.open(null_file, 'w') # there is a danger here that ENV will be modified by exec_posix. Normally it would only affect the ENV # of a forked process, but here, we're stubbing Kernel.fork, so the method has the ability to override the # "real" ENV. To guard against this, we'll capture a snapshot of ENV before each test. - @saved_env = clone_env + @saved_env = ENV.to_hash # Now, we're going to effectively "mock" the magic ruby 'ENV' variable by creating a local definition of it # inside of the module we're testing. Puppet::Util::Execution::ENV = {} end after :each do # And here we remove our "mock" version of 'ENV', which will allow us to validate that the real ENV has been # left unharmed. Puppet::Util::Execution.send(:remove_const, :ENV) # capture the current environment and make sure it's the same as it was before the test - cur_env = clone_env + cur_env = ENV.to_hash # we will get some fairly useless output if we just use the raw == operator on the hashes here, so we'll # be a bit more explicit and laborious in the name of making the error more useful... @saved_env.each_pair { |key,val| cur_env[key].should == val } (cur_env.keys - @saved_env.keys).should == [] end it "should fork a child process to execute the command" do Kernel.expects(:fork).returns(pid).yields Kernel.expects(:exec).with('test command') call_exec_posix('test command', {}, @stdin, @stdout, @stderr) end it "should start a new session group" do Process.expects(:setsid) call_exec_posix('test command', {}, @stdin, @stdout, @stderr) end it "should close all open file descriptors except stdin/stdout/stderr" do # This is ugly, but I can't really think of a better way to do it without # letting it actually close fds, which seems risky (0..2).each {|n| IO.expects(:new).with(n).never} (3..256).each {|n| IO.expects(:new).with(n).returns mock('io', :close) } call_exec_posix('test command', {}, @stdin, @stdout, @stderr) end it "should permanently change to the correct user and group if specified" do Puppet::Util::SUIDManager.expects(:change_group).with(55, true) Puppet::Util::SUIDManager.expects(:change_user).with(50, true) call_exec_posix('test command', {:uid => 50, :gid => 55}, @stdin, @stdout, @stderr) end it "should exit failure if there is a problem execing the command" do Kernel.expects(:exec).with('test command').raises("failed to execute!") Puppet::Util::Execution.stubs(:puts) Puppet::Util::Execution.expects(:exit!).with(1) call_exec_posix('test command', {}, @stdin, @stdout, @stderr) end it "should properly execute commands specified as arrays" do Kernel.expects(:exec).with('test command', 'with', 'arguments') call_exec_posix(['test command', 'with', 'arguments'], {:uid => 50, :gid => 55}, @stdin, @stdout, @stderr) end it "should properly execute string commands with embedded newlines" do Kernel.expects(:exec).with("/bin/echo 'foo' ; \n /bin/echo 'bar' ;") call_exec_posix("/bin/echo 'foo' ; \n /bin/echo 'bar' ;", {:uid => 50, :gid => 55}, @stdin, @stdout, @stderr) end it "should return the pid of the child process" do call_exec_posix('test command', {}, @stdin, @stdout, @stderr).should == pid end end describe "#execute_windows (stubs)", :if => Puppet.features.microsoft_windows? do before :each do Process.stubs(:create).returns(proc_info_stub) stub_process_wait(0) @stdin = File.open(null_file, 'r') @stdout = Tempfile.new('stdout') @stderr = File.open(null_file, 'w') end it "should create a new process for the command" do Process.expects(:create).with( :command_line => "test command", :startup_info => {:stdin => @stdin, :stdout => @stdout, :stderr => @stderr}, :close_handles => false ).returns(proc_info_stub) call_exec_windows('test command', {}, @stdin, @stdout, @stderr) end it "should return the process info of the child process" do call_exec_windows('test command', {}, @stdin, @stdout, @stderr).should == proc_info_stub end it "should quote arguments containing spaces if command is specified as an array" do Process.expects(:create).with do |args| args[:command_line] == '"test command" with some "arguments \"with spaces"' end.returns(proc_info_stub) call_exec_windows(['test command', 'with', 'some', 'arguments "with spaces'], {}, @stdin, @stdout, @stderr) end end describe "#execute (stubs)" do before :each do stub_process_wait(0) end describe "when an execution stub is specified" do before :each do Puppet::Util::ExecutionStub.set do |command,args,stdin,stdout,stderr| "execution stub output" end end it "should call the block on the stub" do Puppet::Util::Execution.execute("/usr/bin/run_my_execute_stub").should == "execution stub output" end it "should not actually execute anything" do Puppet::Util::Execution.expects(:execute_posix).never Puppet::Util::Execution.expects(:execute_windows).never Puppet::Util::Execution.execute("/usr/bin/run_my_execute_stub") end end describe "when setting up input and output files" do include PuppetSpec::Files let(:executor) { Puppet.features.microsoft_windows? ? 'execute_windows' : 'execute_posix' } let(:rval) { Puppet.features.microsoft_windows? ? proc_info_stub : pid } before :each do Puppet::Util::Execution.stubs(:wait_for_output) end it "should set stdin to the stdinfile if specified" do input = tmpfile('stdin') FileUtils.touch(input) Puppet::Util::Execution.expects(executor).with do |_,_,stdin,_,_| stdin.path == input end.returns(rval) Puppet::Util::Execution.execute('test command', :stdinfile => input) end it "should set stdin to the null file if not specified" do Puppet::Util::Execution.expects(executor).with do |_,_,stdin,_,_| stdin.path == null_file end.returns(rval) Puppet::Util::Execution.execute('test command') end describe "when squelch is set" do it "should set stdout and stderr to the null file" do Puppet::Util::Execution.expects(executor).with do |_,_,_,stdout,stderr| stdout.path == null_file and stderr.path == null_file end.returns(rval) Puppet::Util::Execution.execute('test command', :squelch => true) end end describe "when squelch is not set" do it "should set stdout to a temporary output file" do outfile = Tempfile.new('stdout') Tempfile.stubs(:new).returns(outfile) Puppet::Util::Execution.expects(executor).with do |_,_,_,stdout,_| stdout.path == outfile.path end.returns(rval) Puppet::Util::Execution.execute('test command', :squelch => false) end it "should set stderr to the same file as stdout if combine is true" do outfile = Tempfile.new('stdout') Tempfile.stubs(:new).returns(outfile) Puppet::Util::Execution.expects(executor).with do |_,_,_,stdout,stderr| stdout.path == outfile.path and stderr.path == outfile.path end.returns(rval) Puppet::Util::Execution.execute('test command', :squelch => false, :combine => true) end it "should set stderr to the null device if combine is false" do outfile = Tempfile.new('stdout') Tempfile.stubs(:new).returns(outfile) Puppet::Util::Execution.expects(executor).with do |_,_,_,stdout,stderr| stdout.path == outfile.path and stderr.path == null_file end.returns(rval) Puppet::Util::Execution.execute('test command', :squelch => false, :combine => false) end end end describe "on Windows", :if => Puppet.features.microsoft_windows? do it "should always close the process and thread handles" do Puppet::Util::Execution.stubs(:execute_windows).returns(proc_info_stub) Puppet::Util::Windows::Process.expects(:wait_process).with(process_handle).raises('whatever') Process.expects(:CloseHandle).with(thread_handle) Process.expects(:CloseHandle).with(process_handle) expect { Puppet::Util::Execution.execute('test command') }.should raise_error(RuntimeError) end end end describe "#execute (posix locale)", :unless => Puppet.features.microsoft_windows? do before :each do # there is a danger here that ENV will be modified by exec_posix. Normally it would only affect the ENV # of a forked process, but, in some of the previous tests in this file we're stubbing Kernel.fork., which could # allow the method to override the "real" ENV. This shouldn't be a problem for these tests because they are # not stubbing Kernel.fork, but, better safe than sorry... so, to guard against this, we'll capture a snapshot # of ENV before each test. - @saved_env = clone_env + @saved_env = ENV.to_hash end after :each do # capture the current environment and make sure it's the same as it was before the test - cur_env = clone_env + cur_env = ENV.to_hash # we will get some fairly useless output if we just use the raw == operator on the hashes here, so we'll # be a bit more explicit and laborious in the name of making the error more useful... @saved_env.each_pair { |key,val| cur_env[key].should == val } (cur_env.keys - @saved_env.keys).should == [] end # build up a printf-style string that contains a command to get the value of an environment variable # from the operating system. We can substitute into this with the names of the desired environment variables later. get_env_var_cmd = 'echo $%s' # a sentinel value that we can use to emulate what locale environment variables might be set to on an international # system. lang_sentinel_value = "es_ES.UTF-8" # a temporary hash that contains sentinel values for each of the locale environment variables that we override in # "execute" locale_sentinel_env = {} Puppet::Util::POSIX::LOCALE_ENV_VARS.each { |var| locale_sentinel_env[var] = lang_sentinel_value } it "should override the locale environment variables when :override_locale is not set (defaults to true)" do # temporarily override the locale environment vars with a sentinel value, so that we can confirm that # execute is actually setting them. Puppet::Util.withenv(locale_sentinel_env) do Puppet::Util::POSIX::LOCALE_ENV_VARS.each do |var| # we expect that all of the POSIX vars will have been cleared except for LANG and LC_ALL expected_value = (['LANG', 'LC_ALL'].include?(var)) ? "C" : "" Puppet::Util::execute(get_env_var_cmd % var).strip.should == expected_value end end end it "should override the LANG environment variable when :override_locale is set to true" do # temporarily override the locale environment vars with a sentinel value, so that we can confirm that # execute is actually setting them. Puppet::Util.withenv(locale_sentinel_env) do Puppet::Util::POSIX::LOCALE_ENV_VARS.each do |var| # we expect that all of the POSIX vars will have been cleared except for LANG and LC_ALL expected_value = (['LANG', 'LC_ALL'].include?(var)) ? "C" : "" Puppet::Util::execute(get_env_var_cmd % var, {:override_locale => true}).strip.should == expected_value end end end it "should *not* override the LANG environment variable when :override_locale is set to false" do # temporarily override the locale environment vars with a sentinel value, so that we can confirm that # execute is not setting them. Puppet::Util.withenv(locale_sentinel_env) do Puppet::Util::POSIX::LOCALE_ENV_VARS.each do |var| Puppet::Util::execute(get_env_var_cmd % var, {:override_locale => false}).strip.should == lang_sentinel_value end end end it "should have restored the LANG and locale environment variables after execution" do # we'll do this once without any sentinel values, to give us a little more test coverage orig_env_vals = {} Puppet::Util::POSIX::LOCALE_ENV_VARS.each do |var| orig_env_vals[var] = ENV[var] end # now we can really execute any command--doesn't matter what it is... Puppet::Util::execute(get_env_var_cmd % 'anything', {:override_locale => true}) # now we check and make sure the original environment was restored Puppet::Util::POSIX::LOCALE_ENV_VARS.each do |var| ENV[var].should == orig_env_vals[var] end # now, once more... but with our sentinel values Puppet::Util.withenv(locale_sentinel_env) do # now we can really execute any command--doesn't matter what it is... Puppet::Util::execute(get_env_var_cmd % 'anything', {:override_locale => true}) # now we check and make sure the original environment was restored Puppet::Util::POSIX::LOCALE_ENV_VARS.each do |var| ENV[var].should == locale_sentinel_env[var] end end end end describe "#execute (posix user env vars)", :unless => Puppet.features.microsoft_windows? do # build up a printf-style string that contains a command to get the value of an environment variable # from the operating system. We can substitute into this with the names of the desired environment variables later. get_env_var_cmd = 'echo $%s' # a sentinel value that we can use to emulate what locale environment variables might be set to on an international # system. user_sentinel_value = "Abracadabra" # a temporary hash that contains sentinel values for each of the locale environment variables that we override in # "execute" user_sentinel_env = {} Puppet::Util::POSIX::USER_ENV_VARS.each { |var| user_sentinel_env[var] = user_sentinel_value } it "should unset user-related environment vars during execution" do # first we set up a temporary execution environment with sentinel values for the user-related environment vars # that we care about. Puppet::Util.withenv(user_sentinel_env) do # with this environment, we loop over the vars in question Puppet::Util::POSIX::USER_ENV_VARS.each do |var| # ensure that our temporary environment is set up as we expect ENV[var].should == user_sentinel_env[var] # run an "exec" via the provider and ensure that it unsets the vars Puppet::Util::execute(get_env_var_cmd % var).strip.should == "" # ensure that after the exec, our temporary env is still intact ENV[var].should == user_sentinel_env[var] end end end it "should have restored the user-related environment variables after execution" do # we'll do this once without any sentinel values, to give us a little more test coverage orig_env_vals = {} Puppet::Util::POSIX::USER_ENV_VARS.each do |var| orig_env_vals[var] = ENV[var] end # now we can really execute any command--doesn't matter what it is... Puppet::Util::execute(get_env_var_cmd % 'anything') # now we check and make sure the original environment was restored Puppet::Util::POSIX::USER_ENV_VARS.each do |var| ENV[var].should == orig_env_vals[var] end # now, once more... but with our sentinel values Puppet::Util.withenv(user_sentinel_env) do # now we can really execute any command--doesn't matter what it is... Puppet::Util::execute(get_env_var_cmd % 'anything') # now we check and make sure the original environment was restored Puppet::Util::POSIX::USER_ENV_VARS.each do |var| ENV[var].should == user_sentinel_env[var] end end end end describe "after execution" do before :each do stub_process_wait(0) if Puppet.features.microsoft_windows? Puppet::Util::Execution.stubs(:execute_windows).returns(proc_info_stub) else Puppet::Util::Execution.stubs(:execute_posix).returns(pid) end end it "should wait for the child process to exit" do Puppet::Util::Execution.stubs(:wait_for_output) Puppet::Util::Execution.execute('test command') end it "should close the stdin/stdout/stderr files used by the child" do stdin = mock 'file', :close stdout = mock 'file', :close stderr = mock 'file', :close File.expects(:open). times(3). returns(stdin). then.returns(stdout). then.returns(stderr) Puppet::Util::Execution.execute('test command', {:squelch => true, :combine => false}) end it "should read and return the output if squelch is false" do stdout = Tempfile.new('test') Tempfile.stubs(:new).returns(stdout) stdout.write("My expected command output") Puppet::Util::Execution.execute('test command').should == "My expected command output" end it "should not read the output if squelch is true" do stdout = Tempfile.new('test') Tempfile.stubs(:new).returns(stdout) stdout.write("My expected command output") Puppet::Util::Execution.execute('test command', :squelch => true).should == nil end it "should delete the file used for output if squelch is false" do stdout = Tempfile.new('test') path = stdout.path Tempfile.stubs(:new).returns(stdout) Puppet::Util::Execution.execute('test command') File.should_not be_exist(path) end it "should raise an error if failonfail is true and the child failed" do stub_process_wait(1) expect { Puppet::Util::Execution.execute('fail command', :failonfail => true) }.to raise_error(Puppet::ExecutionFailure, /Execution of 'fail command' returned 1/) end it "should not raise an error if failonfail is false and the child failed" do stub_process_wait(1) expect { Puppet::Util::Execution.execute('fail command', :failonfail => false) }.not_to raise_error end it "should not raise an error if failonfail is true and the child succeeded" do expect { Puppet::Util::Execution.execute('fail command', :failonfail => true) }.not_to raise_error end it "should respect default values for args that aren't overridden if a partial arg list is passed in" do stub_process_wait(1) expect { # here we are passing in a non-nil value for "arguments", but we aren't specifying a value for # :failonfail. We expect it to be set to its normal default value (true). Puppet::Util::Execution.execute('fail command', { :squelch => true }) }.to raise_error(Puppet::ExecutionFailure, /Execution of 'fail command' returned 1/) end end end describe "#execpipe" do it "should execute a string as a string" do Puppet::Util::Execution.expects(:open).with('| echo hello 2>&1').returns('hello') $CHILD_STATUS.expects(:==).with(0).returns(true) Puppet::Util::Execution.execpipe('echo hello').should == 'hello' end it "should execute an array by pasting together with spaces" do Puppet::Util::Execution.expects(:open).with('| echo hello 2>&1').returns('hello') $CHILD_STATUS.expects(:==).with(0).returns(true) Puppet::Util::Execution.execpipe(['echo', 'hello']).should == 'hello' end it "should fail if asked to fail, and the child does" do Puppet::Util::Execution.stubs(:open).returns('error message') $CHILD_STATUS.expects(:==).with(0).returns(false) expect { Puppet::Util::Execution.execpipe('echo hello') }. to raise_error Puppet::ExecutionFailure, /error message/ end it "should not fail if asked not to fail, and the child does" do Puppet::Util::Execution.stubs(:open).returns('error message') $CHILD_STATUS.stubs(:==).with(0).returns(false) expect do Puppet::Util::Execution.execpipe('echo hello', false).should == 'error message' end.not_to raise_error end end end