beaker 2.7.1 → 2.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.
Files changed (53) hide show
  1. checksums.yaml +8 -8
  2. data/HISTORY.md +121 -2
  3. data/lib/beaker/dsl.rb +2 -2
  4. data/lib/beaker/dsl/helpers.rb +13 -1429
  5. data/lib/beaker/dsl/helpers/facter_helpers.rb +48 -0
  6. data/lib/beaker/dsl/helpers/hiera_helpers.rb +71 -0
  7. data/lib/beaker/dsl/helpers/host_helpers.rb +506 -0
  8. data/lib/beaker/dsl/helpers/puppet_helpers.rb +698 -0
  9. data/lib/beaker/dsl/helpers/tk_helpers.rb +101 -0
  10. data/lib/beaker/dsl/helpers/web_helpers.rb +115 -0
  11. data/lib/beaker/dsl/install_utils.rb +8 -1570
  12. data/lib/beaker/dsl/install_utils/ezbake_utils.rb +256 -0
  13. data/lib/beaker/dsl/install_utils/module_utils.rb +237 -0
  14. data/lib/beaker/dsl/install_utils/pe_utils.rb +518 -0
  15. data/lib/beaker/dsl/install_utils/puppet_utils.rb +722 -0
  16. data/lib/beaker/dsl/outcomes.rb +0 -4
  17. data/lib/beaker/dsl/roles.rb +0 -3
  18. data/lib/beaker/dsl/structure.rb +127 -4
  19. data/lib/beaker/dsl/wrappers.rb +0 -4
  20. data/lib/beaker/host.rb +23 -0
  21. data/lib/beaker/host/unix/pkg.rb +4 -4
  22. data/lib/beaker/host_prebuilt_steps.rb +11 -5
  23. data/lib/beaker/hypervisor/vagrant.rb +1 -0
  24. data/lib/beaker/hypervisor/vmpooler.rb +38 -0
  25. data/lib/beaker/logger.rb +10 -4
  26. data/lib/beaker/network_manager.rb +5 -4
  27. data/lib/beaker/options/command_line_parser.rb +7 -0
  28. data/lib/beaker/shared.rb +2 -1
  29. data/lib/beaker/shared/semvar.rb +41 -0
  30. data/lib/beaker/test_suite.rb +20 -6
  31. data/lib/beaker/version.rb +1 -1
  32. data/spec/beaker/dsl/helpers/facter_helpers_spec.rb +59 -0
  33. data/spec/beaker/dsl/helpers/hiera_helpers_spec.rb +96 -0
  34. data/spec/beaker/dsl/helpers/host_helpers_spec.rb +413 -0
  35. data/spec/beaker/dsl/{helpers_spec.rb → helpers/puppet_helpers_spec.rb} +2 -611
  36. data/spec/beaker/dsl/helpers/tk_helpers_spec.rb +83 -0
  37. data/spec/beaker/dsl/helpers/web_helpers_spec.rb +60 -0
  38. data/spec/beaker/dsl/install_utils/module_utils_spec.rb +241 -0
  39. data/spec/beaker/dsl/install_utils/pe_utils_spec.rb +475 -0
  40. data/spec/beaker/dsl/install_utils/puppet_utils_spec.rb +523 -0
  41. data/spec/beaker/dsl/structure_spec.rb +108 -0
  42. data/spec/beaker/host_prebuilt_steps_spec.rb +44 -0
  43. data/spec/beaker/host_spec.rb +41 -0
  44. data/spec/beaker/hypervisor/vagrant_spec.rb +2 -1
  45. data/spec/beaker/logger_spec.rb +9 -2
  46. data/spec/beaker/network_manager_spec.rb +7 -1
  47. data/spec/beaker/options/command_line_parser_spec.rb +3 -2
  48. data/spec/beaker/shared/semvar_spec.rb +36 -0
  49. data/spec/beaker/test_suite_spec.rb +48 -0
  50. data/spec/mocks.rb +10 -0
  51. metadata +23 -5
  52. data/lib/beaker/dsl/ezbake_utils.rb +0 -259
  53. data/spec/beaker/dsl/install_utils_spec.rb +0 -1242
@@ -137,6 +137,13 @@ module Beaker
137
137
  @cmd_options[:log_level] = val
138
138
  end
139
139
 
140
+ opts.on '--log-prefix PREFIX',
141
+ 'Use a custom prefix for your Beaker log files',
142
+ 'can provide nested directories (ie. face/man)',
143
+ '(defaults to hostfile name. ie. ../i/07.yml --> "07")' do |val|
144
+ @cmd_options[:log_prefix] = val
145
+ end
146
+
140
147
  opts.on '-d', '--[no-]dry-run',
141
148
  'Report what would happen on targets',
142
149
  '(default: false)' do |bool|
@@ -1,4 +1,4 @@
1
- [ 'repetition', 'error_handler', 'host_manager', 'timed' ].each do |lib|
1
+ [ 'repetition', 'error_handler', 'host_manager', 'timed', 'semvar' ].each do |lib|
2
2
  require "beaker/shared/#{lib}"
3
3
  end
4
4
  module Beaker
@@ -7,6 +7,7 @@ module Beaker
7
7
  include Beaker::Shared::HostManager
8
8
  include Beaker::Shared::Repetition
9
9
  include Beaker::Shared::Timed
10
+ include Beaker::Shared::Semvar
10
11
  end
11
12
  end
12
13
  include Beaker::Shared
@@ -0,0 +1,41 @@
1
+ module Beaker
2
+ module Shared
3
+ module Semvar
4
+
5
+ #Is semver-ish version a less than semver-ish version b
6
+ #@param [String] a A version of the from '\d.\d.\d.*'
7
+ #@param [String] b A version of the form '\d.\d.\d.*'
8
+ #@return [Boolean] true if a is less than b, otherwise return false
9
+ #
10
+ #@note 3.0.0-160-gac44cfb is greater than 3.0.0, and 2.8.2
11
+ #@note -rc being less than final builds is not yet implemented.
12
+ def version_is_less a, b
13
+ a_nums = a.split('-')[0].split('.')
14
+ b_nums = b.split('-')[0].split('.')
15
+ (0...a_nums.length).each do |i|
16
+ if i < b_nums.length
17
+ if a_nums[i] < b_nums[i]
18
+ return true
19
+ elsif a_nums[i] > b_nums[i]
20
+ return false
21
+ end
22
+ else
23
+ return false
24
+ end
25
+ end
26
+ #checks all dots, they are equal so examine the rest
27
+ a_rest = a.split('-', 2)[1]
28
+ b_rest = b.split('-', 2)[1]
29
+ if a_rest and b_rest and a_rest < b_rest
30
+ return false
31
+ elsif a_rest and not b_rest
32
+ return false
33
+ elsif not a_rest and b_rest
34
+ return true
35
+ end
36
+ return false
37
+ end
38
+ end
39
+ end
40
+ end
41
+
@@ -336,7 +336,7 @@ module Beaker
336
336
  # Gives a full file path for output to be written to, maintaining the latest symlink
337
337
  # @param [String] name The file name that we want to write to.
338
338
  # @param [String] log_dir The desired output directory.
339
- # A symlink will be made from ./parentdir/latest to that.
339
+ # A symlink will be made from ./basedir/latest to that.
340
340
  # @example
341
341
  # log_path('output.txt', 'log/2014-06-02_16_31_22')
342
342
  #
@@ -344,17 +344,31 @@ module Beaker
344
344
  #
345
345
  # ./log/2014-06-02_16_31_22/output.txt
346
346
  # ./log/latest -> 2014-06-02_16_31_22
347
+ #
348
+ # @example
349
+ # log_path('foo.log', 'log/man/date')
350
+ #
351
+ # This will create the structure:
352
+ #
353
+ # ./log/man/date/foo.log
354
+ # ./log/latest -> man/date
347
355
  def log_path(name, log_dir)
348
- log_parent_dir = File.dirname(log_dir)
349
356
  FileUtils.mkdir_p(log_dir) unless File.directory?(log_dir)
350
357
 
351
- latest = File.join(log_parent_dir, "latest")
358
+ base_dir = log_dir
359
+ link_dir = ''
360
+ while File.dirname(base_dir) != '.' do
361
+ link_dir = link_dir == '' ? File.basename(base_dir) : File.join(File.basename(base_dir), link_dir)
362
+ base_dir = File.dirname(base_dir)
363
+ end
364
+
365
+ latest = File.join(base_dir, "latest")
352
366
  if !File.exist?(latest) or File.symlink?(latest) then
353
- File.delete(latest) if File.exist?(latest)
354
- File.symlink(File.basename(log_dir), latest)
367
+ File.delete(latest) if File.exist?(latest) || File.symlink?(latest)
368
+ File.symlink(link_dir, latest)
355
369
  end
356
370
 
357
- File.join(log_parent_dir, 'latest', name)
371
+ File.join(log_dir, name)
358
372
  end
359
373
 
360
374
  end
@@ -1,5 +1,5 @@
1
1
  module Beaker
2
2
  module Version
3
- STRING = '2.7.1'
3
+ STRING = '2.8.0'
4
4
  end
5
5
  end
@@ -0,0 +1,59 @@
1
+ require 'spec_helper'
2
+
3
+ class ClassMixedWithDSLHelpers
4
+ include Beaker::DSL::Helpers
5
+ include Beaker::DSL::Wrappers
6
+ include Beaker::DSL::Roles
7
+ include Beaker::DSL::Patterns
8
+
9
+ def logger
10
+ RSpec::Mocks::Double.new('logger').as_null_object
11
+ end
12
+
13
+ end
14
+
15
+ describe ClassMixedWithDSLHelpers do
16
+ let( :command ){ 'ls' }
17
+ let( :host ) { double.as_null_object }
18
+ let( :result ) { Beaker::Result.new( host, command ) }
19
+
20
+ let( :master ) { make_host( 'master', :roles => %w( master agent default) ) }
21
+ let( :agent ) { make_host( 'agent', :roles => %w( agent ) ) }
22
+ let( :custom ) { make_host( 'custom', :roles => %w( custom agent ) ) }
23
+ let( :dash ) { make_host( 'console', :roles => %w( dashboard agent ) ) }
24
+ let( :db ) { make_host( 'db', :roles => %w( database agent ) ) }
25
+ let( :hosts ) { [ master, agent, dash, db, custom ] }
26
+
27
+
28
+ describe '#fact_on' do
29
+ it 'retrieves a fact on a single host' do
30
+ result.stdout = "family\n"
31
+ expect( subject ).to receive(:facter).with('osfamily',{}).once
32
+ expect( subject ).to receive(:on).and_return(result)
33
+
34
+ expect( subject.fact_on('host','osfamily') ).to be === result.stdout.chomp
35
+ end
36
+
37
+ it 'retrieves an array of facts from multiple hosts' do
38
+ allow( subject ).to receive( :hosts ).and_return( hosts )
39
+ times = hosts.length
40
+ result.stdout = "family\n"
41
+ hosts.each do |host|
42
+ expect( host ).to receive(:exec).and_return(result)
43
+ end
44
+
45
+ expect( subject.fact_on(hosts,'osfamily') ).to be === [result.stdout.chomp] * hosts.length
46
+
47
+ end
48
+ end
49
+
50
+ describe '#fact' do
51
+ it 'delegates to #fact_on with the default host' do
52
+ allow( subject ).to receive(:hosts).and_return(hosts)
53
+ expect( subject ).to receive(:fact_on).with(master,"osfamily",{}).once
54
+
55
+ subject.fact('osfamily')
56
+ end
57
+ end
58
+
59
+ end
@@ -0,0 +1,96 @@
1
+ require 'spec_helper'
2
+
3
+ class ClassMixedWithDSLHelpers
4
+ include Beaker::DSL::Helpers
5
+ include Beaker::DSL::Wrappers
6
+ include Beaker::DSL::Roles
7
+ include Beaker::DSL::Patterns
8
+
9
+ def logger
10
+ RSpec::Mocks::Double.new('logger').as_null_object
11
+ end
12
+
13
+ end
14
+
15
+ describe ClassMixedWithDSLHelpers do
16
+ let( :opts ) { Beaker::Options::Presets.env_vars }
17
+ let( :command ){ 'ls' }
18
+ let( :host ) { double.as_null_object }
19
+ let( :result ) { Beaker::Result.new( host, command ) }
20
+
21
+ let( :master ) { make_host( 'master', :roles => %w( master agent default) ) }
22
+ let( :agent ) { make_host( 'agent', :roles => %w( agent ) ) }
23
+ let( :custom ) { make_host( 'custom', :roles => %w( custom agent ) ) }
24
+ let( :dash ) { make_host( 'console', :roles => %w( dashboard agent ) ) }
25
+ let( :db ) { make_host( 'db', :roles => %w( database agent ) ) }
26
+ let( :hosts ) { [ master, agent, dash, db, custom ] }
27
+
28
+
29
+ describe "#write_hiera_config_on" do
30
+ let(:hierarchy) { [ 'nodes/%{::fqdn}', 'common' ] }
31
+ it 'on FOSS host' do
32
+ host = make_host('testhost', { :platform => 'ubuntu' } )
33
+ expect(subject).to receive(:create_remote_file).with(host, host.puppet['hiera_config'], /#{host[:hieradatadir]}/)
34
+ subject.write_hiera_config_on(host, hierarchy)
35
+ end
36
+
37
+ it 'on PE host' do
38
+ host = make_host('testhost', { :platform => 'ubuntu', :type => 'pe' } )
39
+ expect(subject).to receive(:create_remote_file).with(host, host.puppet['hiera_config'], /#{host[:hieradatadir]}/)
40
+ subject.write_hiera_config_on(host, hierarchy)
41
+ end
42
+
43
+ end
44
+
45
+ describe "#write_hiera_config" do
46
+ let(:hierarchy) { [ 'nodes/%{::fqdn}', 'common' ] }
47
+ it 'delegates to #write_hiera_config_on with the default host' do
48
+ allow( subject ).to receive( :hosts ).and_return( hosts )
49
+ expect( subject ).to receive( :write_hiera_config_on ).with( master, hierarchy).once
50
+ subject.write_hiera_config( hierarchy )
51
+ end
52
+
53
+ end
54
+
55
+ describe "#copy_hiera_data_to" do
56
+ let(:path) { 'spec/fixtures/hieradata' }
57
+ it 'on FOSS host' do
58
+ host = make_host('testhost', { :platform => 'ubuntu' } )
59
+ expect(subject).to receive(:scp_to).with(host, File.expand_path(path), host[:hieradatadir])
60
+ subject.copy_hiera_data_to(host, path)
61
+ end
62
+
63
+ it 'on PE host' do
64
+ host = make_host('testhost', { :platform => 'ubuntu', :type => 'pe' } )
65
+ expect(subject).to receive(:scp_to).with(host, File.expand_path(path), host[:hieradatadir])
66
+ subject.copy_hiera_data_to(host, path)
67
+ end
68
+ end
69
+
70
+ describe "#copy_hiera_data" do
71
+ let(:path) { 'spec/fixtures/hieradata' }
72
+ it 'delegates to #copy_hiera_data_to with the default host' do
73
+ allow( subject ).to receive( :hosts ).and_return( hosts )
74
+ expect( subject ).to receive( :copy_hiera_data_to ).with( master, path).once
75
+ subject.copy_hiera_data( path )
76
+ end
77
+
78
+ end
79
+
80
+ describe '#hiera_datadir' do
81
+ it 'returns the codedir based hieradatadir for AIO' do
82
+ host = hosts[0]
83
+ host['type'] = :aio
84
+ correct_answer = File.join(host.puppet['codedir'], 'hieradata')
85
+ expect( subject.hiera_datadir(host) ).to be === correct_answer
86
+ end
87
+
88
+ it 'returns the hieradata host value for anything not AIO (backwards compatible)' do
89
+ host_hieradatadir_value = '/home/fishing/man/pants'
90
+ host = hosts[0]
91
+ host[:hieradatadir] = host_hieradatadir_value
92
+ expect( subject.hiera_datadir(host) ).to be === host_hieradatadir_value
93
+ end
94
+ end
95
+
96
+ end
@@ -0,0 +1,413 @@
1
+ require 'spec_helper'
2
+
3
+ class ClassMixedWithDSLHelpers
4
+ include Beaker::DSL::Helpers
5
+ include Beaker::DSL::Wrappers
6
+ include Beaker::DSL::Roles
7
+ include Beaker::DSL::Patterns
8
+
9
+ def logger
10
+ RSpec::Mocks::Double.new('logger').as_null_object
11
+ end
12
+
13
+ end
14
+
15
+ describe ClassMixedWithDSLHelpers do
16
+ let( :opts ) { Beaker::Options::Presets.env_vars }
17
+ let( :command ){ 'ls' }
18
+ let( :host ) { double.as_null_object }
19
+ let( :result ) { Beaker::Result.new( host, command ) }
20
+
21
+ let( :master ) { make_host( 'master', :roles => %w( master agent default) ) }
22
+ let( :agent ) { make_host( 'agent', :roles => %w( agent ) ) }
23
+ let( :custom ) { make_host( 'custom', :roles => %w( custom agent ) ) }
24
+ let( :dash ) { make_host( 'console', :roles => %w( dashboard agent ) ) }
25
+ let( :db ) { make_host( 'db', :roles => %w( database agent ) ) }
26
+ let( :hosts ) { [ master, agent, dash, db, custom ] }
27
+
28
+ describe '#on' do
29
+
30
+ before :each do
31
+ result.stdout = 'stdout'
32
+ result.stderr = 'stderr'
33
+ result.exit_code = 0
34
+ end
35
+
36
+ it 'allows the environment the command is run within to be specified' do
37
+ allow( subject ).to receive( :hosts ).and_return( hosts )
38
+
39
+ expect( Beaker::Command ).to receive( :new ).
40
+ with( 'ls ~/.bin', [], {'ENV' => { :HOME => '/tmp/test_home' }} )
41
+
42
+ subject.on( host, 'ls ~/.bin', :environment => {:HOME => '/tmp/test_home' } )
43
+ end
44
+
45
+ it 'if the host is a String Object, finds the matching hosts with that String as role' do
46
+ allow( subject ).to receive( :hosts ).and_return( hosts )
47
+
48
+ expect( master ).to receive( :exec ).once
49
+
50
+ subject.on( 'master', 'echo hello')
51
+
52
+ end
53
+
54
+ it 'if the host is a Symbol Object, finds the matching hsots with that Symbol as role' do
55
+ allow( subject ).to receive( :hosts ).and_return( hosts )
56
+
57
+ expect( master ).to receive( :exec ).once
58
+
59
+ subject.on( :master, 'echo hello')
60
+
61
+ end
62
+
63
+ it 'delegates to itself for each host passed' do
64
+ allow( subject ).to receive( :hosts ).and_return( hosts )
65
+ expected = []
66
+ hosts.each_with_index do |host, i|
67
+ expected << i
68
+ expect( host ).to receive( :exec ).and_return( i )
69
+ end
70
+
71
+ results = subject.on( hosts, command )
72
+ expect( results ).to be == expected
73
+ end
74
+
75
+ context 'upon command completion' do
76
+ before :each do
77
+ allow( subject ).to receive( :hosts ).and_return( hosts )
78
+ expect( host ).to receive( :exec ).and_return( result )
79
+ @res = subject.on( host, command )
80
+ end
81
+
82
+ it 'returns the result of the action' do
83
+ expect( @res ).to be == result
84
+ end
85
+
86
+ it 'provides access to stdout' do
87
+ expect( @res.stdout ).to be == 'stdout'
88
+ end
89
+
90
+ it 'provides access to stderr' do
91
+ expect( @res.stderr ).to be == 'stderr'
92
+ end
93
+
94
+ it 'provides access to exit_code' do
95
+ expect( @res.exit_code ).to be == 0
96
+ end
97
+ end
98
+
99
+ context 'when passed a block with arity of 1' do
100
+ before :each do
101
+ allow( subject ).to receive( :hosts ).and_return( hosts )
102
+ expect( host ).to receive( :exec ).and_return( result )
103
+ end
104
+
105
+ it 'yields result' do
106
+ subject.on host, command do |containing_class|
107
+ expect( containing_class ).
108
+ to be_an_instance_of( Beaker::Result )
109
+ end
110
+ end
111
+
112
+ it 'provides access to stdout' do
113
+ subject.on host, command do |containing_class|
114
+ expect( containing_class.stdout ).to be == 'stdout'
115
+ end
116
+ end
117
+
118
+ it 'provides access to stderr' do
119
+ subject.on host, command do |containing_class|
120
+ expect( containing_class.stderr ).to be == 'stderr'
121
+ end
122
+ end
123
+
124
+ it 'provides access to exit_code' do
125
+ subject.on host, command do |containing_class|
126
+ expect( containing_class.exit_code ).to be == 0
127
+ end
128
+ end
129
+ end
130
+
131
+ context 'when passed a block with arity of 0' do
132
+ before :each do
133
+ allow( subject ).to receive( :hosts ).and_return( hosts )
134
+ expect( host ).to receive( :exec ).and_return( result )
135
+ end
136
+
137
+ it 'yields self' do
138
+ subject.on host, command do
139
+ expect( subject ).
140
+ to be_an_instance_of( ClassMixedWithDSLHelpers )
141
+ end
142
+ end
143
+
144
+ it 'provides access to stdout' do
145
+ subject.on host, command do
146
+ expect( subject.stdout ).to be == 'stdout'
147
+ end
148
+ end
149
+
150
+ it 'provides access to stderr' do
151
+ subject.on host, command do
152
+ expect( subject.stderr ).to be == 'stderr'
153
+ end
154
+ end
155
+
156
+ it 'provides access to exit_code' do
157
+ subject.on host, command do
158
+ expect( subject.exit_code ).to be == 0
159
+ end
160
+ end
161
+ end
162
+
163
+ end
164
+
165
+ describe "#retry_on" do
166
+ it 'fails correctly when command never succeeds' do
167
+ result.stdout = 'stdout'
168
+ result.stderr = 'stderr'
169
+ result.exit_code = 1
170
+
171
+ retries = 5
172
+
173
+ opts = {
174
+ :max_retries => retries,
175
+ :retry_interval => 0.0001,
176
+ }
177
+
178
+ allow( subject ).to receive(:on).and_return(result)
179
+ expect( subject ).to receive(:on).exactly(retries+2)
180
+ expect { subject.retry_on(host, command, opts) }.to raise_error(RuntimeError)
181
+ end
182
+
183
+ it 'will return success correctly if it succeeds the first time' do
184
+ result.stdout = 'stdout'
185
+ result.stderr = 'stderr'
186
+ result.exit_code = 0
187
+
188
+ opts = {
189
+ :max_retries => 5,
190
+ :retry_interval => 0.0001,
191
+ }
192
+
193
+ allow( subject ).to receive(:on).and_return(result)
194
+ expect( subject ).to receive(:on).once
195
+
196
+ result_given = subject.retry_on(host, command, opts)
197
+ expect(result_given.exit_code).to be === 0
198
+ end
199
+
200
+ it 'will return success correctly if it succeeds after failing a few times' do
201
+ result.stdout = 'stdout'
202
+ result.stderr = 'stderr'
203
+
204
+ opts = {
205
+ :max_retries => 10,
206
+ :retry_interval => 0.1,
207
+ }
208
+
209
+ reps_num = 4
210
+ count = 0
211
+ allow( subject ).to receive(:on) do
212
+ result.exit_code = count > reps_num ? 0 : 1
213
+ count += 1
214
+ result
215
+ end
216
+ expect( subject ).to receive(:on).exactly(reps_num + 2)
217
+
218
+ result_given = subject.retry_on(host, command, opts)
219
+ expect(result_given.exit_code).to be === 0
220
+ end
221
+ end
222
+
223
+ describe "shell" do
224
+ it 'delegates to #on with the default host' do
225
+ allow( subject ).to receive( :hosts ).and_return( hosts )
226
+
227
+ expect( subject ).to receive( :on ).with( master, "echo hello", {}).once
228
+
229
+ subject.shell( "echo hello" )
230
+ end
231
+ end
232
+
233
+ describe '#scp_from' do
234
+ it 'delegates to the host' do
235
+ allow( subject ).to receive( :hosts ).and_return( hosts )
236
+ expect( subject ).to receive( :logger ).exactly( hosts.length ).times
237
+ expect( result ).to receive( :log ).exactly( hosts.length ).times
238
+
239
+ hosts.each do |host|
240
+ expect( host ).to receive( :do_scp_from ).and_return( result )
241
+ end
242
+
243
+ subject.scp_from( hosts, '/var/log/my.log', 'log/my.log' )
244
+ end
245
+ end
246
+
247
+ describe '#scp_to' do
248
+ it 'delegates to the host' do
249
+ allow( subject ).to receive( :hosts ).and_return( hosts )
250
+ expect( subject ).to receive( :logger ).exactly( hosts.length ).times
251
+ expect( result ).to receive( :log ).exactly( hosts.length ).times
252
+
253
+ hosts.each do |host|
254
+ expect( host ).to receive( :do_scp_to ).and_return( result )
255
+ end
256
+
257
+ subject.scp_to( hosts, '/var/log/my.log', 'log/my.log' )
258
+ end
259
+ end
260
+
261
+ describe '#rsync_to' do
262
+ it 'delegates to the host' do
263
+ allow( subject ).to receive( :hosts ).and_return( hosts )
264
+
265
+ hosts.each do |host|
266
+ expect( host ).to receive( :do_rsync_to ).and_return( result )
267
+ end
268
+
269
+ subject.rsync_to( hosts, '/var/log/my.log', 'log/my.log' )
270
+ end
271
+ end
272
+
273
+ describe '#create_remote_file using scp' do
274
+ it 'scps the contents passed in to the hosts' do
275
+ my_opts = { :silent => true }
276
+ tmpfile = double
277
+
278
+ expect( tmpfile ).to receive( :path ).exactly( 2 ).times.
279
+ and_return( '/local/path/to/blah' )
280
+
281
+ expect( Tempfile ).to receive( :open ).and_yield( tmpfile )
282
+
283
+ expect( File ).to receive( :open )
284
+
285
+ expect( subject ).to receive( :scp_to ).
286
+ with( hosts, '/local/path/to/blah', '/remote/path', my_opts )
287
+
288
+ subject.create_remote_file( hosts, '/remote/path', 'blah', my_opts )
289
+ end
290
+ end
291
+
292
+ describe '#create_remote_file using rsync' do
293
+ it 'scps the contents passed in to the hosts' do
294
+ my_opts = { :silent => true, :protocol => 'rsync' }
295
+ tmpfile = double
296
+
297
+ expect( tmpfile ).to receive( :path ).exactly( 2 ).times.
298
+ and_return( '/local/path/to/blah' )
299
+
300
+ expect( Tempfile ).to receive( :open ).and_yield( tmpfile )
301
+
302
+ expect( File ).to receive( :open )
303
+
304
+ expect( subject ).to receive( :rsync_to ).
305
+ with( hosts, '/local/path/to/blah', '/remote/path', my_opts )
306
+
307
+ subject.create_remote_file( hosts, '/remote/path', 'blah', my_opts )
308
+ end
309
+ end
310
+
311
+ describe '#create_tmpdir_on' do
312
+ let(:host) { {'user' => 'puppet'} }
313
+ let(:result) { double.as_null_object }
314
+
315
+ before :each do
316
+ allow(host).to receive(:result).and_return(result)
317
+ allow(result).to receive(:exit_code).and_return(0)
318
+ allow(result).to receive(:stdout).and_return('puppet')
319
+ end
320
+
321
+ context 'with no user argument' do
322
+
323
+ context 'with no path name argument' do
324
+ it 'executes chown once' do
325
+ expect(subject).to receive(:on).with(host, /^getent passwd puppet/).and_return(result)
326
+ expect(host).to receive(:tmpdir).with(/\/tmp\/beaker.*/)
327
+ expect(subject).to receive(:on).with(host, /chown puppet.puppet.*/)
328
+ subject.create_tmpdir_on(host, '/tmp/beaker')
329
+ end
330
+ end
331
+
332
+ context 'with path name argument' do
333
+ it 'executes chown once' do
334
+ expect(subject).to receive(:on).with(host, /^getent passwd puppet/).and_return(result)
335
+ expect(host).to receive(:tmpdir).with(/\/tmp\/bogus.*/).and_return("/tmp/bogus")
336
+ expect(subject).to receive(:on).with(host, /chown puppet.puppet \/tmp\/bogus.*/)
337
+ subject.create_tmpdir_on(host, "/tmp/bogus")
338
+ end
339
+ end
340
+
341
+ end
342
+
343
+ context 'with an valid user argument' do
344
+ it 'executes chown once' do
345
+ expect(subject).to receive(:on).with(host, /^getent passwd curiousgeorge/).and_return(result)
346
+ expect(host).to receive(:tmpdir).with(/\/tmp\/bogus.*/).and_return("/tmp/bogus")
347
+ expect(subject).to receive(:on).with(host, /chown curiousgeorge.curiousgeorge \/tmp\/bogus.*/)
348
+ subject.create_tmpdir_on(host, "/tmp/bogus", "curiousgeorge")
349
+ end
350
+ end
351
+
352
+ context 'with a invalid user argument' do
353
+ it 'executes chown once' do
354
+ allow(result).to receive(:exit_code).and_return(1)
355
+ expect(subject).to receive(:on).with(host, /^getent passwd curiousgeorge/).and_return(result)
356
+ expect{
357
+ subject.create_tmpdir_on(host, "/tmp/bogus", "curiousgeorge")
358
+ }.to raise_error(RuntimeError, /User curiousgeorge does not exist on/)
359
+ end
360
+ end
361
+
362
+ end
363
+
364
+ describe '#run_script_on' do
365
+ it 'scps the script to a tmpdir and executes it on host(s)' do
366
+ expect( subject ).to receive( :scp_to )
367
+ expect( subject ).to receive( :on )
368
+ subject.run_script_on( 'host', '~/.bin/make-enterprisy' )
369
+ end
370
+ end
371
+
372
+ describe '#run_script' do
373
+ it 'delegates to #run_script_on with the default host' do
374
+ allow( subject ).to receive( :hosts ).and_return( hosts )
375
+
376
+ expect( subject ).to receive( :run_script_on ).with( master, "/tmp/test.sh", {}).once
377
+
378
+ subject.run_script( '/tmp/test.sh' )
379
+ end
380
+ end
381
+
382
+ describe '#add_system32_hosts_entry' do
383
+ before do
384
+ allow( subject ).to receive(:on).and_return(Beaker::Result.new({},''))
385
+ end
386
+ context 'on debian' do
387
+ let(:platform) { 'debian-7-amd64' }
388
+ let(:host) { make_host('testbox.test.local', :platform => 'debian-7-amd64') }
389
+ it 'logs message - nothing to do on this host' do
390
+ expect( Beaker::Command ).to receive( :new ).never
391
+
392
+ expect {
393
+ subject.add_system32_hosts_entry(host, {})
394
+ }.to raise_error
395
+ end
396
+ end
397
+ context 'on windows' do
398
+ let(:platform) { 'windows-2008R2-amd64' }
399
+ let(:host) { make_host('testbox.test.local', :platform => 'windows-2008R2-amd64') }
400
+ it 'it add an entry into the /etc/hosts file' do
401
+ entry = { 'ip' => '23.251.154.122', 'name' => 'forge.puppetlabs.com' }
402
+ expect(subject).to receive(:on) do |host, command|
403
+ expect(command.command).to eq('powershell.exe')
404
+ expect(command.args).to eq(["-ExecutionPolicy Bypass", "-InputFormat None", "-NoLogo", "-NoProfile", "-NonInteractive", "-Command $text = \\\"23.251.154.122`t`tforge.puppetlabs.com\\\"; Add-Content -path 'C:\\Windows\\System32\\Drivers\\etc\\hosts' -value $text"])
405
+ end
406
+
407
+
408
+ subject.add_system32_hosts_entry(host, entry)
409
+ end
410
+ end
411
+ end
412
+
413
+ end