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.
- checksums.yaml +8 -8
- data/HISTORY.md +121 -2
- data/lib/beaker/dsl.rb +2 -2
- data/lib/beaker/dsl/helpers.rb +13 -1429
- data/lib/beaker/dsl/helpers/facter_helpers.rb +48 -0
- data/lib/beaker/dsl/helpers/hiera_helpers.rb +71 -0
- data/lib/beaker/dsl/helpers/host_helpers.rb +506 -0
- data/lib/beaker/dsl/helpers/puppet_helpers.rb +698 -0
- data/lib/beaker/dsl/helpers/tk_helpers.rb +101 -0
- data/lib/beaker/dsl/helpers/web_helpers.rb +115 -0
- data/lib/beaker/dsl/install_utils.rb +8 -1570
- data/lib/beaker/dsl/install_utils/ezbake_utils.rb +256 -0
- data/lib/beaker/dsl/install_utils/module_utils.rb +237 -0
- data/lib/beaker/dsl/install_utils/pe_utils.rb +518 -0
- data/lib/beaker/dsl/install_utils/puppet_utils.rb +722 -0
- data/lib/beaker/dsl/outcomes.rb +0 -4
- data/lib/beaker/dsl/roles.rb +0 -3
- data/lib/beaker/dsl/structure.rb +127 -4
- data/lib/beaker/dsl/wrappers.rb +0 -4
- data/lib/beaker/host.rb +23 -0
- data/lib/beaker/host/unix/pkg.rb +4 -4
- data/lib/beaker/host_prebuilt_steps.rb +11 -5
- data/lib/beaker/hypervisor/vagrant.rb +1 -0
- data/lib/beaker/hypervisor/vmpooler.rb +38 -0
- data/lib/beaker/logger.rb +10 -4
- data/lib/beaker/network_manager.rb +5 -4
- data/lib/beaker/options/command_line_parser.rb +7 -0
- data/lib/beaker/shared.rb +2 -1
- data/lib/beaker/shared/semvar.rb +41 -0
- data/lib/beaker/test_suite.rb +20 -6
- data/lib/beaker/version.rb +1 -1
- data/spec/beaker/dsl/helpers/facter_helpers_spec.rb +59 -0
- data/spec/beaker/dsl/helpers/hiera_helpers_spec.rb +96 -0
- data/spec/beaker/dsl/helpers/host_helpers_spec.rb +413 -0
- data/spec/beaker/dsl/{helpers_spec.rb → helpers/puppet_helpers_spec.rb} +2 -611
- data/spec/beaker/dsl/helpers/tk_helpers_spec.rb +83 -0
- data/spec/beaker/dsl/helpers/web_helpers_spec.rb +60 -0
- data/spec/beaker/dsl/install_utils/module_utils_spec.rb +241 -0
- data/spec/beaker/dsl/install_utils/pe_utils_spec.rb +475 -0
- data/spec/beaker/dsl/install_utils/puppet_utils_spec.rb +523 -0
- data/spec/beaker/dsl/structure_spec.rb +108 -0
- data/spec/beaker/host_prebuilt_steps_spec.rb +44 -0
- data/spec/beaker/host_spec.rb +41 -0
- data/spec/beaker/hypervisor/vagrant_spec.rb +2 -1
- data/spec/beaker/logger_spec.rb +9 -2
- data/spec/beaker/network_manager_spec.rb +7 -1
- data/spec/beaker/options/command_line_parser_spec.rb +3 -2
- data/spec/beaker/shared/semvar_spec.rb +36 -0
- data/spec/beaker/test_suite_spec.rb +48 -0
- data/spec/mocks.rb +10 -0
- metadata +23 -5
- data/lib/beaker/dsl/ezbake_utils.rb +0 -259
- 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|
|
data/lib/beaker/shared.rb
CHANGED
@@ -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
|
+
|
data/lib/beaker/test_suite.rb
CHANGED
@@ -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 ./
|
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
|
-
|
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(
|
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(
|
371
|
+
File.join(log_dir, name)
|
358
372
|
end
|
359
373
|
|
360
374
|
end
|
data/lib/beaker/version.rb
CHANGED
@@ -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
|