onceover 3.15.1 → 3.17.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +72 -82
  4. data/.travis.yml +3 -8
  5. data/Gemfile +9 -2
  6. data/README.md +67 -3
  7. data/bin/onceover +3 -3
  8. data/factsets/Ubuntu-18.04-64.json +556 -0
  9. data/features/step_definitions/common.rb +12 -1
  10. data/features/windows.feature +30 -0
  11. data/features/{run.feature → zzz_run.feature} +5 -0
  12. data/lib/onceover/beaker.rb +6 -0
  13. data/lib/onceover/cli.rb +1 -1
  14. data/lib/onceover/cli/init.rb +1 -1
  15. data/lib/onceover/cli/run.rb +4 -3
  16. data/lib/onceover/cli/show.rb +3 -3
  17. data/lib/onceover/cli/update.rb +2 -2
  18. data/lib/onceover/controlrepo.rb +36 -36
  19. data/lib/onceover/deploy.rb +3 -1
  20. data/lib/onceover/group.rb +1 -1
  21. data/lib/onceover/logger.rb +2 -1
  22. data/lib/onceover/rake_tasks.rb +2 -1
  23. data/lib/onceover/rspec/formatters.rb +17 -5
  24. data/lib/onceover/runner.rb +17 -5
  25. data/lib/onceover/testconfig.rb +22 -12
  26. data/onceover.gemspec +14 -18
  27. data/spec/fixtures/controlrepos/caching/spec/r10k.yaml +3 -0
  28. data/spec/fixtures/controlrepos/windows/Gemfile +3 -0
  29. data/spec/fixtures/controlrepos/windows/Puppetfile +3 -0
  30. data/spec/fixtures/controlrepos/windows/environment.conf +1 -0
  31. data/spec/fixtures/controlrepos/windows/site-modules/role/manifests/acl.pp +12 -0
  32. data/spec/fixtures/controlrepos/windows/site-modules/role/manifests/groups.pp +8 -0
  33. data/spec/fixtures/controlrepos/windows/site-modules/role/manifests/users.pp +9 -0
  34. data/spec/fixtures/controlrepos/windows/site/role/manifests/groups.pp +8 -0
  35. data/spec/fixtures/controlrepos/windows/site/role/manifests/users.pp +9 -0
  36. data/spec/fixtures/controlrepos/windows/spec/onceover.yaml +24 -0
  37. data/templates/test_spec.rb.erb +60 -0
  38. metadata +81 -110
@@ -26,7 +26,7 @@ Given(/^control repo "([^"]*)" without "([^"]*)"$/) do |controlrepo_name, filena
26
26
  end
27
27
 
28
28
  When(/^I run onceover command "([^"]*)"$/) do |command|
29
- @cmd.command = command
29
+ @cmd.command = "#{command} --debug"
30
30
  puts @cmd
31
31
  @cmd.run
32
32
  end
@@ -37,6 +37,17 @@ When(/^I run onceover command "([^"]*)" with class "([^"]*)"$/) do |command, cl
37
37
  @cmd.run
38
38
  end
39
39
 
40
+ # The below can be used to skip tests if they only work on one os
41
+ When(/^test osfamily is "(\w*)"$/) do |osfamily|
42
+ require 'facter'
43
+ pending unless Facter.value(:os)['family'] == osfamily
44
+ end
45
+
46
+ When(/^test osfamily is not "(\w*)"$/) do |osfamily|
47
+ require 'facter'
48
+ pending if Facter.value(:os)['family'] == osfamily
49
+ end
50
+
40
51
  Then(/^I see help for commands: "([^"]*)"$/) do |commands|
41
52
  # Get chunk of output between COMMANDS and OPTION, there should be help section
42
53
  commands_help = @cmd.output[/COMMANDS(.*)OPTIONS/m, 1]
@@ -0,0 +1,30 @@
1
+ @windows
2
+ Feature: Run onceover with windows
3
+ Onceover should allow to run rspec and acceptance test for all profvile and role classes
4
+ or for any part of them. Use should set if he wants to see only summary of tests or full
5
+ log info.
6
+
7
+ Background:
8
+ Given onceover executable
9
+
10
+ Scenario: Run with common Windows code
11
+ Given control repo "windows"
12
+ When I run onceover command "run spec" with class "role::users"
13
+ Then I should not see any errors
14
+
15
+ Scenario: Run with common Windows code without workarounds
16
+ Given existing control repo "windows"
17
+ When I run onceover command "run spec --no_workarounds" with class "role::users"
18
+ And test osfamily is not "windows"
19
+ Then Onceover should exit 1
20
+
21
+ Scenario: Compiling a windows role with groups that is valid should compile
22
+ Given control repo "windows"
23
+ When I run onceover command "run spec" with class "role::groups"
24
+ Then I should not see any errors
25
+
26
+ Scenario: Compiling a windows role with users that is valid should compile
27
+ Given control repo "windows"
28
+ When I run onceover command "run spec" with class "role::users"
29
+ Then I should not see any errors
30
+
@@ -27,6 +27,11 @@ Feature: Run rspec and acceptance test suites
27
27
  When I run onceover command "run spec"
28
28
  Then I should see message pattern "apache::params"
29
29
 
30
+ Scenario: Checking that r10k config works
31
+ Given initialized control repo "caching"
32
+ When I run onceover command "run spec --debug"
33
+ Then I should see message pattern "r10k.yaml"
34
+
30
35
  Scenario: Run spec tests with misspelled module in Puppetfile
31
36
  Given initialized control repo "basic"
32
37
  And in Puppetfile is misspelled module's name
@@ -1,3 +1,6 @@
1
+ # rubocop:disable Style/RescueStandardError
2
+ # ^^ I canlt be bothered fixing this because all of this code is deprecated
3
+
1
4
  class Onceover
2
5
  class Beaker
3
6
  # WARNING: All of this functionality is deprecated. It will be left around
@@ -232,7 +235,10 @@ class Onceover
232
235
  end
233
236
 
234
237
  raise "The networkmanager created too many machines! Only expecting one" if hosts.count > 1
238
+
235
239
  @nwm.instance_variable_get(:@hosts)[0]
236
240
  end
237
241
  end
238
242
  end
243
+
244
+ # rubocop:enable Style/RescueStandardError
@@ -3,7 +3,7 @@ require 'cri'
3
3
  class Onceover
4
4
  class CLI
5
5
  def self.command
6
- @cmd ||= Cri::Command.define do
6
+ @command ||= Cri::Command.define do
7
7
  name 'onceover'
8
8
  usage 'onceover <subcommand> [options]'
9
9
  summary 'Tool for testing Puppet controlrepos'
@@ -9,7 +9,7 @@ class Onceover
9
9
  class CLI
10
10
  class Init
11
11
  def self.command
12
- @cmd ||= Cri::Command.define do
12
+ @command ||= Cri::Command.define do
13
13
  name 'init'
14
14
  usage 'init'
15
15
  summary 'Sets up a controlrepo for testing from scratch'
@@ -10,7 +10,7 @@ class Onceover
10
10
  class CLI
11
11
  class Run
12
12
  def self.command
13
- @cmd ||= Cri::Command.define do
13
+ @command ||= Cri::Command.define do
14
14
  name 'run'
15
15
  usage 'run [spec|acceptance]'
16
16
  summary 'Runs either the spec or acceptance tests'
@@ -35,13 +35,14 @@ This includes deploying using r10k and running all custom tests.
35
35
 
36
36
  class Spec
37
37
  def self.command
38
- @cmd ||= Cri::Command.define do
38
+ @command ||= Cri::Command.define do
39
39
  name 'spec'
40
40
  usage 'spec'
41
41
  summary 'Runs spec tests'
42
42
 
43
43
  optional :p, :parallel, 'Runs spec tests in parallel. This increases speed at the cost of poorly formatted logs and irrelevant junit output.'
44
44
  optional nil, :format, 'Which RSpec formatter to use, valid options are: documentation, progress, FailureCollector, OnceoverFormatter. You also specify this multiple times', multiple: true, default: :defaults
45
+ optional nil, :no_workarounds, 'Disables workarounds that have been added for convenience to get around common RSPec issues such as https://github.com/rodjek/rspec-puppet/issues/665'
45
46
 
46
47
  run do |opts, args, cmd|
47
48
  repo = Onceover::Controlrepo.new(opts)
@@ -56,7 +57,7 @@ This includes deploying using r10k and running all custom tests.
56
57
 
57
58
  class Acceptance
58
59
  def self.command
59
- @cmd ||= Cri::Command.define do
60
+ @command ||= Cri::Command.define do
60
61
  name 'acceptance'
61
62
  usage 'acceptance'
62
63
  summary 'Runs acceptance tests'
@@ -7,7 +7,7 @@ class Onceover
7
7
  class CLI
8
8
  class Show
9
9
  def self.command
10
- @cmd ||= Cri::Command.define do
10
+ @command ||= Cri::Command.define do
11
11
  name 'show'
12
12
  usage 'show [controlrepo|puppetfile]'
13
13
  summary 'Shows the current state of things'
@@ -25,7 +25,7 @@ Shows the state of either the controlrepo or the Puppetfile
25
25
 
26
26
  class Repo
27
27
  def self.command
28
- @cmd ||= Cri::Command.define do
28
+ @command ||= Cri::Command.define do
29
29
  name 'repo'
30
30
  usage 'repo [options]'
31
31
  summary 'Shows the current state of the Controlrepo'
@@ -50,7 +50,7 @@ Useful for debugging.
50
50
 
51
51
  class Puppetfile
52
52
  def self.command
53
- @cmd ||= Cri::Command.define do
53
+ @command ||= Cri::Command.define do
54
54
  name 'puppetfile'
55
55
  usage 'puppetfile [options]'
56
56
  summary 'Shows the current state of the puppetfile'
@@ -7,7 +7,7 @@ class Onceover
7
7
  class CLI
8
8
  class Update
9
9
  def self.command
10
- @cmd ||= Cri::Command.define do
10
+ @command ||= Cri::Command.define do
11
11
  name 'update'
12
12
  usage 'update puppetfile'
13
13
  summary 'Updates stuff, currently only the Puppetfile'
@@ -22,7 +22,7 @@ class Onceover
22
22
 
23
23
  class Puppetfile
24
24
  def self.command
25
- @cmd ||= Cri::Command.define do
25
+ @command ||= Cri::Command.define do
26
26
  name 'puppetfile'
27
27
  usage 'puppetfile'
28
28
  summary 'Update all modules in the Puppetfile'
@@ -3,7 +3,6 @@ require 'erb'
3
3
  require 'yaml'
4
4
  require 'find'
5
5
  require 'pathname'
6
- require 'thread'
7
6
  require 'multi_json'
8
7
  require 'onceover/beaker'
9
8
  require 'onceover/logger'
@@ -115,7 +114,7 @@ class Onceover
115
114
  @environment_conf = opts[:environment_conf] || File.expand_path('./environment.conf', @root)
116
115
  @spec_dir = opts[:spec_dir] || File.expand_path('./spec', @root)
117
116
  @facts_dir = opts[:facts_dir] || File.expand_path('factsets', @spec_dir)
118
- _facts_dirs = [@facts_dir, File.expand_path('../../../factsets', __FILE__)]
117
+ _facts_dirs = [@facts_dir, File.expand_path('../../factsets', __dir__)]
119
118
  _facts_files = opts[:facts_files] || _facts_dirs.map{|d| File.join(d, '*.json')}
120
119
  @facts_files = _facts_files.map{|_path| Dir[_path]}.flatten
121
120
 
@@ -134,7 +133,7 @@ class Onceover
134
133
  def to_s
135
134
  require 'colored'
136
135
 
137
- <<-END.gsub(/^\s{4}/,'')
136
+ <<-REPO.gsub(/^\s{4}/,'')
138
137
  #{'puppetfile'.green} #{@puppetfile}
139
138
  #{'environment_conf'.green} #{@environment_conf}
140
139
  #{'facts_dir'.green} #{@facts_dir}
@@ -144,7 +143,7 @@ class Onceover
144
143
  #{'roles'.green} #{roles}
145
144
  #{'profiles'.green} #{profiles}
146
145
  #{'onceover.yaml'.green} #{@onceover_yaml}
147
- END
146
+ REPO
148
147
  end
149
148
 
150
149
  def roles
@@ -190,6 +189,7 @@ class Onceover
190
189
  if filter
191
190
  # Allow us to pass a hash of facts to filter by
192
191
  raise "Filter param must be a hash" unless filter.is_a?(Hash)
192
+
193
193
  all_facts.keep_if do |hash|
194
194
  matches = []
195
195
  filter.each do |filter_fact,value|
@@ -206,7 +206,7 @@ class Onceover
206
206
  end
207
207
 
208
208
  def print_puppetfile_table
209
- require 'table_print'
209
+ require 'terminal-table'
210
210
  require 'versionomy'
211
211
  require 'colored'
212
212
  require 'r10k/puppetfile'
@@ -221,46 +221,44 @@ class Onceover
221
221
  threads = []
222
222
  puppetfile.modules.each do |mod|
223
223
  threads << Thread.new do
224
- return_hash = {}
224
+ row = []
225
225
  logger.debug "Loading data for #{mod.full_name}"
226
- return_hash[:full_name] = mod.full_name
226
+ row << mod.full_name
227
227
  if mod.is_a?(R10K::Module::Forge)
228
- return_hash[:current_version] = mod.expected_version
229
- return_hash[:latest_version] = mod.v3_module.current_release.version
230
- return_hash[:endorsement] = mod.v3_module.endorsement
228
+ row << mod.expected_version
229
+ row << mod.v3_module.current_release.version
230
+
231
+ current = Versionomy.parse(mod.expected_version)
232
+ latest = Versionomy.parse(mod.v3_module.current_release.version)
233
+ row << if current.major < latest.major
234
+ "Major".red
235
+ elsif current.minor < latest.minor
236
+ "Minor".yellow
237
+ elsif current.tiny < latest.tiny
238
+ "Tiny".green
239
+ else
240
+ "No".green
241
+ end
242
+
243
+ row << mod.v3_module.endorsement
231
244
  superseded_by = mod.v3_module.superseded_by
232
- return_hash[:superseded_by] = superseded_by.nil? ? '' : superseded_by[:slug]
233
- current = Versionomy.parse(return_hash[:current_version])
234
- latest = Versionomy.parse(return_hash[:latest_version])
235
- if current.major < latest.major
236
- return_hash[:out_of_date] = "Major".red
237
- elsif current.minor < latest.minor
238
- return_hash[:out_of_date] = "Minor".yellow
239
- elsif current.tiny < latest.tiny
240
- return_hash[:out_of_date] = "Tiny".green
241
- else
242
- return_hash[:out_of_date] = "No".green
243
- end
245
+ row << (superseded_by.nil? ? '' : superseded_by[:slug])
244
246
  else
245
- return_hash[:current_version] = "N/A"
246
- return_hash[:latest_version] = "N/A"
247
- return_hash[:out_of_date] = "N/A"
248
- return_hash[:endorsement] = "N/A"
249
- return_hash[:superseded_by] = "N/A"
247
+ row << "N/A"
248
+ row << "N/A"
249
+ row << "N/A"
250
+ row << "N/A"
251
+ row << "N/A"
250
252
  end
251
- output_array << return_hash
253
+ output_array << row
252
254
  end
253
255
  end
254
256
 
255
257
  threads.map(&:join)
256
258
 
257
- tp output_array,
258
- {:full_name => {:display_name => "Full Name"}},
259
- {:current_version => {:display_name => "Current Version"}},
260
- {:latest_version => {:display_name => "Latest Version"}},
261
- {:out_of_date => {:display_name => "Out of Date?"}},
262
- {:endorsement => {:display_name => "Endorsement"}},
263
- {:superseded_by => {:display_name => "Superseded by"}}
259
+ output_array.sort_by! { |line| line[0] }
260
+
261
+ puts Terminal::Table.new(headings: ["Full Name", "Current Version", "Latest Version", "Out of Date?", "Endorsement", "Superseded by"], rows: output_array)
264
262
  end
265
263
 
266
264
  def update_puppetfile
@@ -305,6 +303,7 @@ class Onceover
305
303
  # Load up the Puppetfile using R10k
306
304
  puppetfile = R10K::Puppetfile.new(@root)
307
305
  fail 'Could not load Puppetfile' unless puppetfile.load
306
+
308
307
  modules = puppetfile.modules
309
308
 
310
309
  # Iterate over everything and seperate it out for the sake of readability
@@ -395,6 +394,7 @@ class Onceover
395
394
  possibe_datadirs = Dir["#{@root}/*/"]
396
395
  possibe_datadirs.keep_if { |dir| dir =~ /hiera(?:.*data)?/i }
397
396
  raise "There were too many directories that looked like hiera data: #{possibe_datadirs}" if possibe_datadirs.count > 1
397
+
398
398
  File.expand_path(possibe_datadirs[0])
399
399
  end
400
400
 
@@ -417,7 +417,7 @@ class Onceover
417
417
  # Finally, split the modulepath values and return
418
418
  begin
419
419
  environment_config['modulepath'] = environment_config['modulepath'].split(':')
420
- rescue
420
+ rescue StandardError
421
421
  raise "modulepath was not found in environment.conf, don't know where to look for roles & profiles"
422
422
  end
423
423
 
@@ -118,8 +118,10 @@ class Onceover
118
118
  prod_dir = "#{repo.tempdir}/#{repo.environmentpath}/production"
119
119
  Dir.chdir(prod_dir) do
120
120
  install_cmd = []
121
- install_cmd << "r10k puppetfile install --verbose --color --puppetfile #{repo.puppetfile}"
121
+ install_cmd << "r10k puppetfile install --color --puppetfile #{repo.puppetfile}"
122
122
  install_cmd << "--force" if force
123
+ install_cmd << "--config #{repo.r10k_config_file}" if repo.r10k_config_file
124
+ install_cmd << (logger.level > 0 ? "--verbose" : "--verbose debug") # Enable debugging if we're debugging
123
125
  install_cmd = install_cmd.join(' ')
124
126
  logger.debug "Running #{install_cmd} from #{prod_dir}"
125
127
  system(install_cmd)
@@ -71,7 +71,7 @@ class Onceover
71
71
  else
72
72
  return false
73
73
  end
74
- rescue
74
+ rescue StandardErroor
75
75
  return false
76
76
  end
77
77
  end
@@ -4,7 +4,8 @@ module Onceover::Logger
4
4
  def logger
5
5
  unless $logger
6
6
  # here we setup a color scheme called 'bright'
7
- Logging.color_scheme('bright',
7
+ Logging.color_scheme(
8
+ 'bright',
8
9
  :levels => {
9
10
  :debug => :cyan,
10
11
  :info => :green,
@@ -8,9 +8,10 @@ require 'pathname'
8
8
  desc 'Writes a `fixtures.yml` file based on the Puppetfile'
9
9
  task :generate_fixtures do
10
10
  repo = Onceover::Controlrepo.new
11
- if File.exists?(File.expand_path('./.fixtures.yml', repo.root))
11
+ if File.exist?(File.expand_path('./.fixtures.yml', repo.root))
12
12
  raise ".fixtures.yml already exits, we won't overwrite because we are scared"
13
13
  end
14
+
14
15
  File.write(File.expand_path('./.fixtures.yml', repo.root), repo.fixtures)
15
16
  end
16
17
 
@@ -2,8 +2,14 @@ require 'rspec'
2
2
  require 'pathname'
3
3
 
4
4
  class OnceoverFormatter
5
- RSpec::Core::Formatters.register self, :example_group_started,
6
- :example_passed, :example_failed, :example_pending, :dump_failures#, :dump_summary
5
+ RSpec::Core::Formatters.register(
6
+ self,
7
+ :example_group_started,
8
+ :example_passed,
9
+ :example_failed,
10
+ :example_pending,
11
+ :dump_failures,
12
+ )
7
13
 
8
14
  COMPILATION_ERROR = %r{error during compilation: (?<error>.*)}
9
15
  ERROR_WITH_LOCATION = %r{(?<error>.*?)\s(at )?(\((file: (?<file>.*?), )?line: (?<line>\d+)(, column: (?<column>\d+))?\))(; )?}
@@ -218,8 +224,14 @@ end
218
224
  class OnceoverFormatterParallel < OnceoverFormatter
219
225
  require 'yaml'
220
226
 
221
- RSpec::Core::Formatters.register self, :example_group_started,
222
- :example_passed, :example_failed, :example_pending, :dump_failures
227
+ RSpec::Core::Formatters.register(
228
+ self,
229
+ :example_group_started,
230
+ :example_passed,
231
+ :example_failed,
232
+ :example_pending,
233
+ :dump_failures,
234
+ )
223
235
 
224
236
  def example_group_started notification
225
237
  # Do nothing
@@ -287,7 +299,7 @@ class FailureCollector
287
299
  end
288
300
 
289
301
  def dump_failures(failures)
290
- open(File.expand_path("#{RSpec.configuration.onceover_tempdir}/failures.out"), 'a') { |f|
302
+ File.open(File.expand_path("#{RSpec.configuration.onceover_tempdir}/failures.out"), 'a') { |f|
291
303
  failures.failed_examples.each do |fe|
292
304
  f.puts
293
305
  f.puts "#{fe.metadata[:description]}"
@@ -53,8 +53,10 @@ class Onceover
53
53
  @config.acceptance_tests.each { |test| @config.verify_acceptance_test(@repo, test) }
54
54
 
55
55
  # Write them out
56
- @config.write_acceptance_tests("#{@repo.tempdir}/spec/acceptance",
57
- @config.run_filters(Onceover::Test.deduplicate(@config.acceptance_tests)))
56
+ @config.write_acceptance_tests(
57
+ "#{@repo.tempdir}/spec/acceptance",
58
+ @config.run_filters(Onceover::Test.deduplicate(@config.acceptance_tests))
59
+ )
58
60
  end
59
61
 
60
62
  # Parse the current hiera config, modify, and write it to the temp dir
@@ -85,10 +87,11 @@ class Onceover
85
87
  #`bin/rake spec_standalone`
86
88
  if @config.opts[:parallel]
87
89
  logger.debug "Running #{@command_prefix}rake parallel_spec from #{@repo.tempdir}"
88
- result = Backticks::Runner.new(interactive:true).run(@command_prefix.strip.split, 'rake', 'parallel_spec').join
90
+ result = run_command(@command_prefix.strip.split, 'rake', 'parallel_spec')
89
91
  else
92
+ require 'io/console'
90
93
  logger.debug "Running #{@command_prefix}rake spec_standalone from #{@repo.tempdir}"
91
- result = Backticks::Runner.new(interactive:true).run(@command_prefix.strip.split, 'rake', 'spec_standalone').join
94
+ result = run_command(@command_prefix.strip.split, 'rake', 'spec_standalone')
92
95
  end
93
96
 
94
97
  # Reset env to previous state if we modified it
@@ -115,11 +118,20 @@ class Onceover
115
118
  #`bundle install --binstubs`
116
119
  #`bin/rake spec_standalone`
117
120
  logger.debug "Running #{@command_prefix}rake acceptance from #{@repo.tempdir}"
118
- result = Backticks::Runner.new(interactive:true).run(@command_prefix.strip.split, 'rake', 'acceptance').join
121
+ result = run_command(@command_prefix.strip.split, 'rake', 'acceptance')
119
122
  end
120
123
 
121
124
  # Finally exit and preserve the exit code
122
125
  exit result.status.exitstatus
123
126
  end
127
+
128
+ def run_command(*args)
129
+ begin
130
+ STDERR.raw! if STDERR.isatty
131
+ result = Backticks::Runner.new(interactive: true).run(args.flatten).join
132
+ ensure
133
+ STDERR.cooked! if STDERR.isatty
134
+ end
135
+ end
124
136
  end
125
137
  end