beaker 3.34.0 → 3.35.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -1
  3. data/acceptance/tests/base/external_resources_test.rb +18 -3
  4. data/acceptance/tests/base/host/host_test.rb +1 -1
  5. data/docs/concepts/testing_beaker_itself.md +4 -4
  6. data/docs/concepts/ticket_process.md +12 -12
  7. data/docs/concepts/types_puppet_4_and_the_all_in_one_agent.md +1 -1
  8. data/docs/how_to/change_terminal_output_coloring.md +1 -1
  9. data/docs/how_to/confine.md +3 -3
  10. data/docs/how_to/debug_beaker_tests.md +19 -19
  11. data/docs/how_to/enabling_cross_sut_access.md +1 -1
  12. data/docs/how_to/hosts/README.md +1 -1
  13. data/docs/how_to/hosts/cisco.md +1 -1
  14. data/docs/how_to/hypervisors/README.md +1 -1
  15. data/docs/how_to/platform_specific_tag_confines.md +2 -2
  16. data/docs/how_to/preserve_hosts.md +2 -2
  17. data/docs/how_to/rake_tasks.md +3 -4
  18. data/docs/how_to/test_arbitrary_beaker_versions.md +3 -3
  19. data/docs/how_to/upgrade_from_2_to_3.md +4 -4
  20. data/docs/tutorials/README.md +1 -1
  21. data/docs/tutorials/test_suites.md +1 -1
  22. data/lib/beaker/cli.rb +1 -0
  23. data/lib/beaker/command.rb +2 -2
  24. data/lib/beaker/dsl/assertions.rb +1 -1
  25. data/lib/beaker/dsl/helpers/facter_helpers.rb +1 -1
  26. data/lib/beaker/dsl/install_utils/pe_defaults.rb +1 -1
  27. data/lib/beaker/dsl/roles.rb +1 -1
  28. data/lib/beaker/dsl/structure.rb +2 -2
  29. data/lib/beaker/host/cisco.rb +3 -3
  30. data/lib/beaker/host/mac/exec.rb +1 -1
  31. data/lib/beaker/host/windows/exec.rb +1 -1
  32. data/lib/beaker/host_prebuilt_steps.rb +3 -0
  33. data/lib/beaker/options/hosts_file_parser.rb +9 -2
  34. data/lib/beaker/options/parser.rb +1 -1
  35. data/lib/beaker/shared/options_resolver.rb +6 -6
  36. data/lib/beaker/subcommand.rb +13 -8
  37. data/lib/beaker/tasks/quick_start.rb +2 -2
  38. data/lib/beaker/version.rb +1 -1
  39. data/spec/beaker/host/unix/exec_spec.rb +1 -1
  40. data/spec/beaker/host_prebuilt_steps_spec.rb +1 -0
  41. data/spec/beaker/options/hosts_file_parser_spec.rb +15 -7
  42. data/spec/beaker/shared/error_handler_spec.rb +2 -2
  43. data/spec/beaker/shared/repetition_spec.rb +2 -2
  44. data/spec/beaker/subcommand_spec.rb +82 -30
  45. data/spec/helpers.rb +1 -1
  46. data/spec/mock_fission.rb +4 -4
  47. data/spec/mock_vsphere.rb +5 -5
  48. data/spec/mock_vsphere_helper.rb +1 -1
  49. metadata +2 -2
@@ -1,8 +1,8 @@
1
1
  # How To Upgrade from 2.y to 3.0
2
2
 
3
3
  This is a guide detailing all the issues to be aware of, and to help people make
4
- any changes that you might need to move from beaker 2.y to 3.0. To test out
5
- beaker 3.0.0, we recommend implementing the strategy outlined [here](test_arbitrary_beaker_versions.md)
4
+ any changes that you might need to move from beaker 2.y to 3.0. To test out
5
+ beaker 3.0.0, we recommend implementing the strategy outlined [here](test_arbitrary_beaker_versions.md)
6
6
  to ensure this new major release does not break your existing testing.
7
7
 
8
8
  ## Ruby version 1.9.3 no longer supported
@@ -39,10 +39,10 @@ doc for info on how to do this.
39
39
 
40
40
  ## EPEL package update
41
41
 
42
- In beaker < 3.0.0, the epel package names had hardcoded defaults listed in the
42
+ In beaker < 3.0.0, the epel package names had hardcoded defaults listed in the
43
43
  presets default; in beaker >= 3.0.0, beaker utilizes the `release-latest` file
44
44
  provided on epel mirrors for el versions 5, 6, and 7. Since only the latest epel
45
- packages are available on epel mirrors, beaker only supports installation of
45
+ packages are available on epel mirrors, beaker only supports installation of
46
46
  that latest version.
47
47
 
48
48
  ## Solaris and AIX Hypervisors removed
@@ -22,7 +22,7 @@ If you haven't installed beaker yet, your guide to doing
22
22
  so can be found [here](installation.md).
23
23
 
24
24
  ## Quick Start
25
-
25
+
26
26
  As a completely new beaker user, the
27
27
  [quick start rake tasks doc](quick_start_rake_tasks.md)
28
28
  will take you through getting beaker running for the
@@ -47,7 +47,7 @@ failure modes.
47
47
 
48
48
  The pre-suite is for setting up the Systems Under Test (SUTs) for the testing
49
49
  suite. No surprises here, usually these files are filled with the setup and
50
- installation code needed to verify that the operating assumptions of the
50
+ installation code needed to verify that the operating assumptions of the
51
51
  software being tested are true.
52
52
 
53
53
  Pre-suites, since they’re supposed to contain just setup code, will fail-fast
@@ -16,6 +16,7 @@ module Beaker
16
16
  # the options are parsed and replaced with a new logger based on what is passed
17
17
  # in to configure the logger.
18
18
  @logger = Beaker::Logger.new
19
+ @options = {}
19
20
  end
20
21
 
21
22
  def parse_options
@@ -66,7 +66,7 @@ module Beaker
66
66
  # interface.
67
67
  # @param [String] cmd An command to call.
68
68
  # @param [Hash] env An optional hash of environment variables to be used
69
- # @param [String] pc An optional list of commands to prepend
69
+ # @param [String] pc An optional list of commands to prepend
70
70
  #
71
71
  # @return [String] This returns the fully formed command line invocation.
72
72
  def cmd_line host, cmd = @command, env = @environment, pc = @prepend_cmds
@@ -78,7 +78,7 @@ module Beaker
78
78
  end
79
79
 
80
80
  # This will cause things like `puppet -t -v agent` which is maybe bad.
81
- if host[:platform] =~ /cisco_ios_xr/
81
+ if host[:platform] =~ /cisco_ios_xr/
82
82
  cmd_line_array = [prepend_commands, env_string, cmd, options_string, args_string]
83
83
  else
84
84
  cmd_line_array = [env_string, prepend_commands, cmd, options_string, args_string]
@@ -98,7 +98,7 @@ module Beaker
98
98
  # Assert that the provided string does not match the provided regular expression, can pass optional message
99
99
  # @deprecated This is placed her for backwards compatability for tests that used Test::Unit::Assertions,
100
100
  # http://apidock.com/ruby/Test/Unit/Assertions/assert_no_match
101
- #
101
+ #
102
102
  def assert_no_match(regexp, string, msg=nil)
103
103
  assert_instance_of(Regexp, regexp, "The first argument to assert_no_match should be a Regexp.")
104
104
  msg = message(msg) { "<#{mu_pp(regexp)}> expected to not match\n<#{mu_pp(string)}>" }
@@ -13,7 +13,7 @@ module Beaker
13
13
  # (or range) of integer exit codes that should be considered
14
14
  # acceptable. An error will be thrown if the exit code does not
15
15
  # match one of the values in this list.
16
- # @option opts [Boolean] :accept_all_exit_codes (false) Consider all
16
+ # @option opts [Boolean] :accept_all_exit_codes (false) Consider all
17
17
  # exit codes as passing.
18
18
  # @option opts [Boolean] :dry_run (false) Do not actually execute any
19
19
  # commands on the SUT
@@ -72,7 +72,7 @@ module Beaker
72
72
  PE_DEFAULTS[platform].each_pair do |key, val|
73
73
  host[key] = val
74
74
  end
75
- # add the type and group here for backwards compatability
75
+ # add the type and group here for backwards compatability
76
76
  if host['platform'] =~ /windows/
77
77
  host['group'] = 'Administrators'
78
78
  else
@@ -161,7 +161,7 @@ module Beaker
161
161
  end
162
162
 
163
163
  #Create a new role method for a given arbitrary role name. Makes it possible to be able to run
164
- #commands without having to refer to role by String or Symbol. Will not add a new method
164
+ #commands without having to refer to role by String or Symbol. Will not add a new method
165
165
  #definition if the name is already in use.
166
166
  # @param [String, Symbol, Array[String,Symbol]] role The role that you wish to create a definition for, either a String
167
167
  # Symbol or an Array of Strings or Symbols.
@@ -68,7 +68,7 @@ module Beaker
68
68
 
69
69
  set_current_step_name(step_name)
70
70
  # Here we prompt the user to tell us if the step passed or failed
71
- loop do
71
+ loop do
72
72
  input = Readline.readline('Did this step pass, Y/n? ', true).squeeze(" ").strip.downcase
73
73
  if %w(y yes).include?(input)
74
74
  break
@@ -102,7 +102,7 @@ module Beaker
102
102
  def manual_test manual_test_name, &block
103
103
  if(@options.has_key?(:exec_manual_tests) && @options[:exec_manual_tests] == true)
104
104
  # here the option is set so we run the test as normal
105
- test_name manual_test_name, &block
105
+ test_name manual_test_name, &block
106
106
  else
107
107
  # here no option was set so we log the test name and skip it
108
108
  test_name manual_test_name
@@ -119,15 +119,15 @@ module Cisco
119
119
  # this will be raised with the appropriate message
120
120
  def validate_setup
121
121
  msg = nil
122
- if self[:platform] =~ /cisco_nexus/
122
+ if self[:platform] =~ /cisco_nexus/
123
123
  if !self[:vrf]
124
- msg = 'Cisco Nexus hosts must be provided with a :vrf value.'
124
+ msg = 'Cisco Nexus hosts must be provided with a :vrf value.'
125
125
  end
126
126
  if !self[:user]
127
127
  msg = 'Cisco hosts must be provided with a :user value'
128
128
  end
129
129
  end
130
- if self[:platform] =~ /cisco_ios_xr/
130
+ if self[:platform] =~ /cisco_ios_xr/
131
131
  if !self[:user]
132
132
  msg = 'Cisco hosts must be provided with a :user value'
133
133
  end
@@ -30,7 +30,7 @@ module Mac::Exec
30
30
  # Checks if selinux is enabled
31
31
  # selinux is not availble on OS X
32
32
  #
33
- # @return [Boolean] false
33
+ # @return [Boolean] false
34
34
  def selinux_enabled?()
35
35
  false
36
36
  end
@@ -113,7 +113,7 @@ module Windows::Exec
113
113
  #
114
114
  # @return [Boolean]
115
115
  def cygwin_installed?
116
- output = exec(Beaker::Command.new('cygcheck --check-setup cygwin'), :accept_all_exit_codes => true).stdout
116
+ output = exec(Beaker::Command.new('cygcheck --check-setup cygwin'), :accept_all_exit_codes => true).stdout
117
117
  return true if output.match(/cygwin/) && output.match(/OK/)
118
118
  false
119
119
  end
@@ -432,6 +432,9 @@ module Beaker
432
432
  elsif host['platform'] =~ /solaris-11/
433
433
  host.exec(Command.new("if grep \"root::::type=role\" /etc/user_attr; then sudo rolemod -K type=normal root; else echo \"root user already type=normal\"; fi"), {:pty => true} )
434
434
  host.exec(Command.new("sudo gsed -i -e 's/PermitRootLogin no/PermitRootLogin yes/g' /etc/ssh/sshd_config"), {:pty => true} )
435
+ elsif host['platform'] =~ /f5/
436
+ #interacting with f5 should using tmsh
437
+ logger.warn("Attempting to enable root login non-supported platform: #{host.name}: #{host['platform']}")
435
438
  elsif host.is_cygwin?
436
439
  host.exec(Command.new("sed -ri 's/^#?PermitRootLogin /PermitRootLogin yes/' /etc/sshd_config"), {:pty => true})
437
440
  elsif host.is_powershell?
@@ -14,12 +14,17 @@ module Beaker
14
14
  # @raise [ArgumentError] Raises if hosts_file_path is not a valid YAML file
15
15
  # @raise [Errno::ENOENT] File not found error: hosts_file doesn't exist
16
16
  def self.parse_hosts_file(hosts_file_path = nil)
17
+ require 'erb'
18
+
17
19
  host_options = new_host_options
18
20
  return host_options unless hosts_file_path
19
21
  error_message = "#{hosts_file_path} is not a valid YAML file\n\t"
20
22
  host_options = self.merge_hosts_yaml( host_options, error_message ) {
21
23
  hosts_file_path = File.expand_path( hosts_file_path )
22
- YAML.load_file( hosts_file_path )
24
+
25
+ raise "#{hosts_file_path} is not a valid path" unless File.exist?(hosts_file_path)
26
+
27
+ YAML.load(ERB.new(File.read(hosts_file_path), nil, '-').result(binding))
23
28
  }
24
29
  fix_roles_array( host_options )
25
30
  end
@@ -31,11 +36,13 @@ module Beaker
31
36
  # @return [OptionsHash] Contents of the hosts file as an OptionsHash
32
37
  # @raise [ArgumentError] If hosts_def_yaml is not a valid YAML string
33
38
  def self.parse_hosts_string(hosts_def_yaml = nil)
39
+ require 'erb'
40
+
34
41
  host_options = new_host_options
35
42
  return host_options unless hosts_def_yaml
36
43
  error_message = "#{hosts_def_yaml}\nis not a valid YAML string\n\t"
37
44
  host_options = self.merge_hosts_yaml( host_options, error_message ) {
38
- YAML.load( hosts_def_yaml )
45
+ YAML.load(ERB.new(hosts_def_yaml, nil, '-').result(binding))
39
46
  }
40
47
  fix_roles_array( host_options )
41
48
  end
@@ -171,7 +171,7 @@ module Beaker
171
171
 
172
172
  # Update the @attribution hash with the source of each key in the options_hash
173
173
  #
174
- # @param [Hash] options_hash Options hash
174
+ # @param [Hash] options_hash Options hash
175
175
  # @param [String] source Where the options were specified
176
176
  # @return [Hash] hash Hash of sources for each key
177
177
  def tag_sources(options_hash, source)
@@ -3,25 +3,25 @@ module Beaker
3
3
  # Methods for parsing options.
4
4
  module OptionsResolver
5
5
  # parses local and global options to determine if a particular mode should
6
- # be run in parallel. typically, local_options will specify a true/false
6
+ # be run in parallel. typically, local_options will specify a true/false
7
7
  # value, while global_options will specify an array of mode names that should
8
8
  # be run in parallel. the value specified in local_options will take precedence
9
- # over the values specified in global_options.
9
+ # over the values specified in global_options.
10
10
  # @param [Hash] local_options local options for running in parallel
11
11
  # @option local_options [Boolean] :run_in_parallel flag for running in parallel
12
12
  # @param [Hash] global_options global options for running in parallel
13
13
  # @option global_options [Array<String>] :run_in_parallel list of modes to run in parallel
14
14
  # @param [String] mode the mode we want to query global_options for
15
- # @return [Boolean] true if the specified mode is in global_options and :run_in_parallel in local_options is not false,
15
+ # @return [Boolean] true if the specified mode is in global_options and :run_in_parallel in local_options is not false,
16
16
  # or if :run_in_parallel in local_options is true, false otherwise
17
17
  # @example
18
- # run_in_parallel?({:run_in_parallel => true})
18
+ # run_in_parallel?({:run_in_parallel => true})
19
19
  # -> will return true
20
20
  #
21
- # run_in_parallel?({:run_in_parallel => true}, {:run_in_parallel => ['install','configure']}, 'install')
21
+ # run_in_parallel?({:run_in_parallel => true}, {:run_in_parallel => ['install','configure']}, 'install')
22
22
  # -> will return true
23
23
  #
24
- # run_in_parallel?({:run_in_parallel => false}, {:run_in_parallel => ['install','configure']}, 'install')
24
+ # run_in_parallel?({:run_in_parallel => false}, {:run_in_parallel => ['install','configure']}, 'install')
25
25
  # -> will return false
26
26
  def run_in_parallel?(local_options=nil, global_options=nil, mode=nil)
27
27
  run_in_parallel = local_options[:run_in_parallel] unless local_options.nil?
@@ -6,6 +6,7 @@ module Beaker
6
6
  class Subcommand < Thor
7
7
  SubcommandUtil = Beaker::Subcommands::SubcommandUtil
8
8
 
9
+ attr_reader :cli
9
10
 
10
11
  def initialize(*args)
11
12
  super
@@ -171,8 +172,9 @@ module Beaker
171
172
  end
172
173
 
173
174
  beaker_suites = [:pre_suite, :tests, :post_suite, :pre_cleanup]
174
-
175
- if Pathname(resource).exist?
175
+ resources = resource.split(',')
176
+ paths = resources.map { |r| Pathname(r) }
177
+ if paths.all?(&:exist?)
176
178
  # If we determine the resource is a valid file resource, then we empty
177
179
  # all the suites and run that file resource in the tests suite. In the
178
180
  # future, when we have the ability to have custom suites, we should change
@@ -180,12 +182,14 @@ module Beaker
180
182
  beaker_suites.each do |suite|
181
183
  @cli.options[suite] = []
182
184
  end
183
- if Pathname(resource).directory?
184
- @cli.options[:tests] = Dir.glob("#{Pathname(resource)}/**/*.rb")
185
- else
186
- @cli.options[:tests] = [Pathname(resource).to_s]
187
- end
188
- elsif resource.match(/pre-suite|tests|post-suite|pre-cleanup/)
185
+ @cli.options[:tests] = paths.map do |path|
186
+ if path.directory?
187
+ Dir.glob("#{path}/**/*.rb")
188
+ else
189
+ path.to_s
190
+ end
191
+ end.flatten
192
+ elsif resources.all? { |r| r =~ /^(pre-suite|tests|post-suite|pre-cleanup)$/ }
189
193
  # The regex match here is loose so that users can supply multiple suites,
190
194
  # such as `beaker exec pre-suite,tests`.
191
195
  beaker_suites.each do |suite|
@@ -194,6 +198,7 @@ module Beaker
194
198
  else
195
199
  raise ArgumentError, "Unable to parse #{resource} with beaker exec"
196
200
  end
201
+
197
202
  @cli.execute!
198
203
  end
199
204
 
@@ -50,11 +50,11 @@ namespace :beaker_quickstart do
50
50
 
51
51
  desc 'Generate Default Smoke Test'
52
52
  task :gen_smoke_test do
53
- smoke_test_file = "acceptance/setup/default_smoke_test.rb"
53
+ smoke_test_file = "acceptance/tests/default_smoke_test.rb"
54
54
  FileUtils.mkdir_p('acceptance/tests') # -p ignores when dir already exists
55
55
  if !File.exist?(smoke_test_file) then
56
56
  puts "Writing default smoke test to file - #{smoke_test_file}"
57
- File.open("acceptance/tests/default_smoke_test.rb", 'w') do |fh|
57
+ File.open(smoke_test_file, 'w') do |fh|
58
58
  fh.print("test_name 'puppet install smoketest' do
59
59
  step 'puppet install smoketest: verify \\'puppet help\\' can be successfully called on
60
60
  all hosts' do
@@ -1,5 +1,5 @@
1
1
  module Beaker
2
2
  module Version
3
- STRING = '3.34.0'
3
+ STRING = '3.35.0'
4
4
  end
5
5
  end
@@ -102,7 +102,7 @@ module Beaker
102
102
  describe '#ssh_service_restart' do
103
103
  PlatformHelpers::SYSTEMDPLATFORMS.each do |platform|
104
104
  it "calls the correct command for #{platform}" do
105
- opts['platform'] = platform
105
+ opts['platform'] = platform
106
106
  expect(instance).to receive(:exec)
107
107
  expect(Beaker::Command).to receive(:new).with("systemctl restart sshd.service")
108
108
  expect{instance.ssh_service_restart}.to_not raise_error
@@ -38,6 +38,7 @@ describe Beaker do
38
38
  end
39
39
  end
40
40
 
41
+ it_should_behave_like 'enables_root_login', 'f5', []
41
42
  # Non-cygwin Windows
42
43
  it_should_behave_like 'enables_root_login', 'pswindows', [], false
43
44
 
@@ -28,14 +28,14 @@ module Beaker
28
28
 
29
29
  it "raises an error on no file found" do
30
30
  FakeFS.deactivate!
31
- expect{parser.parse_hosts_file("not a valid path")}.to raise_error(Errno::ENOENT)
31
+ expect{parser.parse_hosts_file("not a valid path")}.to raise_error(/is not a valid path/)
32
32
  end
33
33
 
34
34
  it "raises an error on bad yaml file" do
35
35
  FakeFS.deactivate!
36
- allow( YAML ).to receive(:load_file) { raise Psych::SyntaxError }
37
- allow( File ).to receive(:exists?).and_return(true)
38
- expect { parser.parse_hosts_file("not a valid path") }.to raise_error(ArgumentError)
36
+ expect( File ).to receive(:exist?).and_return(true)
37
+
38
+ expect { parser.parse_hosts_file("not a valid path") }.to raise_error(Errno::ENOENT)
39
39
  end
40
40
 
41
41
  it 'returns a #new_host_options hash if given no arguments' do
@@ -43,12 +43,20 @@ module Beaker
43
43
  expect( host_options ).to be === parser.new_host_options
44
44
  end
45
45
 
46
- it 'passes a YAML.load_file call through to #merge_hosts_yaml' do
46
+ it 'passes a YAML.load call through to #merge_hosts_yaml' do
47
47
  yaml_string = 'not actually yaml, but that wont matter'
48
- allow( File ).to receive( :expand_path ).with( yaml_string ) { yaml_string }
49
- expect( YAML ).to receive( :load_file ).with( yaml_string )
48
+ expect( File ).to receive( :exist?).and_return(true)
49
+ expect( File ).to receive( :read ).and_return(yaml_string)
50
50
  parser.parse_hosts_file( yaml_string )
51
51
  end
52
+
53
+ it 'processes ERB in the host YAML successfully' do
54
+ yaml_string = '1 plus 2: <%= 1 + 2 %>'
55
+ expect( File ).to receive( :exist?).and_return(true)
56
+ expect( File ).to receive( :read ).and_return(yaml_string)
57
+ beaker_options_hash = parser.parse_hosts_file( yaml_string )
58
+ expect(beaker_options_hash['1 plus 2']).to eq(3)
59
+ end
52
60
  end
53
61
 
54
62
  describe '#parse_hosts_string' do
@@ -19,14 +19,14 @@ module Beaker
19
19
  ex = Exception.new("ArgumentError")
20
20
  allow( ex ).to receive( :backtrace ).and_return(backtrace)
21
21
  mesg = "I'm the extra message"
22
-
22
+
23
23
  backtrace.each_line do |line|
24
24
  expect( logger ).to receive( :error ).with(line)
25
25
  end
26
26
 
27
27
  expect( subject ).to receive( :raise ).once
28
28
 
29
- subject.report_and_raise(logger, ex, mesg)
29
+ subject.report_and_raise(logger, ex, mesg)
30
30
 
31
31
  end
32
32
 
@@ -10,7 +10,7 @@ module Beaker
10
10
 
11
11
  block = double( 'block' )
12
12
  expect( block ).to receive( :exec ).exactly( 5 ).times.and_return( false )
13
-
13
+
14
14
  subject.repeat_for( 5 ) do
15
15
  block.exec
16
16
  end
@@ -21,7 +21,7 @@ module Beaker
21
21
 
22
22
  block = double( 'block' )
23
23
  expect( block ).to receive( :exec ).once.and_return( true )
24
-
24
+
25
25
  subject.repeat_for( 5 ) do
26
26
  block.exec
27
27
  end
@@ -9,9 +9,9 @@ module Beaker
9
9
 
10
10
  context '#initialize' do
11
11
  it 'creates a cli object' do
12
- expect(Beaker::CLI).to receive(:new).once
13
- subcommand
12
+ expect(subcommand.cli).to be
14
13
  end
14
+
15
15
  describe 'File operation initialization for subcommands' do
16
16
  it 'checks to ensure subcommand file resources exist' do
17
17
  expect(FileUtils).to receive(:mkdir_p).with(SubcommandUtil::CONFIG_DIR)
@@ -28,7 +28,6 @@ module Beaker
28
28
  expect(FileUtils).to receive(:touch).with(SubcommandUtil::SUBCOMMAND_STATE)
29
29
  subcommand
30
30
  end
31
-
32
31
  end
33
32
  end
34
33
 
@@ -80,6 +79,9 @@ module Beaker
80
79
 
81
80
  it 'should not error with valid beaker options' do
82
81
  beaker_options_list.each do |option|
82
+ allow_any_instance_of(Beaker::CLI).to receive(:parse_options)
83
+ allow_any_instance_of(Beaker::CLI).to receive(:configured_options).and_return({})
84
+
83
85
  allow(YAML::Store).to receive(:new).with(SubcommandUtil::SUBCOMMAND_STATE).and_return(yaml_store_mock)
84
86
  allow(yaml_store_mock).to receive(:transaction).and_yield
85
87
  allow(yaml_store_mock).to receive(:[]=).with('provisioned', false)
@@ -87,6 +89,7 @@ module Beaker
87
89
  allow_any_instance_of(Beaker::Logger).to receive(:notify).twice
88
90
  expect(SubcommandUtil::SUBCOMMAND_OPTIONS).to receive(:exist?).and_return(true)
89
91
  expect(SubcommandUtil::SUBCOMMAND_STATE).to receive(:exist?).and_return(true)
92
+
90
93
  expect {Beaker::Subcommand.start(['init', '--hosts', 'centos', "--#{option}"])}.to_not output(/ERROR/).to_stderr
91
94
  end
92
95
  end
@@ -103,13 +106,16 @@ module Beaker
103
106
  end
104
107
 
105
108
  context '#init' do
106
- let( :cli ) { subcommand.instance_variable_get(:@cli) }
109
+ let( :cli ) { subcommand.cli }
107
110
  let( :mock_options ) { {:timestamp => 'noon', :other_key => 'cordite'}}
108
111
  let( :yaml_store_mock ) { double('yaml_store_mock') }
109
- it 'calculates options and writes them to disk and deletes the' do
110
- expect(cli).to receive(:parse_options)
112
+
113
+ before :each do
114
+ allow(cli).to receive(:parse_options)
111
115
  allow(cli).to receive(:configured_options).and_return(mock_options)
116
+ end
112
117
 
118
+ it 'calculates options and writes them to disk and deletes the' do
113
119
  allow(File).to receive(:open)
114
120
  allow(YAML::Store).to receive(:new).with(SubcommandUtil::SUBCOMMAND_STATE).and_return(yaml_store_mock)
115
121
  allow(yaml_store_mock).to receive(:transaction).and_yield
@@ -117,13 +123,14 @@ module Beaker
117
123
  subcommand.init
118
124
  expect(mock_options).not_to have_key(:timestamp)
119
125
  end
126
+
120
127
  it 'requires hosts flag' do
121
128
  expect{subcommand.init}.to raise_error(NotImplementedError)
122
129
  end
123
130
  end
124
131
 
125
132
  context '#provision' do
126
- let ( :cli ) { subcommand.instance_variable_get(:@cli) }
133
+ let ( :cli ) { subcommand.cli }
127
134
  let( :yaml_store_mock ) { double('yaml_store_mock') }
128
135
  let ( :host_hash ) { {'mynode.net' => {:name => 'mynode', :platform => Beaker::Platform.new('centos-6-x86_64')}}}
129
136
  let ( :cleaned_hosts ) {double()}
@@ -133,6 +140,7 @@ module Beaker
133
140
  let ( :hosts) {double('hosts')}
134
141
  let ( :hypervisors) {double('hypervisors')}
135
142
  let (:options) {double ('options')}
143
+
136
144
  it 'provisions the host and saves the host info' do
137
145
  expect(YAML::Store).to receive(:new).with(SubcommandUtil::SUBCOMMAND_STATE).and_return(yaml_store_mock)
138
146
  allow(yaml_store_mock).to receive(:[]).and_return(false)
@@ -157,59 +165,103 @@ module Beaker
157
165
  expect(yaml_store_mock).to receive(:[]=).with('provisioned', true)
158
166
  subcommand.provision
159
167
  end
168
+
160
169
  it 'does not allow hosts to be passed' do
161
170
  subcommand.options = {:hosts => "myhost"}
162
171
  expect{subcommand.provision()}.to raise_error(NotImplementedError)
163
172
  end
164
173
  end
165
174
 
166
-
167
175
  context 'exec' do
176
+ before :each do
177
+ allow(subcommand.cli).to receive(:parse_options)
178
+ allow(subcommand.cli).to receive(:initialize_network_manager)
179
+ end
180
+
168
181
  it 'calls execute! when no resource is given' do
169
182
  expect_any_instance_of(Pathname).to_not receive(:directory?)
170
183
  expect_any_instance_of(Pathname).to_not receive(:exist?)
171
- expect_any_instance_of(Beaker::CLI).to receive(:parse_options).once
172
- expect_any_instance_of(Beaker::CLI).to receive(:initialize_network_manager).once
173
- expect_any_instance_of(Beaker::CLI).to receive(:execute!).once
184
+ expect(subcommand.cli).to receive(:execute!).once
174
185
  expect{subcommand.exec}.to_not raise_error
175
186
  end
176
187
 
177
- it 'checks to to see if the resource is a file_resource' do
188
+ it 'allows hard coded suite names to be specified' do
189
+ subcommand.cli.options[:pre_suite] = %w[step1.rb]
190
+ subcommand.cli.options[:post_suite] = %w[step2.rb]
191
+ subcommand.cli.options[:tests] = %w[tests/1.rb]
192
+
193
+ subcommand.exec('pre-suite,tests')
194
+
195
+ expect(subcommand.cli.options[:pre_suite]).to eq(%w[step1.rb])
196
+ expect(subcommand.cli.options[:post_suite]).to eq([])
197
+ expect(subcommand.cli.options[:tests]).to eq(%w[tests/1.rb])
198
+ end
199
+
200
+ it 'errors when a resource is neither a valid file resource or suite name' do
201
+ allow_any_instance_of(Pathname).to receive(:exist?).and_return(false)
202
+ expect{subcommand.exec('blahblahblah')}.to raise_error(ArgumentError)
203
+ end
178
204
 
179
- expect_any_instance_of(Pathname).to receive(:exist?).and_return(true)
180
- expect_any_instance_of(Pathname).to receive(:directory?).and_return(false)
181
- expect_any_instance_of(Beaker::CLI).to receive(:execute!).once
182
- expect{subcommand.exec('resource')}.to_not raise_error
205
+ it 'accepts a tests directory, clearing all other suites' do
206
+ allow_any_instance_of(Pathname).to receive(:exist?).and_return(true)
207
+ allow_any_instance_of(Pathname).to receive(:directory?).and_return(true)
208
+ allow(Dir).to receive(:glob)
209
+ .with('tests/**/*.rb')
210
+ .and_return(%w[tests/a.rb tests/b/c.rb])
211
+
212
+ subcommand.exec('tests')
213
+
214
+ expect(subcommand.cli.options[:pre_suite]).to eq([])
215
+ expect(subcommand.cli.options[:post_suite]).to eq([])
216
+ expect(subcommand.cli.options[:pre_cleanup]).to eq([])
217
+ expect(subcommand.cli.options[:tests]).to eq(%w[tests/a.rb tests/b/c.rb])
183
218
  end
184
219
 
185
- it 'checks to see if the resource is a directory' do
186
- expect_any_instance_of(Pathname).to receive(:exist?).and_return(true)
187
- expect_any_instance_of(Pathname).to receive(:directory?).and_return(true)
188
- expect(Dir).to receive(:glob)
189
- expect_any_instance_of(Beaker::CLI).to receive(:execute!).once
190
- expect{subcommand.exec('resource')}.to_not raise_error
220
+ it 'accepts comma-separated list of tests, clearing all other suites' do
221
+ allow_any_instance_of(Pathname).to receive(:exist?).and_return(true)
222
+ allow_any_instance_of(Pathname).to receive(:file?).and_return(true)
223
+
224
+ subcommand.exec('tests/1.rb,tests/2.rb')
225
+
226
+ expect(subcommand.cli.options[:pre_suite]).to eq([])
227
+ expect(subcommand.cli.options[:post_suite]).to eq([])
228
+ expect(subcommand.cli.options[:pre_cleanup]).to eq([])
229
+ expect(subcommand.cli.options[:tests]).to eq(%w[tests/1.rb tests/2.rb])
191
230
  end
192
231
 
193
- it 'allows a hard coded suite name to be specified' do
232
+ it 'accepts comma-separated list of directories, recursively scanning each' do
233
+ allow_any_instance_of(Pathname).to receive(:exist?).and_return(true)
234
+ allow_any_instance_of(Pathname).to receive(:directory?).and_return(true)
235
+ allow(Dir).to receive(:glob).with('tests/a/**/*.rb').and_return(%w[tests/a/x.rb])
236
+ allow(Dir).to receive(:glob).with('tests/b/**/*.rb').and_return(%w[tests/b/x/y.rb tests/b/x/z.rb])
194
237
 
195
- allow_any_instance_of(Pathname).to receive(:exist?).and_return(false)
196
- expect_any_instance_of(Beaker::CLI).to receive(:execute!).once
197
- expect{subcommand.exec('tests')}.to_not raise_error
238
+ subcommand.exec('tests/a,tests/b')
239
+
240
+ expect(subcommand.cli.options[:tests]).to eq(%w[tests/a/x.rb tests/b/x/y.rb tests/b/x/z.rb])
198
241
  end
199
242
 
200
- it 'errors when a resource is neither a valid file resource or suite name' do
243
+ it 'rejects comma-separated file and suite name' do
201
244
  allow_any_instance_of(Pathname).to receive(:exist?).and_return(false)
202
- expect{subcommand.exec('blahblahblah')}.to raise_error(ArgumentError)
245
+
246
+ expect {
247
+ subcommand.exec('pre-suite,tests/whoops')
248
+ }.to raise_error(ArgumentError, %r{Unable to parse pre-suite,tests/whoops})
203
249
  end
204
250
  end
205
251
 
206
252
  context 'destroy' do
207
- let( :cli ) { subcommand.instance_variable_get(:@cli) }
253
+ let( :cli ) { subcommand.cli }
208
254
  let( :mock_options ) { {:timestamp => 'noon', :other_key => 'cordite'}}
209
255
  let( :yaml_store_mock ) { double('yaml_store_mock') }
256
+ let( :network_manager) {double('network_manager')}
257
+
210
258
  it 'calls destroy and updates the yaml store' do
259
+ allow(cli).to receive(:parse_options)
260
+ allow(cli).to receive(:initialize_network_manager)
261
+ allow(cli).to receive(:network_manager).and_return(network_manager)
262
+ expect(network_manager).to receive(:cleanup)
263
+
211
264
  expect(YAML::Store).to receive(:new).with(SubcommandUtil::SUBCOMMAND_STATE).and_return(yaml_store_mock)
212
- allow(SubcommandUtil).to receive(:cleanup).with(cli).and_return(true)
213
265
  allow(yaml_store_mock).to receive(:transaction).and_yield
214
266
  allow(yaml_store_mock).to receive(:[]).with('provisioned').and_return(true)
215
267
  allow(yaml_store_mock).to receive(:delete).with('provisioned').and_return(true)