beaker 2.7.1 → 2.8.0

Sign up to get free protection for your applications and to get access to all the features.
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