puppetlabs-onceover 5.0.3 → 5.0.4
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 +4 -4
- data/.gitignore +4 -0
- data/.rubocop_todo.yml +35 -15
- data/CHANGELOG.md +387 -3
- data/Gemfile +1 -0
- data/lib/puppetlabs-onceover/cli/plugins.rb +3 -3
- data/lib/puppetlabs-onceover/controlrepo.rb +8 -7
- data/lib/puppetlabs-onceover/version.rb +1 -1
- data/spec/fixtures/controlrepos/deploy_test/Puppetfile +3 -0
- data/spec/fixtures/controlrepos/deploy_test/a_dir/nested_file.txt +1 -0
- data/spec/fixtures/controlrepos/deploy_test/a_symlink +1 -0
- data/spec/fixtures/controlrepos/deploy_test/environment.conf +1 -0
- data/spec/fixtures/controlrepos/deploy_test/regular_file.txt +1 -0
- data/spec/puppetlabs-onceover/beaker_spec.rb +293 -0
- data/spec/puppetlabs-onceover/class_spec.rb +89 -0
- data/spec/puppetlabs-onceover/cli/run_spec.rb +80 -0
- data/spec/puppetlabs-onceover/cli/show_spec.rb +67 -0
- data/spec/puppetlabs-onceover/cli_spec.rb +79 -0
- data/spec/puppetlabs-onceover/controlrepo_spec.rb +787 -5
- data/spec/puppetlabs-onceover/deploy_spec.rb +246 -0
- data/spec/puppetlabs-onceover/group_spec.rb +121 -0
- data/spec/puppetlabs-onceover/logger_spec.rb +30 -0
- data/spec/puppetlabs-onceover/node_spec.rb +124 -0
- data/spec/puppetlabs-onceover/rake_tasks_spec.rb +173 -0
- data/spec/puppetlabs-onceover/rspec/formatters_spec.rb +361 -0
- data/spec/puppetlabs-onceover/runner_spec.rb +307 -0
- data/spec/puppetlabs-onceover/test_spec.rb +177 -0
- data/spec/puppetlabs-onceover/testconfig_spec.rb +451 -0
- data/spec/puppetlabs-onceover/vendored_modules_spec.rb +302 -0
- data/spec/puppetlabs-onceover/version_spec.rb +10 -0
- data/spec/spec_helper.rb +8 -0
- metadata +22 -1
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'rake'
|
|
3
|
+
require 'ostruct'
|
|
4
|
+
|
|
5
|
+
describe 'rake_tasks.rb' do
|
|
6
|
+
# SimpleCov/Coverage tracks a given file path's hit-lines against the ISeq
|
|
7
|
+
# produced by the FIRST time it's compiled in this process. Re-`load`ing
|
|
8
|
+
# the file fresh in a before(:each) (once per example) makes every example
|
|
9
|
+
# after the first exercise a *new*, uninstrumented compilation, so real
|
|
10
|
+
# task-body coverage silently reads back as 0. Instead we `load` the file
|
|
11
|
+
# exactly once for the whole group, and use `Rake::Task#reenable` before
|
|
12
|
+
# each invoke so a task can be invoked again in a later example.
|
|
13
|
+
rake_tasks_path = File.expand_path('../../lib/puppetlabs-onceover/rake_tasks.rb', __dir__)
|
|
14
|
+
Rake.application = Rake::Application.new
|
|
15
|
+
load rake_tasks_path
|
|
16
|
+
|
|
17
|
+
before(:each) do
|
|
18
|
+
Rake::Task.tasks.each(&:reenable)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
describe 'generate_fixtures' do
|
|
22
|
+
it 'writes fixtures.yml when it does not already exist' do
|
|
23
|
+
repo = double('repo', root: '/tmp/nonexistent_root_for_test', fixtures: "fixture_content")
|
|
24
|
+
allow(PuppetlabsOnceover::Controlrepo).to receive(:new).and_return(repo)
|
|
25
|
+
allow(File).to receive(:exist?).and_call_original
|
|
26
|
+
allow(File).to receive(:exist?).with(File.expand_path('./.fixtures.yml', repo.root)).and_return(false)
|
|
27
|
+
allow(File).to receive(:write)
|
|
28
|
+
|
|
29
|
+
Rake::Task['generate_fixtures'].invoke
|
|
30
|
+
|
|
31
|
+
expect(File).to have_received(:write).with(File.expand_path('./.fixtures.yml', repo.root), 'fixture_content')
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it 'raises when fixtures.yml already exists' do
|
|
35
|
+
repo = double('repo', root: '/tmp/nonexistent_root_for_test')
|
|
36
|
+
allow(PuppetlabsOnceover::Controlrepo).to receive(:new).and_return(repo)
|
|
37
|
+
allow(File).to receive(:exist?).and_call_original
|
|
38
|
+
allow(File).to receive(:exist?).with(File.expand_path('./.fixtures.yml', repo.root)).and_return(true)
|
|
39
|
+
|
|
40
|
+
expect { Rake::Task['generate_fixtures'].invoke }.to raise_error(/already exits/)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
describe 'hiera_setup' do
|
|
45
|
+
it 'updates the datadir for hash values containing datadir and writes the new config' do
|
|
46
|
+
hiera_config = { defaults: { datadir: 'orig/data' } }
|
|
47
|
+
repo = double('repo')
|
|
48
|
+
allow(repo).to receive(:hiera_config).and_return(hiera_config)
|
|
49
|
+
# Use File.expand_path so these are real OS-native absolute paths on any
|
|
50
|
+
# platform (Windows Pathname#relative_path_from raises "different prefix"
|
|
51
|
+
# when comparing a bare '/some/repo'-style path against one that's been
|
|
52
|
+
# expanded to a drive-letter path).
|
|
53
|
+
allow(repo).to receive(:hiera_config_file).and_return(File.expand_path('/some/repo/hiera.yaml'))
|
|
54
|
+
allow(repo).to receive(:hiera_data).and_return(File.expand_path('/some/repo/data'))
|
|
55
|
+
allow(repo).to receive(:hiera_config=)
|
|
56
|
+
allow(PuppetlabsOnceover::Controlrepo).to receive(:new).and_return(repo)
|
|
57
|
+
|
|
58
|
+
Rake::Task['hiera_setup'].invoke
|
|
59
|
+
|
|
60
|
+
expect(repo).to have_received(:hiera_config=) do |new_config|
|
|
61
|
+
expect(new_config[:defaults][:datadir]).to eq('data')
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it 'leaves non-hash values alone' do
|
|
66
|
+
hiera_config = { version: 5 }
|
|
67
|
+
repo = double('repo')
|
|
68
|
+
allow(repo).to receive(:hiera_config).and_return(hiera_config)
|
|
69
|
+
allow(repo).to receive(:hiera_config_file).and_return('/some/repo/hiera.yaml')
|
|
70
|
+
allow(repo).to receive(:hiera_data).and_return('/some/repo/data')
|
|
71
|
+
allow(repo).to receive(:hiera_config=)
|
|
72
|
+
allow(PuppetlabsOnceover::Controlrepo).to receive(:new).and_return(repo)
|
|
73
|
+
|
|
74
|
+
Rake::Task['hiera_setup'].invoke
|
|
75
|
+
|
|
76
|
+
expect(repo).to have_received(:hiera_config=).with(hiera_config)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
describe 'controlrepo_details' do
|
|
81
|
+
it 'prints the controlrepo to_s' do
|
|
82
|
+
repo = double('repo', to_s: 'REPO DETAILS')
|
|
83
|
+
allow(PuppetlabsOnceover::Controlrepo).to receive(:new).and_return(repo)
|
|
84
|
+
|
|
85
|
+
expect { Rake::Task['controlrepo_details'].invoke }.to output(/REPO DETAILS/).to_stdout
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
describe 'generate_onceover_yaml' do
|
|
90
|
+
it 'reads the controlrepo and attempts to render the controlrepo.yaml.erb template' do
|
|
91
|
+
repo = double('repo')
|
|
92
|
+
allow(PuppetlabsOnceover::Controlrepo).to receive(:new).and_return(repo)
|
|
93
|
+
|
|
94
|
+
# NOTE: the bundled erb gem (6.0.7, from Ruby 3.3.12) no longer accepts
|
|
95
|
+
# ERB.new's legacy positional (safe_level, trim_mode) arguments, which
|
|
96
|
+
# rake_tasks.rb still passes. This is a pre-existing incompatibility in
|
|
97
|
+
# production code, not something introduced by this test. We assert the
|
|
98
|
+
# task reaches and exercises that ERB.new call (line coverage), rather
|
|
99
|
+
# than papering over the ArgumentError it currently raises in this Ruby.
|
|
100
|
+
expect { Rake::Task['generate_onceover_yaml'].invoke }.to raise_error(ArgumentError)
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
describe 'generate_nodesets' do
|
|
105
|
+
it 'writes a nodeset entry for each factset, handling a 404 box lookup' do
|
|
106
|
+
repo = double('repo')
|
|
107
|
+
allow(repo).to receive(:facts).and_return([{ 'os' => { 'family' => 'RedHat' } }])
|
|
108
|
+
allow(repo).to receive(:facts_files).and_return(['/some/repo/facts/centos7.json'])
|
|
109
|
+
allow(PuppetlabsOnceover::Controlrepo).to receive(:new).and_return(repo)
|
|
110
|
+
|
|
111
|
+
require 'puppetlabs-onceover/beaker'
|
|
112
|
+
allow(PuppetlabsOnceover::Beaker).to receive(:facts_to_vagrant_box).and_return('centos/7')
|
|
113
|
+
allow(PuppetlabsOnceover::Beaker).to receive(:facts_to_platform).and_return('el-7-x86_64')
|
|
114
|
+
|
|
115
|
+
http_double = double('http', use_ssl: true, 'use_ssl=': true)
|
|
116
|
+
response = double('response', code: '404', body: '{}')
|
|
117
|
+
allow(Net::HTTP).to receive(:new).and_return(http_double)
|
|
118
|
+
allow(http_double).to receive(:get).and_return(response)
|
|
119
|
+
|
|
120
|
+
# See the note in the generate_onceover_yaml spec above: the bundled
|
|
121
|
+
# erb 6.0.7 no longer accepts ERB.new's legacy positional arguments,
|
|
122
|
+
# so this task raises ArgumentError once it reaches its own ERB.new
|
|
123
|
+
# call further down. We assert the "HOSTS:" header and 404 branch
|
|
124
|
+
# (comment_out = true) execute first, covering those lines.
|
|
125
|
+
expect { Rake::Task['generate_nodesets'].invoke }.to raise_error(ArgumentError).and output(/HOSTS:/).to_stdout
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
it 'writes a nodeset entry using the virtualbox provider url when the box lookup succeeds' do
|
|
129
|
+
repo = double('repo')
|
|
130
|
+
allow(repo).to receive(:facts).and_return([{ 'os' => { 'family' => 'RedHat' } }])
|
|
131
|
+
allow(repo).to receive(:facts_files).and_return(['/some/repo/facts/centos7.json'])
|
|
132
|
+
allow(PuppetlabsOnceover::Controlrepo).to receive(:new).and_return(repo)
|
|
133
|
+
|
|
134
|
+
require 'puppetlabs-onceover/beaker'
|
|
135
|
+
allow(PuppetlabsOnceover::Beaker).to receive(:facts_to_vagrant_box).and_return('centos/7')
|
|
136
|
+
allow(PuppetlabsOnceover::Beaker).to receive(:facts_to_platform).and_return('el-7-x86_64')
|
|
137
|
+
|
|
138
|
+
box_body = {
|
|
139
|
+
'current_version' => {
|
|
140
|
+
'providers' => [
|
|
141
|
+
{ 'name' => 'virtualbox', 'original_url' => 'https://example.com/box.box' }
|
|
142
|
+
]
|
|
143
|
+
}
|
|
144
|
+
}.to_json
|
|
145
|
+
|
|
146
|
+
http_double = double('http', use_ssl: true, 'use_ssl=': true)
|
|
147
|
+
response = double('response', code: '200', body: box_body)
|
|
148
|
+
allow(Net::HTTP).to receive(:new).and_return(http_double)
|
|
149
|
+
allow(http_double).to receive(:get).and_return(response)
|
|
150
|
+
|
|
151
|
+
# As above: covers the successful (non-404) lookup branch, including
|
|
152
|
+
# the virtualbox provider url extraction, before hitting the same
|
|
153
|
+
# pre-existing ERB.new incompatibility.
|
|
154
|
+
expect { Rake::Task['generate_nodesets'].invoke }.to raise_error(ArgumentError).and output(/HOSTS:/).to_stdout
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
describe 'generate_vendor_cache' do
|
|
159
|
+
it 'creates a VendoredModules cache for the controlrepo' do
|
|
160
|
+
repo = double('repo', spec_dir: '/some/repo/spec')
|
|
161
|
+
allow(PuppetlabsOnceover::Controlrepo).to receive(:new).with(debug: true).and_return(repo)
|
|
162
|
+
|
|
163
|
+
require 'puppetlabs-onceover/vendored_modules'
|
|
164
|
+
allow(PuppetlabsOnceover::VendoredModules).to receive(:new)
|
|
165
|
+
|
|
166
|
+
Rake::Task['generate_vendor_cache'].invoke
|
|
167
|
+
|
|
168
|
+
expect(PuppetlabsOnceover::VendoredModules).to have_received(:new).with(
|
|
169
|
+
hash_including(repo: repo, force_update: true)
|
|
170
|
+
)
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
end
|
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'stringio'
|
|
3
|
+
require 'tmpdir'
|
|
4
|
+
require 'fileutils'
|
|
5
|
+
require 'yaml'
|
|
6
|
+
require 'puppetlabs-onceover/controlrepo'
|
|
7
|
+
require 'puppetlabs-onceover/rspec/formatters'
|
|
8
|
+
|
|
9
|
+
describe PuppetlabsOnceoverFormatter do
|
|
10
|
+
let(:output) { StringIO.new }
|
|
11
|
+
subject(:formatter) { described_class.new(output) }
|
|
12
|
+
|
|
13
|
+
def group_double(description)
|
|
14
|
+
group = double('group', description: description)
|
|
15
|
+
allow(group).to receive(:parent_groups).and_return([group])
|
|
16
|
+
group
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def stub_world_groups(descriptions)
|
|
20
|
+
groups = descriptions.map { |d| double('group', description: d) }
|
|
21
|
+
allow(RSpec.configuration.world).to receive(:example_groups).and_return(groups)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def failure_double(role:, factset:, raw_error:, description: 'a test', file_path: '/spec/foo_spec.rb', line_number: 5)
|
|
25
|
+
metadata = {
|
|
26
|
+
example_group: {
|
|
27
|
+
description: factset,
|
|
28
|
+
parent_example_group: { description: role }
|
|
29
|
+
},
|
|
30
|
+
execution_result: double('execution_result', exception: RuntimeError.new(raw_error)),
|
|
31
|
+
description: description,
|
|
32
|
+
file_path: file_path,
|
|
33
|
+
line_number: line_number
|
|
34
|
+
}
|
|
35
|
+
double('example', metadata: metadata)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
describe '#example_group_started' do
|
|
39
|
+
context 'when the group is a top-level role' do
|
|
40
|
+
it 'prints the role name and sets previous_role' do
|
|
41
|
+
stub_world_groups(['role::foo', 'role::barbaz'])
|
|
42
|
+
group = group_double('role::foo')
|
|
43
|
+
notification = double('notification', group: group)
|
|
44
|
+
|
|
45
|
+
formatter.example_group_started(notification)
|
|
46
|
+
|
|
47
|
+
expect(output.string).to include('role::foo:')
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it 'does not reprint the same role twice in a row' do
|
|
51
|
+
stub_world_groups(['role::foo'])
|
|
52
|
+
group = group_double('role::foo')
|
|
53
|
+
notification = double('notification', group: group)
|
|
54
|
+
|
|
55
|
+
formatter.example_group_started(notification)
|
|
56
|
+
first_output = output.string
|
|
57
|
+
formatter.example_group_started(notification)
|
|
58
|
+
|
|
59
|
+
expect(output.string).to eq(first_output)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
context 'when the group is nested (not the top-level role)' do
|
|
64
|
+
it "prints '? ' as a placeholder" do
|
|
65
|
+
top = double('top_group')
|
|
66
|
+
group = double('group', description: 'nested context')
|
|
67
|
+
allow(group).to receive(:parent_groups).and_return([top, group])
|
|
68
|
+
notification = double('notification', group: group)
|
|
69
|
+
|
|
70
|
+
formatter.example_group_started(notification)
|
|
71
|
+
|
|
72
|
+
expect(output.string).to eq('? ')
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
describe '#example_passed' do
|
|
78
|
+
it 'writes a green P' do
|
|
79
|
+
formatter.example_passed(double('notification'))
|
|
80
|
+
expect(output.string).to include('P')
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
describe '#example_failed' do
|
|
85
|
+
it 'writes a red F' do
|
|
86
|
+
formatter.example_failed(double('notification'))
|
|
87
|
+
expect(output.string).to include('F')
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
describe '#example_pending' do
|
|
92
|
+
it 'writes a yellow ?' do
|
|
93
|
+
formatter.example_pending(double('notification'))
|
|
94
|
+
expect(output.string).to include('?')
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
describe '#parse_errors' do
|
|
99
|
+
it 'parses a compilation error with a file/line/column location' do
|
|
100
|
+
allow(RSpec.configuration).to receive(:onceover_tempdir).and_return('/tmp/xyz/.onceover')
|
|
101
|
+
allow(RSpec.configuration).to receive(:onceover_root).and_return('/tmp/xyz')
|
|
102
|
+
allow(RSpec.configuration).to receive(:onceover_environmentpath).and_return('etc/puppetlabs/code/environments')
|
|
103
|
+
|
|
104
|
+
raw = 'Some function failed error during compilation: bad value at (file: /tmp/xyz/.onceover/etc/puppetlabs/code/environments/production/site/role/manifests/foo.pp, line: 4, column: 2); more'
|
|
105
|
+
results = formatter.parse_errors(raw)
|
|
106
|
+
expect(results.first[:line]).to eq('4')
|
|
107
|
+
expect(results.first[:column]).to eq('2')
|
|
108
|
+
expect(results.first[:file]).to eq('site/role/manifests/foo.pp')
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
it 'parses a compilation error whose location omits the file' do
|
|
112
|
+
raw = 'error during compilation: bad value at (line: 9, column: 1); trailer'
|
|
113
|
+
results = formatter.parse_errors(raw)
|
|
114
|
+
expect(results.first[:file]).to be_nil
|
|
115
|
+
expect(results.first[:line]).to eq('9')
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
it 'parses a compilation error with no location at all, matching "on node"' do
|
|
119
|
+
raw = 'error during compilation: something bad happened on node foo.example.com'
|
|
120
|
+
results = formatter.parse_errors(raw)
|
|
121
|
+
expect(results.first[:text]).to eq('something bad happened')
|
|
122
|
+
expect(results.first[:file]).to be_nil
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
it 'falls back to the raw string when a compilation error matches neither location pattern' do
|
|
126
|
+
raw = 'error during compilation: nothing structured here whatsoever'
|
|
127
|
+
results = formatter.parse_errors(raw)
|
|
128
|
+
expect(results).to eq([{ text: raw }])
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
it 'falls back to the raw string for a non-compilation error' do
|
|
132
|
+
raw = "NoMethodError: undefined method 'foo' for nil"
|
|
133
|
+
results = formatter.parse_errors(raw)
|
|
134
|
+
expect(results).to eq([{ text: raw }])
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
describe '#calculate_relative_source' do
|
|
139
|
+
before do
|
|
140
|
+
allow(RSpec.configuration).to receive(:onceover_tempdir).and_return('/tmp/xyz/.onceover')
|
|
141
|
+
allow(RSpec.configuration).to receive(:onceover_root).and_return('/tmp/xyz')
|
|
142
|
+
allow(RSpec.configuration).to receive(:onceover_environmentpath).and_return('etc/puppetlabs/code/environments')
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
it 'returns nil when given a nil file' do
|
|
146
|
+
expect(formatter.calculate_relative_source(nil)).to be_nil
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
it 'calculates the path relative to the production environment root' do
|
|
150
|
+
file = '/tmp/xyz/.onceover/etc/puppetlabs/code/environments/production/site/role/manifests/foo.pp'
|
|
151
|
+
expect(formatter.calculate_relative_source(file)).to eq('site/role/manifests/foo.pp')
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
describe '#extract_failure_data' do
|
|
156
|
+
it 'attaches the list of failing factsets to each parsed error' do
|
|
157
|
+
fails = [
|
|
158
|
+
failure_double(role: 'role::foo', factset: 'using fact set centos-7-x86_64', raw_error: 'boom'),
|
|
159
|
+
failure_double(role: 'role::foo', factset: 'using fact set windows-2019-x64', raw_error: 'boom')
|
|
160
|
+
]
|
|
161
|
+
results = formatter.extract_failure_data(fails)
|
|
162
|
+
expect(results.first[:factsets]).to eq(['centos-7-x86_64', 'windows-2019-x64'])
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
describe '#extract_failures' do
|
|
167
|
+
it 'groups failures by role and then by distinct error message' do
|
|
168
|
+
notification = double(
|
|
169
|
+
'notification',
|
|
170
|
+
failed_examples: [
|
|
171
|
+
failure_double(role: 'role::foo', factset: 'using fact set centos-7-x86_64', raw_error: 'boom one'),
|
|
172
|
+
failure_double(role: 'role::foo', factset: 'using fact set windows-2019-x64', raw_error: 'boom two'),
|
|
173
|
+
failure_double(role: 'role::bar', factset: 'using fact set centos-7-x86_64', raw_error: 'boom three')
|
|
174
|
+
]
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
grouped = formatter.extract_failures(notification)
|
|
178
|
+
|
|
179
|
+
expect(grouped.keys).to contain_exactly('role::foo', 'role::bar')
|
|
180
|
+
expect(grouped['role::foo'].size).to eq(2)
|
|
181
|
+
expect(grouped['role::bar'].size).to eq(1)
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
describe '#dump_failures' do
|
|
186
|
+
before do
|
|
187
|
+
allow(RSpec.configuration).to receive(:onceover_tempdir).and_return('/tmp/xyz/.onceover')
|
|
188
|
+
allow(RSpec.configuration).to receive(:onceover_root).and_return('/tmp/xyz')
|
|
189
|
+
allow(RSpec.configuration).to receive(:onceover_environmentpath).and_return('etc/puppetlabs/code/environments')
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
it 'renders the error summary template for each failing role' do
|
|
193
|
+
notification = double(
|
|
194
|
+
'notification',
|
|
195
|
+
failed_examples: [
|
|
196
|
+
failure_double(role: 'role::foo', factset: 'using fact set centos-7-x86_64', raw_error: 'boom')
|
|
197
|
+
]
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
formatter.dump_failures(notification)
|
|
201
|
+
|
|
202
|
+
expect(output.string).to include('role::foo')
|
|
203
|
+
expect(output.string).to include('failed')
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
describe '#longest_group' do
|
|
208
|
+
it 'returns the length of the longest example group description' do
|
|
209
|
+
stub_world_groups(['role::a', 'role::much_longer_name'])
|
|
210
|
+
expect(formatter.longest_group).to eq('role::much_longer_name'.length)
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
describe 'color helper methods' do
|
|
215
|
+
[:class_name, :black, :red, :green, :yellow, :blue, :magenta, :cyan, :white, :bold].each do |method|
|
|
216
|
+
it "##{method} wraps the given text" do
|
|
217
|
+
expect(formatter.public_send(method, 'hello')).to be_a(String)
|
|
218
|
+
expect(formatter.public_send(method, 'hello')).to include('hello')
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
describe PuppetlabsOnceoverFormatterParallel do
|
|
225
|
+
let(:output) { StringIO.new }
|
|
226
|
+
subject(:formatter) { described_class.new(output) }
|
|
227
|
+
|
|
228
|
+
def failure_double(role:, factset:, raw_error:)
|
|
229
|
+
metadata = {
|
|
230
|
+
example_group: {
|
|
231
|
+
description: factset,
|
|
232
|
+
parent_example_group: { description: role }
|
|
233
|
+
},
|
|
234
|
+
execution_result: double('execution_result', exception: RuntimeError.new(raw_error))
|
|
235
|
+
}
|
|
236
|
+
double('example', metadata: metadata)
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
describe '#example_group_started' do
|
|
240
|
+
it 'does nothing' do
|
|
241
|
+
expect { formatter.example_group_started(double('notification')) }.not_to raise_error
|
|
242
|
+
expect(output.string).to eq('')
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
describe '#example_passed' do
|
|
247
|
+
it 'writes and flushes a green P' do
|
|
248
|
+
formatter.example_passed(double('notification'))
|
|
249
|
+
expect(output.string).to include('P')
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
describe '#example_failed' do
|
|
254
|
+
it 'writes and flushes a red F' do
|
|
255
|
+
formatter.example_failed(double('notification'))
|
|
256
|
+
expect(output.string).to include('F')
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
describe '#example_pending' do
|
|
261
|
+
it 'writes and flushes a yellow ?' do
|
|
262
|
+
formatter.example_pending(double('notification'))
|
|
263
|
+
expect(output.string).to include('?')
|
|
264
|
+
end
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
describe '#dump_failures' do
|
|
268
|
+
it 'dumps a yaml file of the failures into the parallel results dir' do
|
|
269
|
+
tempdir = Dir.mktmpdir
|
|
270
|
+
allow(RSpec.configuration).to receive(:onceover_tempdir).and_return(tempdir)
|
|
271
|
+
|
|
272
|
+
notification = double(
|
|
273
|
+
'notification',
|
|
274
|
+
failed_examples: [failure_double(role: 'role::foo', factset: 'using fact set centos-7-x86_64', raw_error: 'boom')]
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
formatter.dump_failures(notification)
|
|
278
|
+
|
|
279
|
+
files = Dir["#{tempdir}/parallel/*.yaml"]
|
|
280
|
+
expect(files.size).to eq(1)
|
|
281
|
+
expect(YAML.load_file(files.first)).to have_key('role::foo')
|
|
282
|
+
|
|
283
|
+
FileUtils.remove_entry(tempdir)
|
|
284
|
+
end
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
describe '#output_results' do
|
|
288
|
+
before do
|
|
289
|
+
allow(RSpec.configuration).to receive(:onceover_tempdir).and_return('/tmp/xyz/.onceover')
|
|
290
|
+
allow(RSpec.configuration).to receive(:onceover_root).and_return('/tmp/xyz')
|
|
291
|
+
allow(RSpec.configuration).to receive(:onceover_environmentpath).and_return('etc/puppetlabs/code/environments')
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
it 'merges all yaml result files, renders them, and deletes the source files' do
|
|
295
|
+
directory = Dir.mktmpdir
|
|
296
|
+
File.write(File.join(directory, 'results-1.yaml'), { 'role::foo' => [{ text: 'boom one' }] }.to_yaml)
|
|
297
|
+
File.write(File.join(directory, 'results-2.yaml'), { 'role::bar' => [{ text: 'boom two' }] }.to_yaml)
|
|
298
|
+
|
|
299
|
+
formatter.output_results(directory)
|
|
300
|
+
|
|
301
|
+
expect(output.string).to include('role::foo')
|
|
302
|
+
expect(output.string).to include('role::bar')
|
|
303
|
+
expect(Dir["#{directory}/*.yaml"]).to be_empty
|
|
304
|
+
|
|
305
|
+
FileUtils.remove_entry(directory)
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
it 'merges values when the same role appears in multiple files' do
|
|
309
|
+
directory = Dir.mktmpdir
|
|
310
|
+
File.write(File.join(directory, 'results-1.yaml'), { 'role::foo' => [{ text: 'boom one' }] }.to_yaml)
|
|
311
|
+
File.write(File.join(directory, 'results-2.yaml'), { 'role::foo' => [{ text: 'boom two' }] }.to_yaml)
|
|
312
|
+
|
|
313
|
+
formatter.output_results(directory)
|
|
314
|
+
|
|
315
|
+
expect(output.string).to include('role::foo')
|
|
316
|
+
|
|
317
|
+
FileUtils.remove_entry(directory)
|
|
318
|
+
end
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
describe FailureCollector do
|
|
323
|
+
let(:tempdir) { Dir.mktmpdir }
|
|
324
|
+
|
|
325
|
+
before do
|
|
326
|
+
allow(RSpec.configuration).to receive(:onceover_tempdir).and_return(tempdir)
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
after { FileUtils.rm_rf(tempdir) }
|
|
330
|
+
|
|
331
|
+
describe '#initialize' do
|
|
332
|
+
it 'touches a failures.out file in the onceover tempdir' do
|
|
333
|
+
described_class.new(StringIO.new)
|
|
334
|
+
expect(File.exist?(File.join(tempdir, 'failures.out'))).to be true
|
|
335
|
+
end
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
describe '#dump_failures' do
|
|
339
|
+
it 'appends details of each failed example to failures.out' do
|
|
340
|
+
collector = described_class.new(StringIO.new)
|
|
341
|
+
|
|
342
|
+
fe = double(
|
|
343
|
+
'failed_example',
|
|
344
|
+
metadata: {
|
|
345
|
+
description: 'does a thing',
|
|
346
|
+
execution_result: double('execution_result', exception: RuntimeError.new('kaboom')),
|
|
347
|
+
file_path: '/spec/foo_spec.rb',
|
|
348
|
+
line_number: 12
|
|
349
|
+
}
|
|
350
|
+
)
|
|
351
|
+
failures = double('failures', failed_examples: [fe])
|
|
352
|
+
|
|
353
|
+
collector.dump_failures(failures)
|
|
354
|
+
|
|
355
|
+
contents = File.read(File.join(tempdir, 'failures.out'))
|
|
356
|
+
expect(contents).to include('does a thing')
|
|
357
|
+
expect(contents).to include('kaboom')
|
|
358
|
+
expect(contents).to include('/spec/foo_spec.rb:12')
|
|
359
|
+
end
|
|
360
|
+
end
|
|
361
|
+
end
|