beaker 2.46.0 → 2.47.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.
@@ -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