beaker 1.7.0 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,6 +3,7 @@ module Beaker
3
3
  module Validator
4
4
  PACKAGES = ['curl']
5
5
  UNIX_PACKAGES = ['ntpdate']
6
+ SLES_PACKAGES = ['ntp']
6
7
 
7
8
  def self.validate(hosts, logger)
8
9
  hosts.each do |host|
@@ -11,12 +12,20 @@ module Beaker
11
12
  host.install_package pkg
12
13
  end
13
14
  end
14
- if host['platform'] !~ /(windows)|(aix)|(solaris)/
15
- UNIX_PACKAGES.each do |pkg|
16
- if not host.check_for_package pkg
17
- host.install_package pkg
15
+ case
16
+ when host['platform'] =~ /sles-/
17
+ SLES_PACKAGES.each do |pkg|
18
+ if not host.check_for_package pkg
19
+ host.install_package pkg
20
+ end
21
+ end
22
+
23
+ when host['platform'] !~ /(windows)|(aix)|(solaris)/
24
+ UNIX_PACKAGES.each do |pkg|
25
+ if not host.check_for_package pkg
26
+ host.install_package pkg
27
+ end
18
28
  end
19
- end
20
29
  end
21
30
  end
22
31
  rescue => e
@@ -1,5 +1,5 @@
1
1
  module Beaker
2
2
  module Version
3
- STRING = '1.7.0'
3
+ STRING = '1.8.0'
4
4
  end
5
5
  end
@@ -8,6 +8,12 @@ module Beaker
8
8
  basic_hosts }
9
9
  let( :master_certname ) { 'master_certname' }
10
10
 
11
+ it 'generates 3.2 answers for 3.3 hosts' do
12
+ @ver = '3.3'
13
+ Beaker::Answers::Version32.should_receive( :answers ).with( hosts, master_certname, {}).once
14
+ subject.answers( @ver, hosts, master_certname, {} )
15
+ end
16
+
11
17
  it 'generates 3.2 answers for 3.2 hosts' do
12
18
  @ver = '3.2'
13
19
  Beaker::Answers::Version32.should_receive( :answers ).with( hosts, master_certname, {}).once
@@ -63,7 +69,15 @@ module Beaker
63
69
  it 'should add q_upgrade_with_unknown_disk_space to the dashboard on upgrade' do
64
70
  @ver = '3.2'
65
71
  expect( subject.answers( hosts, master_certname, {:type => :upgrade} )['vm2']).to include :q_upgrade_with_unknown_disk_space
66
- end
72
+ end
73
+
74
+ it 'should add answers to the host objects' do
75
+ @ver = '3.2'
76
+ answers = subject.answers( hosts, master_certname, {})
77
+ hosts.each do |host|
78
+ expect( host[:answers] ).to be === answers[host.name]
79
+ end
80
+ end
67
81
  end
68
82
 
69
83
  describe Version30 do
@@ -85,9 +99,18 @@ module Beaker
85
99
  it 'sets correct answers for a master' do
86
100
  expect( subject.answers( hosts, master_certname, {} )['vm1'] ).to be === { :q_install=>"y", :q_vendor_packages_install=>"y", :q_puppetagent_install=>"y", :q_puppet_cloud_install=>"y", :q_verify_packages=>"y", :q_puppet_symlinks_install=>"y", :q_puppetagent_certname=>hosts[0], :q_puppetagent_server=>master_certname, :q_puppetmaster_install=>"y", :q_all_in_one_install=>"y", :q_puppet_enterpriseconsole_install=>"y", :q_puppetdb_install=>"y", :q_database_install=>"y", :q_puppetdb_hostname=>hosts[0], :q_puppetdb_port=>8081, :q_puppetmaster_dnsaltnames=>"master_certname,puppet,#{hosts[0][:ip]}", :q_puppetmaster_enterpriseconsole_hostname=>hosts[0], :q_puppetmaster_enterpriseconsole_port=>443, :q_puppetmaster_certname=>"master_certname", :q_puppetdb_database_name=>"pe-puppetdb", :q_puppetdb_database_user=>"mYpdBu3r", :q_puppetdb_database_password=>"'~!@\#$%^*-/ aZ'", :q_puppet_enterpriseconsole_auth_database_name=>"console_auth", :q_puppet_enterpriseconsole_auth_database_user=>"mYu7hu3r", :q_puppet_enterpriseconsole_auth_database_password=>"'~!@\#$%^*-/ aZ'", :q_puppet_enterpriseconsole_database_name=>"console", :q_puppet_enterpriseconsole_database_user=>"mYc0nS03u3r", :q_puppet_enterpriseconsole_database_password=>"'~!@\#$%^*-/ aZ'", :q_database_host=>hosts[0], :q_database_port=>5432, :q_pe_database=>"y", :q_puppet_enterpriseconsole_inventory_hostname=>hosts[0], :q_puppet_enterpriseconsole_inventory_certname=>hosts[0], :q_puppet_enterpriseconsole_inventory_dnsaltnames=>hosts[0], :q_puppet_enterpriseconsole_inventory_port=>8140, :q_puppet_enterpriseconsole_master_hostname=>hosts[0], :q_puppet_enterpriseconsole_auth_user_email=>"'admin@example.com'", :q_puppet_enterpriseconsole_auth_password=>"'~!@\#$%^*-/ aZ'", :q_puppet_enterpriseconsole_httpd_port=>443, :q_puppet_enterpriseconsole_smtp_host=>"'vm1'", :q_puppet_enterpriseconsole_smtp_use_tls=>"'n'", :q_puppet_enterpriseconsole_smtp_port=>"'25'", :q_database_root_password=>"'=ZYdjiP3jCwV5eo9s1MBd'", :q_database_root_user=>"pe-postgres" }
87
101
  end
102
+
88
103
  it 'generates nil answers for a windows host' do
89
104
  expect( subject.answers( hosts, master_certname, {} )['vm2'] ).to be === nil
90
105
  end
106
+
107
+ it 'should add answers to the host objects' do
108
+ @ver = '3.0'
109
+ answers = subject.answers( hosts, master_certname, {})
110
+ hosts.each do |host|
111
+ expect( host[:answers] ).to be === answers[host.name]
112
+ end
113
+ end
91
114
  end
92
115
 
93
116
  describe Version28 do
@@ -109,6 +132,13 @@ module Beaker
109
132
  expect( subject.answers( hosts, master_certname, {} )['vm2'] ).to be === nil
110
133
  end
111
134
 
135
+ it 'should add answers to the host objects' do
136
+ @ver = '2.8'
137
+ answers = subject.answers( hosts, master_certname, {})
138
+ hosts.each do |host|
139
+ expect( host[:answers] ).to be === answers[host.name]
140
+ end
141
+ end
112
142
 
113
143
  end
114
144
  describe Version20 do
@@ -130,6 +160,14 @@ module Beaker
130
160
  expect( subject.answers( hosts, master_certname, {} )['vm2'] ).to be === nil
131
161
  end
132
162
 
163
+ it 'should add answers to the host objects' do
164
+ @ver = '2.0'
165
+ answers = subject.answers( hosts, master_certname, {})
166
+ hosts.each do |host|
167
+ expect( host[:answers] ).to be === answers[host.name]
168
+ end
169
+ end
170
+
133
171
  end
134
172
 
135
173
  end
@@ -95,10 +95,10 @@ describe ClassMixedWithDSLHelpers do
95
95
  host.should_receive( :exec ).and_return( result )
96
96
  end
97
97
 
98
- it 'yields self' do
98
+ it 'yields result' do
99
99
  subject.on host, command do |containing_class|
100
100
  expect( containing_class ).
101
- to be_an_instance_of( ClassMixedWithDSLHelpers )
101
+ to be_an_instance_of( Beaker::Result )
102
102
  end
103
103
  end
104
104
 
@@ -651,11 +651,17 @@ describe ClassMixedWithDSLHelpers do
651
651
  end
652
652
 
653
653
  describe '#with_puppet_running_on' do
654
- let(:is_pe) { false }
655
- let(:host) { FakeHost.new(:pe => is_pe) }
656
654
  let(:test_case_path) { 'testcase/path' }
657
655
  let(:tmpdir_path) { '/tmp/tmpdir' }
658
656
  let(:puppet_path) { '/puppet/path' }
657
+ let(:is_pe) { false }
658
+ let(:host) do
659
+ FakeHost.new(:pe => is_pe,
660
+ :options => {
661
+ 'puppetpath' => puppet_path,
662
+ 'platform' => 'el'
663
+ })
664
+ end
659
665
 
660
666
  def stub_host_and_subject_to_allow_the_default_testdir_argument_to_be_created
661
667
  subject.instance_variable_set(:@path, test_case_path)
@@ -665,7 +671,6 @@ describe ClassMixedWithDSLHelpers do
665
671
 
666
672
  before do
667
673
  stub_host_and_subject_to_allow_the_default_testdir_argument_to_be_created
668
- host.stub(:[]).and_return(puppet_path)
669
674
  end
670
675
 
671
676
  it "raises an ArgumentError if you try to submit a String instead of a Hash of options" do
@@ -790,6 +795,26 @@ describe ClassMixedWithDSLHelpers do
790
795
  end.to raise_error(RuntimeError, /failed.*because.*Failed while yielding./)
791
796
  end
792
797
 
798
+ it 'dumps the puppet logs if there is an error in the teardown' do
799
+ host.should_receive(:port_open?).with(8140).and_return(true)
800
+
801
+ subject.logger.should_receive(:notify).with(/Dumping master log/)
802
+
803
+ expect do
804
+ subject.with_puppet_running_on(host, {})
805
+ end.to raise_error(RuntimeError, /Also failed in teardown/)
806
+ end
807
+
808
+ it 'does not mask the teardown error with an error from dumping the logs' do
809
+ host.should_receive(:port_open?).with(8140).and_return(true)
810
+
811
+ subject.logger.should_receive(:notify).with(/Dumping master log/).and_raise("Error from dumping logs")
812
+
813
+ expect do
814
+ subject.with_puppet_running_on(host, {})
815
+ end.to raise_error(RuntimeError, /Also failed in teardown/)
816
+ end
817
+
793
818
  it 'does not swallow a teardown exception if no earlier exception was raised' do
794
819
  host.should_receive(:port_open?).with(8140).and_return(true)
795
820
  subject.logger.should_not_receive(:error)
@@ -9,7 +9,6 @@ module Beaker
9
9
  let(:hosts_path) { File.join(File.expand_path(File.dirname(__FILE__)), "data", "hosts.cfg") }
10
10
  let(:badyaml_path) { File.join(File.expand_path(File.dirname(__FILE__)), "data", "badyaml.cfg") }
11
11
  let(:home) { ENV['HOME'] }
12
- let(:platforms_regex) { Parser::PLATFORMS }
13
12
 
14
13
  it "supports usage function" do
15
14
  expect{parser.usage}.to_not raise_error
@@ -21,26 +20,6 @@ module Beaker
21
20
  expect(parser.repo).to be === "#{repo}"
22
21
  end
23
22
 
24
- #read through the file of possible platform values, correctly identify the 50 invalid platform values
25
- describe "recognizes valid platforms" do
26
-
27
- it "accepts correctly formatted platform values" do
28
- expect( 'oracle-version-arch' =~ platforms_regex ).to be === 0
29
- end
30
-
31
- it "rejects non-supported osfamilies" do
32
- expect( 'amazon6-version-arch' =~ platforms_regex ).to be === nil
33
- end
34
-
35
- it "rejects platforms without version/arch" do
36
- expect( 'ubuntu-5' =~ platforms_regex ).to be === nil
37
- end
38
-
39
- it "rejects platforms that do not have osfamily at start of string" do
40
- expect( 'oel-r5-u6-x86-64' =~ platforms_regex ).to be === nil
41
- end
42
- end
43
-
44
23
  #test parse_install_options
45
24
  it "can transform --install PUPPET/3.1 into #{repo}/puppet.git#3.1" do
46
25
  opts = ["PUPPET/3.1"]
@@ -154,7 +133,7 @@ module Beaker
154
133
  it "can correctly combine arguments from different sources" do
155
134
  FakeFS.deactivate!
156
135
  args = ["-h", hosts_path, "--log-level", "debug", "--type", "git", "--install", "PUPPET/1.0,HIERA/hello"]
157
- expect(parser.parse_args(args)).to be === {:log_level=>"debug", :hosts_file=>hosts_path, :options_file=>nil, :type=>"git", :provision=>true, :preserve_hosts=>'never', :root_keys=>false, :quiet=>false, :xml=>false, :color=>true, :dry_run=>false, :timeout=>300, :fail_mode=>'slow', :timesync=>false, :repo_proxy=>false, :add_el_extras=>false, :consoleport=>443, :pe_dir=>"/opt/enterprise/dists", :pe_version_file=>"LATEST", :pe_version_file_win=>"LATEST-win", :dot_fog=>"#{home}/.fog", :help=>false, :ec2_yaml=>"config/image_templates/ec2.yaml", :ssh=>{:config=>false, :paranoid=>false, :timeout=>300, :auth_methods=>["publickey"], :port=>22, :forward_agent=>true, :keys=>["#{home}/.ssh/id_rsa"], :user_known_hosts_file=>"#{home}/.ssh/known_hosts"}, :install=>["git://github.com/puppetlabs/puppet.git#1.0", "git://github.com/puppetlabs/hiera.git#hello"], :HOSTS=>{:"pe-ubuntu-lucid"=>{:roles=>["agent", "dashboard", "database", "master"], :vmname=>"pe-ubuntu-lucid", :platform=>"ubuntu-10.04-i386", :snapshot=>"clean-w-keys", :hypervisor=>"fusion"}, :"pe-centos6"=>{:roles=>["agent"], :vmname=>"pe-centos6", :platform=>"el-6-i386", :hypervisor=>"fusion", :snapshot=>"clean-w-keys"}}, :nfs_server=>"none", :helper=>[], :load_path=>[], :tests=>[], :pre_suite=>[], :post_suite=>[], :modules=>[]}
136
+ expect(parser.parse_args(args)).to be === {:log_level=>"debug", :trace_limit=>10, :hosts_file=>hosts_path, :options_file=>nil, :type=>"git", :provision=>true, :preserve_hosts=>'never', :root_keys=>false, :quiet=>false, :xml=>false, :color=>true, :dry_run=>false, :timeout=>300, :fail_mode=>'slow', :timesync=>false, :repo_proxy=>false, :add_el_extras=>false, :consoleport=>443, :pe_dir=>"/opt/enterprise/dists", :pe_version_file=>"LATEST", :pe_version_file_win=>"LATEST-win", :dot_fog=>"#{home}/.fog", :help=>false, :ec2_yaml=>"config/image_templates/ec2.yaml", :ssh=>{:config=>false, :paranoid=>false, :timeout=>300, :auth_methods=>["publickey"], :port=>22, :forward_agent=>true, :keys=>["#{home}/.ssh/id_rsa"], :user_known_hosts_file=>"#{home}/.ssh/known_hosts"}, :install=>["git://github.com/puppetlabs/puppet.git#1.0", "git://github.com/puppetlabs/hiera.git#hello"], :HOSTS=>{:"pe-ubuntu-lucid"=>{:roles=>["agent", "dashboard", "database", "master"], :vmname=>"pe-ubuntu-lucid", :platform=>"ubuntu-10.04-i386", :snapshot=>"clean-w-keys", :hypervisor=>"fusion"}, :"pe-centos6"=>{:roles=>["agent"], :vmname=>"pe-centos6", :platform=>"el-6-i386", :hypervisor=>"fusion", :snapshot=>"clean-w-keys"}}, :nfs_server=>"none", :helper=>[], :load_path=>[], :tests=>[], :pre_suite=>[], :post_suite=>[], :modules=>[]}
158
137
  end
159
138
 
160
139
  it "ensures that fail-mode is one of fast/slow" do
@@ -174,10 +153,10 @@ module Beaker
174
153
  {
175
154
  'HOSTS' => {
176
155
  :master => {
177
- :roles => ["master","agent"],
156
+ :roles => ["master","agent","arbitrary_role"],
178
157
  },
179
158
  :agent => {
180
- :roles => ["agent"],
159
+ :roles => ["agent","default","other_abitrary_role"],
181
160
  },
182
161
  }
183
162
  }
@@ -198,7 +177,7 @@ module Beaker
198
177
  it "restricts #{platform} hosts to agent for #{type}" do
199
178
  hosts_file = fake_hosts_file_for_platform(hosts, platform)
200
179
  args << "--hosts" << hosts_file
201
- expect { parser.parse_args(args) }.to raise_error(ArgumentError, /#{platform}.*can only have role 'agent'/)
180
+ expect { parser.parse_args(args) }.to raise_error(ArgumentError, /#{platform}.*may not have roles 'master', 'dashboard', or 'database'/)
202
181
  end
203
182
  end
204
183
 
@@ -0,0 +1,97 @@
1
+ require 'spec_helper'
2
+
3
+ module Beaker
4
+ describe Platform do
5
+
6
+ let( :logger ) { double( 'logger' ) }
7
+ let( :platform ) { Platform.new(@name) }
8
+
9
+ context 'initialize' do
10
+
11
+ describe "recognizes valid platforms" do
12
+
13
+ it "accepts correctly formatted platform values" do
14
+ @name = 'oracle-version-arch'
15
+ expect{ platform }.not_to raise_error
16
+ end
17
+
18
+ it "rejects non-supported osfamilies" do
19
+ @name = 'amazon6-version-arch'
20
+ expect{ platform }.to raise_error(ArgumentError)
21
+ end
22
+
23
+ it "rejects platforms without version/arch" do
24
+ @name = 'ubuntu-5'
25
+ expect{ platform }.to raise_error(ArgumentError)
26
+ end
27
+
28
+ it "rejects platforms that do not have osfamily at start of string" do
29
+ @name = 'o3l-r5-u6-x86'
30
+ expect{ platform }.to raise_error(ArgumentError)
31
+ end
32
+
33
+ end
34
+
35
+ end
36
+
37
+ context 'with_version_codename' do
38
+
39
+ it "can convert debian-7-xxx to debian-wheezy-xxx" do
40
+ @name = 'debian-7-xxx'
41
+ expect( platform.with_version_codename ).to be === 'debian-wheezy-xxx'
42
+ end
43
+
44
+ it "can convert debian-6-xxx to debian-squeeze-xxx" do
45
+ @name = 'debian-6-xxx'
46
+ expect( platform.with_version_codename ).to be === 'debian-squeeze-xxx'
47
+ end
48
+
49
+ it "can convert ubuntu-1310-xxx to ubuntu-saucy-xxx" do
50
+ @name = 'ubuntu-1310-xxx'
51
+ expect( platform.with_version_codename ).to be === 'ubuntu-saucy-xxx'
52
+ end
53
+
54
+ it "can convert ubuntu-12.10-xxx to ubuntu-quantal-xxx" do
55
+ @name = 'ubuntu-12.10-xxx'
56
+ expect( platform.with_version_codename ).to be === 'ubuntu-quantal-xxx'
57
+ end
58
+
59
+ it "leaves centos-7-xxx alone" do
60
+ @name = 'centos-7-xxx'
61
+ expect( platform.with_version_codename ).to be === 'centos-7-xxx'
62
+ end
63
+
64
+ end
65
+
66
+ context 'with_version_number' do
67
+
68
+ it "can convert debian-wheezy-xxx to debian-7-xxx" do
69
+ @name = 'debian-wheezy-xxx'
70
+ expect( platform.with_version_number ).to be === 'debian-7-xxx'
71
+ end
72
+
73
+ it "can convert debian-squeeze-xxx to debian-6-xxx" do
74
+ @name = 'debian-squeeze-xxx'
75
+ expect( platform.with_version_number ).to be === 'debian-6-xxx'
76
+ end
77
+
78
+ it "can convert ubuntu-saucy-xxx to ubuntu-1310-xxx" do
79
+ @name = 'ubuntu-saucy-xxx'
80
+ expect( platform.with_version_number ).to be === 'ubuntu-1310-xxx'
81
+ end
82
+
83
+ it "can convert ubuntu-quantal-xxx to ubuntu-1210-xxx" do
84
+ @name = 'ubuntu-quantal-xxx'
85
+ expect( platform.with_version_number ).to be === 'ubuntu-1210-xxx'
86
+ end
87
+
88
+ it "leaves centos-7-xxx alone" do
89
+ @name = 'centos-7-xxx'
90
+ expect( platform.with_version_number ).to be === 'centos-7-xxx'
91
+ end
92
+
93
+ end
94
+
95
+ end
96
+
97
+ end
@@ -15,6 +15,24 @@ module Beaker
15
15
 
16
16
  end
17
17
 
18
+ it "can retry on failure on unix hosts" do
19
+ @hosts = make_hosts( { :platform => 'unix', :exit_code => [1, 0] } )
20
+ ntp_control.stub( :sleep ).and_return(true)
21
+
22
+ Command.should_receive( :new ).with("ntpdate -t 20 #{ntpserver}").exactly( 6 ).times
23
+
24
+ ntp_control.timesync
25
+ end
26
+
27
+ it "eventually gives up and raises an error when unix hosts can't be synched" do
28
+ @hosts = make_hosts( { :platform => 'unix', :exit_code => 1 } )
29
+ ntp_control.stub( :sleep ).and_return(true)
30
+
31
+ Command.should_receive( :new ).with("ntpdate -t 20 #{ntpserver}").exactly( 5 ).times
32
+
33
+ expect{ ntp_control.timesync }.to raise_error
34
+ end
35
+
18
36
  it "can sync time on solaris-10 hosts" do
19
37
  @hosts = make_hosts( { :platform => 'solaris-10' } )
20
38
 
@@ -36,6 +54,16 @@ module Beaker
36
54
 
37
55
  end
38
56
 
57
+ it "can sync time on Sles hosts" do
58
+ @hosts = make_hosts( { :platform => 'sles-13.1-x64' } )
59
+
60
+ Command.should_receive( :new ).with("sntp #{ntpserver}").exactly( 3 ).times
61
+
62
+ ntp_control.timesync
63
+
64
+ end
65
+
66
+
39
67
  end
40
68
 
41
69
  end
@@ -6,6 +6,7 @@ module Beaker
6
6
  let( :validator ) { Beaker::Utils::Validator }
7
7
  let( :pkgs ) { Beaker::Utils::Validator::PACKAGES }
8
8
  let( :unix_only_pkgs ) { Beaker::Utils::Validator::UNIX_PACKAGES }
9
+ let( :sles_only_pkgs ) { Beaker::Utils::Validator::SLES_PACKAGES }
9
10
  let( :platform ) { @platform || 'unix' }
10
11
  let( :hosts ) { hosts = make_hosts( { :platform => platform } )
11
12
  hosts[0][:roles] = ['agent']
@@ -26,6 +27,10 @@ module Beaker
26
27
  host.should_receive( :check_for_package ).with( pkg ).once.and_return( false )
27
28
  host.should_receive( :install_package ).with( pkg ).once
28
29
  end
30
+ sles_only_pkgs.each do |pkg|
31
+ host.should_receive( :check_for_package).with( pkg ).never
32
+ host.should_receive( :install_package ).with( pkg ).never
33
+ end
29
34
 
30
35
  end
31
36
 
@@ -45,6 +50,34 @@ module Beaker
45
50
  host.should_receive( :check_for_package).with( pkg ).never
46
51
  host.should_receive( :install_package ).with( pkg ).never
47
52
  end
53
+ sles_only_pkgs.each do |pkg|
54
+ host.should_receive( :check_for_package).with( pkg ).never
55
+ host.should_receive( :install_package ).with( pkg ).never
56
+ end
57
+
58
+ end
59
+
60
+ validator.validate(hosts, logger)
61
+
62
+ end
63
+
64
+ it "can validate SLES hosts" do
65
+ @platform = 'sles-13.1-x64'
66
+
67
+ hosts.each do |host|
68
+ pkgs.each do |pkg|
69
+ host.should_receive( :check_for_package ).with( pkg ).once.and_return( false )
70
+ host.should_receive( :install_package ).with( pkg ).once
71
+ end
72
+ unix_only_pkgs.each do |pkg|
73
+ host.should_receive( :check_for_package).with( pkg ).never
74
+ host.should_receive( :install_package ).with( pkg ).never
75
+ end
76
+ sles_only_pkgs.each do |pkg|
77
+ host.should_receive( :check_for_package).with( pkg ).once.and_return( false )
78
+ host.should_receive( :install_package ).with( pkg ).once
79
+ end
80
+
48
81
  end
49
82
 
50
83
  validator.validate(hosts, logger)
@@ -58,12 +58,13 @@ module HostHelpers
58
58
 
59
59
  def generate_result (name, opts )
60
60
  result = double( 'result' )
61
- stdout = opts.has_key?(:stdout) ? opts[:stdout] : name
61
+ stdout = opts.has_key?(:stdout) ? opts[:stdout] : name
62
62
  stderr = opts.has_key?(:stderr) ? opts[:stderr] : name
63
63
  exit_code = opts.has_key?(:exit_code) ? opts[:exit_code] : 0
64
+ exit_code = [exit_code].flatten
64
65
  result.stub( :stdout ).and_return( stdout )
65
66
  result.stub( :stderr ).and_return( stderr )
66
- result.stub( :exit_code ).and_return( exit_code )
67
+ result.stub( :exit_code ).and_return( *exit_code )
67
68
  result
68
69
  end
69
70