beaker 2.46.0 → 2.47.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,49 @@
1
+ require 'beaker-hostgenerator'
2
+
3
+ namespace :beaker_quickstart do
4
+
5
+ desc 'Generate Default Beaker Host Config File'
6
+ task :gen_hosts do
7
+ cli = BeakerHostGenerator::CLI.new(['redhat7-64default.mdcal-redhat7-64af'])
8
+ FileUtils.mkdir_p('acceptance/config') # -p ignores when dir already exists
9
+ File.open("acceptance/config/default_hosts.yaml", 'w') do |fh|
10
+ fh.print(cli.execute)
11
+ end
12
+ end
13
+
14
+ desc 'Generate Default Pre-Suite'
15
+ task :gen_pre_suite do
16
+ FileUtils.mkdir_p('acceptance/setup') # -p ignores when dir already exists
17
+ File.open("acceptance/setup/default_pre_suite.rb", 'w') do |fh|
18
+ fh.print('install_puppet')
19
+ end
20
+ end
21
+
22
+ desc 'Generate Default Smoke Test'
23
+ task :gen_smoke_test do
24
+ FileUtils.mkdir_p('acceptance/tests') # -p ignores when dir already exists
25
+ File.open("acceptance/tests/default_smoke_test.rb", 'w') do |fh|
26
+ fh.print("test_name 'puppet install smoketest'
27
+ step 'puppet install smoketest: verify \\'puppet help\\' can be successfully called on
28
+ all hosts'
29
+ hosts.each do |host|
30
+ on host, puppet('help')
31
+ end")
32
+ end
33
+ end
34
+
35
+ desc 'Run Default Smoke Test'
36
+ task :run => ['beaker_quickstart:gen_hosts', 'beaker_quickstart:gen_pre_suite', 'beaker_quickstart:gen_smoke_test'] do
37
+ system(beaker_command)
38
+ end
39
+
40
+ end
41
+
42
+ def beaker_command
43
+ cmd_parts = []
44
+ cmd_parts << "beaker"
45
+ cmd_parts << "--hosts acceptance/config/default_hosts.yaml"
46
+ cmd_parts << "--pre-suite acceptance/setup/default_pre_suite.rb"
47
+ cmd_parts << "--tests acceptance/tests/default_smoke_test.rb"
48
+ cmd_parts.flatten.join(" ")
49
+ end
@@ -97,7 +97,7 @@ module Beaker
97
97
  cmd_parts = []
98
98
  cmd_parts << "beaker"
99
99
  cmd_parts << "--keyfile #{@keyfile}" if @keyfile
100
- cmd_parts << "--hosts #{@hosts}" if @hosts
100
+ cmd_parts << "--hosts #{@hosts}" if (@hosts!=nil && !@hosts.empty?)
101
101
  cmd_parts << "--tests #{tests}" if @tests
102
102
  cmd_parts << "--options-file #{@options_file}" if @options_file
103
103
  cmd_parts << "--type #{@type}" if @type
@@ -1,5 +1,5 @@
1
1
  module Beaker
2
2
  module Version
3
- STRING = '2.46.0'
3
+ STRING = '2.47.0'
4
4
  end
5
5
  end
@@ -77,6 +77,22 @@ describe ClassMixedWithDSLHelpers do
77
77
  subject.on( :master, 'echo hello')
78
78
  end
79
79
 
80
+ it 'executes in parallel if run_in_parallel=true' do
81
+ InParallel::InParallelExecutor.logger = logger
82
+ FakeFS.deactivate!
83
+ allow( subject ).to receive( :hosts ).and_return( hosts )
84
+ expected = []
85
+ hosts.each_with_index do |host, i|
86
+ expected << i
87
+ allow( host ).to receive( :exec ).and_return( i )
88
+ end
89
+
90
+ # This will only get hit if forking processes is supported and at least 2 items are being submitted to run in parallel
91
+ expect( InParallel::InParallelExecutor ).to receive(:_execute_in_parallel).with(any_args).and_call_original.exactly(5).times
92
+ results = subject.on( hosts, command, {:run_in_parallel => true})
93
+ expect( results ).to be == expected
94
+ end
95
+
80
96
  it 'delegates to itself for each host passed' do
81
97
  allow( subject ).to receive( :hosts ).and_return( hosts )
82
98
  expected = []
@@ -109,6 +109,28 @@ describe ClassMixedWithDSLHelpers do
109
109
  expect(result).to be_an(Array)
110
110
  end
111
111
 
112
+ it 'operates on an array of hosts in parallel' do
113
+ InParallel::InParallelExecutor.logger = logger
114
+ FakeFS.deactivate!
115
+ # This will only get hit if forking processes is supported and at least 2 items are being submitted to run in parallel
116
+ expect( InParallel::InParallelExecutor ).to receive(:_execute_in_parallel).with(any_args).and_call_original.exactly(2).times
117
+ allow( subject ).to receive( :hosts ).and_return( hosts )
118
+ the_hosts = [master, agent]
119
+
120
+ allow( subject ).to receive( :create_remote_file ).and_return( true )
121
+ the_hosts.each do |host|
122
+ allow( subject ).to receive( :puppet ).
123
+ and_return( 'puppet_command' )
124
+
125
+ allow( subject ).to receive( :on ).
126
+ with( host, 'puppet_command', :acceptable_exit_codes => [0] )
127
+ end
128
+
129
+ result = nil
130
+ result = subject.apply_manifest_on( the_hosts, 'include foobar', { :run_in_parallel => true } )
131
+ expect(result).to be_an(Array)
132
+ end
133
+
112
134
  it 'adds acceptable exit codes with :catch_failures' do
113
135
  allow( subject ).to receive( :hosts ).and_return( hosts )
114
136
  expect( subject ).to receive( :create_remote_file ).and_return( true )
@@ -402,6 +424,46 @@ describe ClassMixedWithDSLHelpers do
402
424
  subject.stop_agent_on( el_agent )
403
425
  end
404
426
 
427
+ it 'can run on an array of hosts' do
428
+ vardir = '/var'
429
+ el_agent = make_host( 'el', :platform => 'el-5-x86_64', :pe_ver => '4.0' )
430
+ el_agent2 = make_host( 'el', :platform => 'el-5-x86_64', :pe_ver => '4.0' )
431
+
432
+ allow( el_agent ).to receive( :puppet_configprint ).and_return( { 'vardir' => vardir } )
433
+
434
+ expect( el_agent ).to receive( :file_exist? ).with("/var/state/agent_catalog_run.lock").and_return(false)
435
+
436
+ allow( el_agent2 ).to receive( :puppet_configprint ).and_return( { 'vardir' => vardir } )
437
+
438
+ expect( el_agent2 ).to receive( :file_exist? ).with("/var/state/agent_catalog_run.lock").and_return(false)
439
+
440
+ expect( subject ).to receive( :puppet_resource ).with( "service", "puppet", "ensure=stopped").twice
441
+ expect( subject ).to receive( :on ).twice
442
+
443
+ subject.stop_agent_on( [el_agent, el_agent2] )
444
+ end
445
+
446
+ it 'runs in parallel with run_in_parallel=true' do
447
+ InParallel::InParallelExecutor.logger = logger
448
+ FakeFS.deactivate!
449
+ vardir = '/var'
450
+ el_agent = make_host( 'el', :platform => 'el-5-x86_64', :pe_ver => '4.0' )
451
+ el_agent2 = make_host( 'el', :platform => 'el-5-x86_64', :pe_ver => '4.0' )
452
+
453
+ allow( el_agent ).to receive( :puppet_configprint ).and_return( { 'vardir' => vardir } )
454
+
455
+ allow( el_agent ).to receive( :file_exist? ).with("/var/state/agent_catalog_run.lock").and_return(false)
456
+
457
+ allow( el_agent2 ).to receive( :puppet_configprint ).and_return( { 'vardir' => vardir } )
458
+
459
+ allow( el_agent2 ).to receive( :file_exist? ).with("/var/state/agent_catalog_run.lock").and_return(false)
460
+
461
+ # This will only get hit if forking processes is supported and at least 2 items are being submitted to run in parallel
462
+ expect( InParallel::InParallelExecutor ).to receive(:_execute_in_parallel).with(any_args).and_call_original.exactly(2).times
463
+
464
+ subject.stop_agent_on( [el_agent, el_agent2], { :run_in_parallel => true} )
465
+ end
466
+
405
467
  end
406
468
 
407
469
  describe "#stop_agent" do
@@ -449,6 +511,22 @@ describe ClassMixedWithDSLHelpers do
449
511
  subject.sign_certificate_for( agent )
450
512
  end
451
513
 
514
+ it 'accepts an array of hosts to validate' do
515
+ allow( subject ).to receive( :sleep ).and_return( true )
516
+
517
+ result.stdout = "+ \"#{agent}\" + \"#{custom}\""
518
+ allow( subject ).to receive( :hosts ).and_return( hosts )
519
+
520
+ allow( subject ).to receive( :puppet ) do |arg|
521
+ arg
522
+ end
523
+ expect( subject ).to receive( :on ).with( master, "agent -t", :acceptable_exit_codes => [0, 1, 2]).once
524
+ expect( subject ).to receive( :on ).with( master, "cert --allow-dns-alt-names sign master", :acceptable_exit_codes => [0, 24]).once
525
+ expect( subject ).to receive( :on ).with( master, "cert --sign --all --allow-dns-alt-names", :acceptable_exit_codes => [0,24]).once
526
+ expect( subject ).to receive( :on ).with( master, "cert --list --all").once.and_return( result )
527
+
528
+ subject.sign_certificate_for( [master, agent, custom] )
529
+ end
452
530
  end
453
531
 
454
532
  describe "#sign_certificate" do
@@ -427,6 +427,18 @@ describe ClassMixedWithDSLInstallUtils do
427
427
  expect(hosts[0]).to receive(:install_package).with('puppet')
428
428
  subject.install_puppet
429
429
  end
430
+ it 'installs in parallel' do
431
+ InParallel::InParallelExecutor.logger = logger
432
+ FakeFS.deactivate!
433
+ hosts.each{ |host|
434
+ allow(host).to receive(:install_package_with_rpm).with(/puppetlabs-release-el-6\.noarch\.rpm/, '--replacepkgs', {:package_proxy=>false})
435
+ allow(host).to receive(:install_package).with('puppet')
436
+ }
437
+ opts[:run_in_parallel] = true
438
+ # This will only get hit if forking processes is supported and at least 2 items are being submitted to run in parallel
439
+ expect( InParallel::InParallelExecutor ).to receive(:_execute_in_parallel).with(any_args).and_call_original.exactly(3).times
440
+ subject.install_puppet(opts)
441
+ end
430
442
  it 'installs specific version of puppet when passed :version' do
431
443
  expect(hosts[0]).to receive(:install_package).with('puppet-3')
432
444
  subject.install_puppet( :version => '3' )
@@ -89,7 +89,7 @@ describe Beaker do
89
89
  it "can sync time on unix hosts" do
90
90
  hosts = make_hosts( { :platform => 'unix' } )
91
91
 
92
- expect( Beaker::Command ).to receive( :new ).with("ntpdate -t 20 #{ntpserver}").exactly( 3 ).times
92
+ expect( Beaker::Command ).to receive( :new ).with("ntpdate -u -t 20 #{ntpserver}").exactly( 3 ).times
93
93
 
94
94
  subject.timesync( hosts, options )
95
95
  end
@@ -98,7 +98,7 @@ describe Beaker do
98
98
  hosts = make_hosts( { :platform => 'unix', :exit_code => [1, 0] } )
99
99
  allow( subject ).to receive( :sleep ).and_return(true)
100
100
 
101
- expect( Beaker::Command ).to receive( :new ).with("ntpdate -t 20 #{ntpserver}").exactly( 6 ).times
101
+ expect( Beaker::Command ).to receive( :new ).with("ntpdate -u -t 20 #{ntpserver}").exactly( 6 ).times
102
102
 
103
103
  subject.timesync( hosts, options )
104
104
  end
@@ -107,7 +107,7 @@ describe Beaker do
107
107
  hosts = make_hosts( { :platform => 'unix', :exit_code => 1 } )
108
108
  allow( subject ).to receive( :sleep ).and_return(true)
109
109
 
110
- expect( Beaker::Command ).to receive( :new ).with("ntpdate -t 20 #{ntpserver}").exactly( 5 ).times
110
+ expect( Beaker::Command ).to receive( :new ).with("ntpdate -u -t 20 #{ntpserver}").exactly( 5 ).times
111
111
 
112
112
  expect{ subject.timesync( hosts, options ) }.to raise_error(/NTP date was not successful after/)
113
113
  end
@@ -136,7 +136,7 @@ describe Beaker do
136
136
  it "can set time server on unix hosts" do
137
137
  hosts = make_hosts( { :platform => 'unix' } )
138
138
 
139
- expect( Beaker::Command ).to receive( :new ).with("ntpdate -t 20 #{ntpserver_set}").exactly( 3 ).times
139
+ expect( Beaker::Command ).to receive( :new ).with("ntpdate -u -t 20 #{ntpserver_set}").exactly( 3 ).times
140
140
 
141
141
  subject.timesync( hosts, options_ntp )
142
142
  end
@@ -75,7 +75,7 @@ module Beaker
75
75
 
76
76
  context 'if :timesync option set true on host' do
77
77
  it 'does call timesync for host' do
78
- hosts[0][:timesync] = true
78
+ hosts[0].options[:timesync] = true
79
79
  allow( hypervisor ).to receive( :set_env )
80
80
  expect( hypervisor ).to receive( :timesync ).once
81
81
  hypervisor.configure
@@ -85,13 +85,29 @@ module Beaker
85
85
  context 'if :timesync option set true but false on host' do
86
86
  it 'does not call timesync for host' do
87
87
  options[:timesync] = true
88
- hosts[0][:timesync] = false
88
+ hosts[0].options[:timesync] = false
89
89
  allow( hypervisor ).to receive( :set_env )
90
90
  expect( hypervisor ).to_not receive( :timesync )
91
91
  hypervisor.configure
92
92
  end
93
93
  end
94
94
 
95
+ context 'if :run_in_parallel option includes configure' do
96
+ it 'timesync is run in parallel' do
97
+ InParallel::InParallelExecutor.logger = logger
98
+ # Need to deactivate FakeFS since the child processes write STDOUT to file.
99
+ FakeFS.deactivate!
100
+ hosts[0].options[:timesync] = true
101
+ hosts[1].options[:timesync] = true
102
+ hosts[2].options[:timesync] = true
103
+ options[:run_in_parallel] = ['configure']
104
+ allow( hypervisor ).to receive( :set_env )
105
+ # This will only get hit if forking processes is supported and at least 2 items are being submitted to run in parallel
106
+ expect( InParallel::InParallelExecutor ).to receive(:_execute_in_parallel).with(any_args).and_call_original.exactly(3).times
107
+ hypervisor.configure
108
+ end
109
+ end
110
+
95
111
  context "if :disable_iptables option set false" do
96
112
  it "does not call disable_iptables" do
97
113
  options[:disable_iptables] = false
@@ -18,6 +18,12 @@ module Beaker
18
18
  ENV.delete('q_puppet_cloud_install')
19
19
  end
20
20
 
21
+ it "correctly parses the run_in_parallel array" do
22
+ ENV['BEAKER_RUN_IN_PARALLEL'] = "install,configure"
23
+ env = presets.env_vars
24
+ expect(env[:run_in_parallel]).to eq(['install', 'configure'])
25
+ end
26
+
21
27
  it "removes all empty/nil entries in env_vars" do
22
28
  expect(presets.env_vars.has_value?(nil)).to be === false
23
29
  expect(presets.env_vars.has_value?({})).to be === false
@@ -2,7 +2,14 @@ require 'spec_helper'
2
2
 
3
3
  module Beaker
4
4
  module Shared
5
+
6
+ config = RSpec::Mocks.configuration
7
+
8
+ config.patch_marshal_to_support_partial_doubles = true
9
+
5
10
  describe HostManager do
11
+ # The logger double as nil object doesn't work with marshal.load and marshal.unload needed for run_in_parallel.
12
+ let( :logger ) { double('logger') }
6
13
  let( :host_handler ) { Beaker::Shared::HostManager }
7
14
  let( :spec_block ) { Proc.new { |arr| arr } }
8
15
  let( :platform ) { @platform || 'unix' }
@@ -135,6 +142,36 @@ module Beaker
135
142
  expect( myhosts ).to be === hosts
136
143
  end
137
144
 
145
+ it "can execute a block against an array of hosts in parallel" do
146
+ InParallel::InParallelExecutor.logger = Logger.new(STDOUT)
147
+ FakeFS.deactivate!
148
+
149
+ expect( InParallel::InParallelExecutor ).to receive(:_execute_in_parallel).with(any_args).and_call_original.exactly(3).times
150
+
151
+ myhosts = host_handler.run_block_on( hosts, nil, { :run_in_parallel => true } ) do |host|
152
+ # kind of hacky workaround to remove logger which contains a singleton method injected by rspec
153
+
154
+ host.instance_eval("remove_instance_variable(:@logger)")
155
+ host
156
+ end
157
+
158
+ # After marshal load and marshal unload, the logger option (an rspec double) is no longer 'equal' to the original.
159
+ # Array of results can be in different order.
160
+ new_host = myhosts.select{ |host| host.name == hosts[0].name}.first
161
+ hosts[0].options.each { |option|
162
+ expect(option[1]).to eq(new_host.options[option[0]]) unless option[0] == :logger
163
+ }
164
+ end
165
+
166
+ it "does not run in parallel if there is only 1 host in the array" do
167
+ myhosts = host_handler.run_block_on( [hosts[0]], nil, { :run_in_parallel => true } ) do |host|
168
+ puts host
169
+ host
170
+ end
171
+
172
+ expect( myhosts ).to be === [hosts[0]]
173
+ end
174
+
138
175
  it "receives an ArgumentError on empty host" do
139
176
  expect { host_handler.run_block_on( [], role0 ) }.to raise_error(ArgumentError)
140
177
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: beaker
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.46.0
4
+ version: 2.47.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Puppetlabs
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-07-08 00:00:00.000000000 Z
11
+ date: 2016-07-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -95,7 +95,7 @@ dependencies:
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0.10'
97
97
  - !ruby/object:Gem::Dependency
98
- name: beaker-hostgenerator
98
+ name: yard
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - ! '>='
@@ -109,7 +109,7 @@ dependencies:
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
111
  - !ruby/object:Gem::Dependency
112
- name: yard
112
+ name: markdown
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
115
  - - ! '>='
@@ -123,7 +123,7 @@ dependencies:
123
123
  - !ruby/object:Gem::Version
124
124
  version: '0'
125
125
  - !ruby/object:Gem::Dependency
126
- name: markdown
126
+ name: thin
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
129
  - - ! '>='
@@ -137,19 +137,33 @@ dependencies:
137
137
  - !ruby/object:Gem::Version
138
138
  version: '0'
139
139
  - !ruby/object:Gem::Dependency
140
- name: thin
140
+ name: activesupport
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
- - - ! '>='
143
+ - - ~>
144
144
  - !ruby/object:Gem::Version
145
- version: '0'
145
+ version: '4.2'
146
146
  type: :development
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
150
- - - ! '>='
150
+ - - ~>
151
151
  - !ruby/object:Gem::Version
152
- version: '0'
152
+ version: '4.2'
153
+ - !ruby/object:Gem::Dependency
154
+ name: rack
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ~>
158
+ - !ruby/object:Gem::Version
159
+ version: '1.6'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ~>
165
+ - !ruby/object:Gem::Version
166
+ version: '1.6'
153
167
  - !ruby/object:Gem::Dependency
154
168
  name: minitest
155
169
  requirement: !ruby/object:Gem::Requirement
@@ -262,6 +276,20 @@ dependencies:
262
276
  - - ~>
263
277
  - !ruby/object:Gem::Version
264
278
  version: 0.2.1
279
+ - !ruby/object:Gem::Dependency
280
+ name: in-parallel
281
+ requirement: !ruby/object:Gem::Requirement
282
+ requirements:
283
+ - - ~>
284
+ - !ruby/object:Gem::Version
285
+ version: '0.1'
286
+ type: :runtime
287
+ prerelease: false
288
+ version_requirements: !ruby/object:Gem::Requirement
289
+ requirements:
290
+ - - ~>
291
+ - !ruby/object:Gem::Version
292
+ version: '0.1'
265
293
  - !ruby/object:Gem::Dependency
266
294
  name: beaker-answers
267
295
  requirement: !ruby/object:Gem::Requirement
@@ -318,6 +346,20 @@ dependencies:
318
346
  - - ~>
319
347
  - !ruby/object:Gem::Version
320
348
  version: '0.0'
349
+ - !ruby/object:Gem::Dependency
350
+ name: beaker-hostgenerator
351
+ requirement: !ruby/object:Gem::Requirement
352
+ requirements:
353
+ - - ! '>='
354
+ - !ruby/object:Gem::Version
355
+ version: '0'
356
+ type: :runtime
357
+ prerelease: false
358
+ version_requirements: !ruby/object:Gem::Requirement
359
+ requirements:
360
+ - - ! '>='
361
+ - !ruby/object:Gem::Version
362
+ version: '0'
321
363
  - !ruby/object:Gem::Dependency
322
364
  name: rbvmomi
323
365
  requirement: !ruby/object:Gem::Requirement
@@ -615,6 +657,7 @@ files:
615
657
  - docs/hypervisors/vsphere.md
616
658
  - docs/meta/README.md
617
659
  - docs/meta/ticket_process.md
660
+ - docs/runner/run_in_parallel.md
618
661
  - docs/runner/test_run.md
619
662
  - docs/runner/test_suites.md
620
663
  - ext/completion/beaker-completion.bash
@@ -723,6 +766,7 @@ files:
723
766
  - lib/beaker/shared/semvar.rb
724
767
  - lib/beaker/shared/timed.rb
725
768
  - lib/beaker/ssh_connection.rb
769
+ - lib/beaker/tasks/quick_start.rb
726
770
  - lib/beaker/tasks/rake_task.rb
727
771
  - lib/beaker/tasks/test.rb
728
772
  - lib/beaker/test_case.rb