puppetlabs_spec_helper 2.6.2 → 2.7.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -1
- data/README.md +52 -5
- data/lib/puppetlabs_spec_helper/module_spec_helper.rb +6 -1
- data/lib/puppetlabs_spec_helper/puppet_spec_helper.rb +21 -6
- data/lib/puppetlabs_spec_helper/rake_tasks.rb +3 -416
- data/lib/puppetlabs_spec_helper/tasks/beaker.rb +111 -0
- data/lib/puppetlabs_spec_helper/tasks/fixtures.rb +328 -0
- data/lib/puppetlabs_spec_helper/version.rb +1 -1
- data/puppetlabs_spec_helper.gemspec +1 -0
- metadata +7 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d87d6131bfee20ef40887c452db37042acdab37d
|
|
4
|
+
data.tar.gz: a327772c292504414a79d4fd3784ff82348cad4a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6abed6f18fb005b07a38e19c0646716216058d88f425ea1659fd8453ac46bb17cb3135059f4f9deb2f7542609e8348e19121df1d74dc395bfaa94c9a9ec69fd8
|
|
7
|
+
data.tar.gz: c656294475da31a64af15631968a513438291e4f1d1b0e8e3e85d60cb65029ffcfdf63a793d1f2a0982c02706b6f887ed7a0c69d1f30da9d0d7d04d4acdcfb8d
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
All notable changes to this project will be documented in this file.
|
|
3
3
|
This project adheres to [Semantic Versioning](http://semver.org/).
|
|
4
4
|
|
|
5
|
+
## [2.7.0]
|
|
6
|
+
### Summary
|
|
7
|
+
Feature release to begin moving away from mocha as a testing (specifically, mocking) framework for modules.
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- spec/plans/**/*_spec.rb to spec discovery pattern
|
|
11
|
+
- [mocha as default](README.md#mock_with) test framework unless explicitly set by a module
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
- parsing for test tiers in beaker rake task
|
|
15
|
+
- module_spec_helper compatibility with mocha 1.5.0
|
|
16
|
+
|
|
5
17
|
## [2.6.2]
|
|
6
18
|
### Summary
|
|
7
19
|
A bugfix release to remove dependency on GettextSetup.initialize() in the Rake tasks.
|
|
@@ -430,7 +442,8 @@ compatible yet.
|
|
|
430
442
|
### Added
|
|
431
443
|
* Initial release
|
|
432
444
|
|
|
433
|
-
[unreleased]: https://github.com/puppetlabs/puppetlabs_spec_helper/compare/v2.
|
|
445
|
+
[unreleased]: https://github.com/puppetlabs/puppetlabs_spec_helper/compare/v2.7.0...master
|
|
446
|
+
[2.7.0]: https://github.com/puppetlabs/puppetlabs_spec_helper/compare/v2.6.2...v2.7.0
|
|
434
447
|
[2.6.2]: https://github.com/puppetlabs/puppetlabs_spec_helper/compare/v2.6.1...v2.6.2
|
|
435
448
|
[2.6.1]: https://github.com/puppetlabs/puppetlabs_spec_helper/compare/v2.5.1...v2.6.1
|
|
436
449
|
[2.5.1]: https://github.com/puppetlabs/puppetlabs_spec_helper/compare/v2.5.0...v2.5.1
|
data/README.md
CHANGED
|
@@ -345,14 +345,14 @@ remembering to duplicate any existing environment variables:
|
|
|
345
345
|
env:
|
|
346
346
|
- FUTURE_PARSER=yes CI_NODE_TOTAL=2 CI_NODE_INDEX=1
|
|
347
347
|
- FUTURE_PARSER=yes CI_NODE_TOTAL=2 CI_NODE_INDEX=2
|
|
348
|
-
|
|
348
|
+
|
|
349
349
|
#### Running tests tagged with test tiers
|
|
350
|
-
To run tests tagged with risk levels set the ``TEST_TIERS`` environment variable to a comma-separated list of
|
|
350
|
+
To run tests tagged with risk levels set the ``TEST_TIERS`` environment variable to a comma-separated list of
|
|
351
351
|
the appropriate tiers.
|
|
352
352
|
|
|
353
|
-
For example: to run tests marked ``tier_high => true`` and ``tier_medium => true`` in the same test run set the
|
|
353
|
+
For example: to run tests marked ``tier_high => true`` and ``tier_medium => true`` in the same test run set the
|
|
354
354
|
environment variable``TEST_TIERS=high,medium``
|
|
355
|
-
|
|
355
|
+
|
|
356
356
|
Note, if the ``TEST_TIERS`` environment variable is set to empty string or nil, all tiers will be executed.
|
|
357
357
|
|
|
358
358
|
|
|
@@ -451,7 +451,7 @@ This is related to a registry security setting requiring elevated privileges to
|
|
|
451
451
|
|
|
452
452
|
Currently, there are two known approaches to get around this problem.
|
|
453
453
|
|
|
454
|
-
- run your windows shell (cmd) as an Administrator
|
|
454
|
+
- run your windows shell (cmd) as an Administrator
|
|
455
455
|
or
|
|
456
456
|
- modify the registry entry settings to allow symbolic links to be created.
|
|
457
457
|
|
|
@@ -463,5 +463,52 @@ The following links may give you some insight into why...
|
|
|
463
463
|
|
|
464
464
|
[Microsoft TechNet](https://technet.microsoft.com/en-us/library/cc754077.aspx)
|
|
465
465
|
|
|
466
|
+
mock_with
|
|
467
|
+
=========
|
|
468
|
+
|
|
469
|
+
There are two major mocking frameworks in modules test suites today: [mocha](https://rubygems.org/gems/mocha) and [rspec-mocks](https://rubygems.org/gems/rspec-mocks). It is recommended to choose rspec-mocks explicitely by specifying `mock_with` either in your `spec_helper.rb` like so:
|
|
470
|
+
|
|
471
|
+
```
|
|
472
|
+
RSpec.configure do |c|
|
|
473
|
+
c.mock_with :rspec
|
|
474
|
+
end
|
|
475
|
+
require 'puppetlabs_spec_helper/module_spec_helper'
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
or by using the PDK's [`mock_with` option in `.sync.yml`](https://github.com/puppetlabs/pdk-templates#specspec_helperrb) and `pdk update`.
|
|
479
|
+
|
|
480
|
+
You can also continue to use mocha by explicitly specifying `:mocha`, following the [mocha documentation](http://gofreerange.com/mocha/docs/).
|
|
481
|
+
|
|
482
|
+
Migration
|
|
483
|
+
---------
|
|
484
|
+
|
|
485
|
+
To migrate from mocha to rspec-mocks, in many simple cases the following two kinds of changes are all you need:
|
|
486
|
+
|
|
487
|
+
Translate all stubs:
|
|
488
|
+
```
|
|
489
|
+
context.stubs(:some_method).with(arguments).returns('value')
|
|
490
|
+
```
|
|
491
|
+
to this:
|
|
492
|
+
```
|
|
493
|
+
allow(context).to receive(:some_method).with(arguments).and_returns('value')
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
Translate all expectations:
|
|
497
|
+
```
|
|
498
|
+
context.expects(:some_method).with(arguments).returns('value')
|
|
499
|
+
```
|
|
500
|
+
to this:
|
|
501
|
+
```
|
|
502
|
+
expect(context).to receive(:some_method).with(arguments).and_returns('value')
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
Rationale
|
|
506
|
+
---------
|
|
507
|
+
|
|
508
|
+
* As a part of the RSpec project, rspec-mocks integration is better.
|
|
509
|
+
* mocha is extending base ruby objects with its `stubs`, and `expects` methods, polluting the global namespace, with a potential for subtle and gnarly errors.
|
|
510
|
+
* Currently both rspec-mocks and mocha get loaded, leading to test suites that use both.
|
|
511
|
+
* puppetlabs_spec_helper loads and configures mocha unconditionally, causing friction when a different mocking framework is wanted.
|
|
512
|
+
* mocha is an additional dependency to carry.
|
|
466
513
|
|
|
467
514
|
EOF
|
|
@@ -26,7 +26,12 @@ RSpec.configure do |c|
|
|
|
26
26
|
c.parser = 'future' if ENV['FUTURE_PARSER'] == 'yes'
|
|
27
27
|
|
|
28
28
|
c.before :each do
|
|
29
|
-
|
|
29
|
+
if c.mock_framework.framework_name == :rspec
|
|
30
|
+
allow(Puppet.features).to receive(:root?).and_return(true)
|
|
31
|
+
else
|
|
32
|
+
Puppet.features.stubs(:root?).returns(true)
|
|
33
|
+
end
|
|
34
|
+
|
|
30
35
|
# stringify_facts and trusted_node_data were removed in puppet4
|
|
31
36
|
if Puppet.version.to_f < 4.0
|
|
32
37
|
Puppet.settings[:stringify_facts] = false if ENV['STRINGIFY_FACTS'] == 'no'
|
|
@@ -3,12 +3,21 @@ require 'puppetlabs_spec_helper/puppetlabs_spec_helper'
|
|
|
3
3
|
# Don't want puppet getting the command line arguments for rake or autotest
|
|
4
4
|
ARGV.clear
|
|
5
5
|
|
|
6
|
-
# This is needed because we're using mocha with rspec instead of Test::Unit or MiniTest
|
|
7
|
-
ENV['MOCHA_OPTIONS']='skip_integration'
|
|
8
|
-
|
|
9
6
|
require 'puppet'
|
|
10
7
|
require 'rspec/expectations'
|
|
11
|
-
|
|
8
|
+
|
|
9
|
+
# Detect whether the module is overriding the choice of mocking framework
|
|
10
|
+
# @mock_framework is used since more than seven years, and we need to avoid
|
|
11
|
+
# `mock_framework`'s autoloading to distinguish between the default, and
|
|
12
|
+
# the module's choice.
|
|
13
|
+
# See also below in RSpec.configure
|
|
14
|
+
if RSpec.configuration.instance_variable_get(:@mock_framework).nil?
|
|
15
|
+
# This is needed because we're using mocha with rspec instead of Test::Unit or MiniTest
|
|
16
|
+
ENV['MOCHA_OPTIONS']='skip_integration'
|
|
17
|
+
|
|
18
|
+
# Current versions of RSpec already load this for us, but who knows what's used out there?
|
|
19
|
+
require 'mocha/api'
|
|
20
|
+
end
|
|
12
21
|
|
|
13
22
|
require 'pathname'
|
|
14
23
|
require 'tmpdir'
|
|
@@ -118,8 +127,14 @@ end
|
|
|
118
127
|
|
|
119
128
|
# And here is where we do the main rspec configuration / setup.
|
|
120
129
|
RSpec.configure do |config|
|
|
121
|
-
#
|
|
122
|
-
|
|
130
|
+
# Detect whether the module is overriding the choice of mocking framework
|
|
131
|
+
# @mock_framework is used since more than seven years, and we need to avoid
|
|
132
|
+
# `mock_framework`'s autoloading to distinguish between the default, and
|
|
133
|
+
# the module's choice.
|
|
134
|
+
if config.instance_variable_get(:@mock_framework).nil?
|
|
135
|
+
RSpec.warn_deprecation('puppetlabs_spec_helper: defaults `mock_with` to `:mocha`. See https://github.com/puppetlabs/puppetlabs_spec_helper#mock_with to choose a sensible value for you')
|
|
136
|
+
config.mock_with :mocha
|
|
137
|
+
end
|
|
123
138
|
|
|
124
139
|
# determine whether we can use the new API or not, and call the appropriate initializer method.
|
|
125
140
|
if (defined?(Puppet::Test::TestHelper))
|
|
@@ -2,9 +2,10 @@ require 'fileutils'
|
|
|
2
2
|
require 'rake'
|
|
3
3
|
require 'rspec/core/rake_task'
|
|
4
4
|
require 'tmpdir'
|
|
5
|
-
require 'yaml'
|
|
6
5
|
require 'pathname'
|
|
7
6
|
require 'puppetlabs_spec_helper/version'
|
|
7
|
+
require 'puppetlabs_spec_helper/tasks/beaker'
|
|
8
|
+
require 'puppetlabs_spec_helper/tasks/fixtures'
|
|
8
9
|
|
|
9
10
|
# optional gems
|
|
10
11
|
begin
|
|
@@ -21,10 +22,9 @@ rescue LoadError
|
|
|
21
22
|
# ignore
|
|
22
23
|
end
|
|
23
24
|
|
|
24
|
-
|
|
25
25
|
task :default => [:help]
|
|
26
26
|
|
|
27
|
-
pattern = 'spec/{aliases,classes,defines,unit,functions,hosts,integration,type_aliases,types}/**/*_spec.rb'
|
|
27
|
+
pattern = 'spec/{aliases,classes,defines,unit,functions,hosts,integration,plans,type_aliases,types}/**/*_spec.rb'
|
|
28
28
|
|
|
29
29
|
RSpec::Core::RakeTask.new(:spec_standalone) do |t, args|
|
|
30
30
|
t.rspec_opts = ['--color']
|
|
@@ -55,387 +55,6 @@ RSpec::Core::RakeTask.new(:spec_list_json) do |t|
|
|
|
55
55
|
t.pattern = pattern
|
|
56
56
|
end
|
|
57
57
|
|
|
58
|
-
desc "Run beaker acceptance tests"
|
|
59
|
-
RSpec::Core::RakeTask.new(:beaker) do |t|
|
|
60
|
-
t.rspec_opts = ['--color']
|
|
61
|
-
t.pattern = 'spec/acceptance'
|
|
62
|
-
# TEST_TIERS env variable is a comma separated list of tiers to run. e.g. low, medium, high
|
|
63
|
-
if ENV['TEST_TIERS']
|
|
64
|
-
tiers = '--tag '
|
|
65
|
-
test_tiers = ENV['TEST_TIERS'].split(',')
|
|
66
|
-
raise 'TEST_TIERS env variable must have at least 1 tier specified. low, medium or high (comma separated).' if test_tiers.count == 0
|
|
67
|
-
test_tiers.each do |tier|
|
|
68
|
-
tier_to_add = tier.strip
|
|
69
|
-
raise "#{tier_to_add} not a valid test tier." unless %w(low medium high).include?(tier_to_add)
|
|
70
|
-
tiers += "tier_#{tier_to_add},"
|
|
71
|
-
end
|
|
72
|
-
tiers = tiers.chomp(',')
|
|
73
|
-
t.rspec_opts.push(tiers)
|
|
74
|
-
else
|
|
75
|
-
puts 'TEST_TIERS env variable not defined. Defaulting to run all tests.'
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
module PuppetlabsSpecHelper::RakeTasks
|
|
80
|
-
# This is a helper for the self-symlink entry of fixtures.yml
|
|
81
|
-
def source_dir
|
|
82
|
-
Dir.pwd
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
# cache the repositories and return a hash object
|
|
86
|
-
def repositories
|
|
87
|
-
unless @repositories
|
|
88
|
-
@repositories = fixtures('repositories')
|
|
89
|
-
end
|
|
90
|
-
@repositories
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
# get the array of Beaker set names
|
|
94
|
-
# @return [Array<String>]
|
|
95
|
-
def beaker_node_sets
|
|
96
|
-
return @beaker_nodes if @beaker_nodes
|
|
97
|
-
@beaker_nodes = Dir['spec/acceptance/nodesets/*.yml'].sort.map do |node_set|
|
|
98
|
-
node_set.slice!('.yml')
|
|
99
|
-
File.basename(node_set)
|
|
100
|
-
end
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
# Use "vagrant ssh" to login to the given node in the node set
|
|
104
|
-
# @param set [String] The name of the node set (yml file)
|
|
105
|
-
# @param node [String] The name of the node in the set. For multi-node sets.
|
|
106
|
-
def vagrant_ssh(set, node = nil)
|
|
107
|
-
vagrant_yml_dir = File.join '.vagrant', 'beaker_vagrant_files', "#{set}.yml"
|
|
108
|
-
vagrant_file = File.join vagrant_yml_dir, 'Vagrantfile'
|
|
109
|
-
unless File.file? vagrant_file
|
|
110
|
-
puts "There is no Vagrantfile at: '#{vagrant_file}'. Perhaps, the node is not created or is destroyed."
|
|
111
|
-
exit 1
|
|
112
|
-
end
|
|
113
|
-
Dir.chdir(vagrant_yml_dir) do
|
|
114
|
-
command = 'vagrant ssh'
|
|
115
|
-
command += " #{node}" if node
|
|
116
|
-
# Vagrant is not distributed as a normal gem
|
|
117
|
-
# and we should protect it from the current Ruby environment
|
|
118
|
-
env = {
|
|
119
|
-
'RUBYLIB' => nil,
|
|
120
|
-
'GEM_PATH' => nil,
|
|
121
|
-
'BUNDLE_BIN_PATH' => nil,
|
|
122
|
-
}
|
|
123
|
-
system env, command
|
|
124
|
-
end
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
def auto_symlink
|
|
128
|
-
{ File.basename(Dir.pwd).split('-').last => '#{source_dir}' }
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
def fixtures(category)
|
|
132
|
-
if ENV['FIXTURES_YML']
|
|
133
|
-
fixtures_yaml = ENV['FIXTURES_YML']
|
|
134
|
-
elsif File.exists?('.fixtures.yml')
|
|
135
|
-
fixtures_yaml = '.fixtures.yml'
|
|
136
|
-
elsif File.exists?('.fixtures.yaml')
|
|
137
|
-
fixtures_yaml = '.fixtures.yaml'
|
|
138
|
-
else
|
|
139
|
-
fixtures_yaml = false
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
begin
|
|
143
|
-
if fixtures_yaml
|
|
144
|
-
fixtures = YAML.load_file(fixtures_yaml) || { 'fixtures' => {} }
|
|
145
|
-
else
|
|
146
|
-
fixtures = { 'fixtures' => {} }
|
|
147
|
-
end
|
|
148
|
-
rescue Errno::ENOENT
|
|
149
|
-
fail("Fixtures file not found: '#{fixtures_yaml}'")
|
|
150
|
-
rescue Psych::SyntaxError => e
|
|
151
|
-
fail("Found malformed YAML in '#{fixtures_yaml}' on line #{e.line} column #{e.column}: #{e.problem}")
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
unless fixtures.include?('fixtures')
|
|
155
|
-
# File is non-empty, but does not specify fixtures
|
|
156
|
-
fail("No 'fixtures' entries found in '#{fixtures_yaml}'; required")
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
if fixtures.include? 'defaults'
|
|
160
|
-
fixture_defaults = fixtures['defaults']
|
|
161
|
-
else
|
|
162
|
-
fixture_defaults = {}
|
|
163
|
-
end
|
|
164
|
-
|
|
165
|
-
fixtures = fixtures['fixtures']
|
|
166
|
-
|
|
167
|
-
if fixtures['symlinks'].nil?
|
|
168
|
-
fixtures['symlinks'] = auto_symlink
|
|
169
|
-
end
|
|
170
|
-
|
|
171
|
-
result = {}
|
|
172
|
-
if fixtures.include? category and fixtures[category] != nil
|
|
173
|
-
|
|
174
|
-
defaults = { "target" => "spec/fixtures/modules" }
|
|
175
|
-
|
|
176
|
-
# load defaults from the `.fixtures.yml` `defaults` section
|
|
177
|
-
# for the requested category and merge them into my defaults
|
|
178
|
-
if fixture_defaults.include? category
|
|
179
|
-
defaults = defaults.merge(fixture_defaults[category])
|
|
180
|
-
end
|
|
181
|
-
|
|
182
|
-
fixtures[category].each do |fixture, opts|
|
|
183
|
-
# convert a simple string fixture to a hash, by
|
|
184
|
-
# using the string fixture as the `repo` option of the hash.
|
|
185
|
-
if opts.instance_of?(String)
|
|
186
|
-
opts = { "repo" => opts }
|
|
187
|
-
end
|
|
188
|
-
# there should be a warning or something if it's not a hash...
|
|
189
|
-
if opts.instance_of?(Hash)
|
|
190
|
-
# merge our options into the defaults to get the
|
|
191
|
-
# final option list
|
|
192
|
-
opts = defaults.merge(opts)
|
|
193
|
-
|
|
194
|
-
real_target = eval('"'+opts["target"]+'"')
|
|
195
|
-
real_source = eval('"'+opts["repo"]+'"')
|
|
196
|
-
|
|
197
|
-
result[real_source] = { "target" => File.join(real_target,fixture), "ref" => opts["ref"], "branch" => opts["branch"], "scm" => opts["scm"], "flags" => opts["flags"], "subdir" => opts["subdir"]}
|
|
198
|
-
end
|
|
199
|
-
end
|
|
200
|
-
end
|
|
201
|
-
return result
|
|
202
|
-
end
|
|
203
|
-
|
|
204
|
-
def clone_repo(scm, remote, target, subdir=nil, ref=nil, branch=nil, flags = nil)
|
|
205
|
-
args = []
|
|
206
|
-
case scm
|
|
207
|
-
when 'hg'
|
|
208
|
-
args.push('clone')
|
|
209
|
-
args.push('-b', branch) if branch
|
|
210
|
-
args.push(flags) if flags
|
|
211
|
-
args.push(remote, target)
|
|
212
|
-
when 'git'
|
|
213
|
-
args.push('clone')
|
|
214
|
-
args.push('--depth 1') unless ref
|
|
215
|
-
args.push('-b', branch) if branch
|
|
216
|
-
args.push(flags) if flags
|
|
217
|
-
args.push(remote, target)
|
|
218
|
-
else
|
|
219
|
-
fail "Unfortunately #{scm} is not supported yet"
|
|
220
|
-
end
|
|
221
|
-
result = system("#{scm} #{args.flatten.join ' '}")
|
|
222
|
-
unless File::exists?(target)
|
|
223
|
-
fail "Failed to clone #{scm} repository #{remote} into #{target}"
|
|
224
|
-
end
|
|
225
|
-
result
|
|
226
|
-
end
|
|
227
|
-
|
|
228
|
-
def revision(scm, target, ref)
|
|
229
|
-
args = []
|
|
230
|
-
case scm
|
|
231
|
-
when 'hg'
|
|
232
|
-
args.push('update', '--clean', '-r', ref)
|
|
233
|
-
when 'git'
|
|
234
|
-
args.push('reset', '--hard', ref)
|
|
235
|
-
else
|
|
236
|
-
fail "Unfortunately #{scm} is not supported yet"
|
|
237
|
-
end
|
|
238
|
-
system("cd #{target} && #{scm} #{args.flatten.join ' '}")
|
|
239
|
-
end
|
|
240
|
-
|
|
241
|
-
def remove_subdirectory(target, subdir)
|
|
242
|
-
unless subdir.nil?
|
|
243
|
-
Dir.mktmpdir {|tmpdir|
|
|
244
|
-
FileUtils.mv(Dir.glob("#{target}/#{subdir}/{.[^\.]*,*}"), tmpdir)
|
|
245
|
-
FileUtils.rm_rf("#{target}/#{subdir}")
|
|
246
|
-
FileUtils.mv(Dir.glob("#{tmpdir}/{.[^\.]*,*}"), "#{target}")
|
|
247
|
-
}
|
|
248
|
-
end
|
|
249
|
-
end
|
|
250
|
-
|
|
251
|
-
# creates a logger so we can log events with certain levels
|
|
252
|
-
def logger
|
|
253
|
-
unless @logger
|
|
254
|
-
require 'logger'
|
|
255
|
-
if ENV['ENABLE_LOGGER']
|
|
256
|
-
level = Logger::DEBUG
|
|
257
|
-
else
|
|
258
|
-
level = Logger::INFO
|
|
259
|
-
end
|
|
260
|
-
@logger = Logger.new(STDERR)
|
|
261
|
-
@logger.level = level
|
|
262
|
-
end
|
|
263
|
-
@logger
|
|
264
|
-
end
|
|
265
|
-
|
|
266
|
-
def module_working_directory
|
|
267
|
-
# The problem with the relative path is that PMT doesn't expand the path properly and so passing in a relative path here
|
|
268
|
-
# becomes something like C:\somewhere\backslashes/spec/fixtures/work-dir on Windows, and then PMT barfs itself.
|
|
269
|
-
# This has been reported as https://tickets.puppetlabs.com/browse/PUP-4884
|
|
270
|
-
File.expand_path(ENV['MODULE_WORKING_DIR'] ? ENV['MODULE_WORKING_DIR'] : 'spec/fixtures/work-dir')
|
|
271
|
-
end
|
|
272
|
-
|
|
273
|
-
# returns the current thread count that is currently active
|
|
274
|
-
# a status of false or nil means the thread completed
|
|
275
|
-
# so when anything else we count that as a active thread
|
|
276
|
-
def current_thread_count(items)
|
|
277
|
-
active_threads = items.find_all do |item, opts|
|
|
278
|
-
if opts[:thread]
|
|
279
|
-
opts[:thread].status
|
|
280
|
-
else
|
|
281
|
-
false
|
|
282
|
-
end
|
|
283
|
-
end
|
|
284
|
-
logger.debug "Current thread count #{active_threads.count}"
|
|
285
|
-
active_threads.count
|
|
286
|
-
end
|
|
287
|
-
|
|
288
|
-
# returns the max_thread_count
|
|
289
|
-
# because we may want to limit ssh or https connections
|
|
290
|
-
def max_thread_limit
|
|
291
|
-
unless @max_thread_limit
|
|
292
|
-
# the default thread count is 10 but can be
|
|
293
|
-
# raised by using environment variable MAX_FIXTURE_THREAD_COUNT
|
|
294
|
-
if ENV['MAX_FIXTURE_THREAD_COUNT'].to_i > 0
|
|
295
|
-
@max_thread_limit = ENV['MAX_FIXTURE_THREAD_COUNT'].to_i
|
|
296
|
-
else
|
|
297
|
-
@max_thread_limit = 10 # the default
|
|
298
|
-
end
|
|
299
|
-
end
|
|
300
|
-
@max_thread_limit
|
|
301
|
-
end
|
|
302
|
-
|
|
303
|
-
def check_directory_for_symlinks(dir='.')
|
|
304
|
-
dir = Pathname.new(dir) unless dir.is_a?(Pathname)
|
|
305
|
-
results = []
|
|
306
|
-
|
|
307
|
-
dir.each_child(true) do |child|
|
|
308
|
-
if child.symlink?
|
|
309
|
-
results << child
|
|
310
|
-
elsif child.directory? && child.basename.to_s != '.git'
|
|
311
|
-
results.concat(check_directory_for_symlinks(child))
|
|
312
|
-
end
|
|
313
|
-
end
|
|
314
|
-
|
|
315
|
-
results
|
|
316
|
-
end
|
|
317
|
-
end
|
|
318
|
-
include PuppetlabsSpecHelper::RakeTasks
|
|
319
|
-
|
|
320
|
-
desc "Create the fixtures directory"
|
|
321
|
-
task :spec_prep do
|
|
322
|
-
# Ruby only sets File::ALT_SEPARATOR on Windows and Rubys standard library
|
|
323
|
-
# uses this to check for Windows
|
|
324
|
-
is_windows = !!File::ALT_SEPARATOR
|
|
325
|
-
if is_windows
|
|
326
|
-
begin
|
|
327
|
-
require 'win32/dir'
|
|
328
|
-
rescue LoadError
|
|
329
|
-
$stderr.puts "win32-dir gem not installed, falling back to executing mklink directly"
|
|
330
|
-
end
|
|
331
|
-
end
|
|
332
|
-
|
|
333
|
-
# git has a race condition creating that directory, that would lead to aborted clone operations
|
|
334
|
-
FileUtils::mkdir_p("spec/fixtures/modules")
|
|
335
|
-
|
|
336
|
-
repositories.each do |remote, opts|
|
|
337
|
-
scm = 'git'
|
|
338
|
-
target = opts["target"]
|
|
339
|
-
subdir = opts["subdir"]
|
|
340
|
-
ref = opts["ref"]
|
|
341
|
-
scm = opts["scm"] if opts["scm"]
|
|
342
|
-
branch = opts["branch"] if opts["branch"]
|
|
343
|
-
flags = opts["flags"]
|
|
344
|
-
# get the current active threads that are alive
|
|
345
|
-
count = current_thread_count(repositories)
|
|
346
|
-
if count < max_thread_limit
|
|
347
|
-
logger.debug "New Thread started for #{remote}"
|
|
348
|
-
# start up a new thread and store it in the opts hash
|
|
349
|
-
opts[:thread] = Thread.new do
|
|
350
|
-
clone_repo(scm, remote, target, subdir, ref, branch, flags)
|
|
351
|
-
revision(scm, target, ref) if ref
|
|
352
|
-
remove_subdirectory(target, subdir) if subdir
|
|
353
|
-
end
|
|
354
|
-
else
|
|
355
|
-
# the last thread started should be the longest wait
|
|
356
|
-
item, item_opts = repositories.find_all {|i,o| o.has_key?(:thread)}.last
|
|
357
|
-
logger.debug "Waiting on #{item}"
|
|
358
|
-
item_opts[:thread].join # wait for the thread to finish
|
|
359
|
-
# now that we waited lets try again
|
|
360
|
-
redo
|
|
361
|
-
end
|
|
362
|
-
end
|
|
363
|
-
|
|
364
|
-
# wait for all the threads to finish
|
|
365
|
-
repositories.each {|remote, opts| opts[:thread].join }
|
|
366
|
-
|
|
367
|
-
fixtures("symlinks").each do |target, link|
|
|
368
|
-
link = link['target']
|
|
369
|
-
unless File.symlink?(link)
|
|
370
|
-
logger.info("Creating symlink from #{link} to #{target}")
|
|
371
|
-
if is_windows
|
|
372
|
-
target = File.join(File.dirname(link), target) unless Pathname.new(target).absolute?
|
|
373
|
-
if Dir.respond_to?(:create_junction)
|
|
374
|
-
Dir.create_junction(link, target)
|
|
375
|
-
else
|
|
376
|
-
system("call mklink /J \"#{link.gsub('/', '\\')}\" \"#{target.gsub('/', '\\')}\"")
|
|
377
|
-
end
|
|
378
|
-
else
|
|
379
|
-
FileUtils::ln_sf(target, link)
|
|
380
|
-
end
|
|
381
|
-
end
|
|
382
|
-
end
|
|
383
|
-
|
|
384
|
-
fixtures("forge_modules").each do |remote, opts|
|
|
385
|
-
ref = ""
|
|
386
|
-
flags = ""
|
|
387
|
-
if opts.instance_of?(String)
|
|
388
|
-
target = opts
|
|
389
|
-
elsif opts.instance_of?(Hash)
|
|
390
|
-
target = opts["target"]
|
|
391
|
-
ref = " --version #{opts['ref']}" if not opts['ref'].nil?
|
|
392
|
-
flags = " #{opts['flags']}" if opts['flags']
|
|
393
|
-
end
|
|
394
|
-
next if File::exists?(target)
|
|
395
|
-
|
|
396
|
-
working_dir = module_working_directory
|
|
397
|
-
target_dir = File.expand_path('spec/fixtures/modules')
|
|
398
|
-
|
|
399
|
-
command = "puppet module install" + ref + flags + \
|
|
400
|
-
" --ignore-dependencies" \
|
|
401
|
-
" --force" \
|
|
402
|
-
" --module_working_dir \"#{working_dir}\"" \
|
|
403
|
-
" --target-dir \"#{target_dir}\" \"#{remote}\""
|
|
404
|
-
|
|
405
|
-
unless system(command)
|
|
406
|
-
fail "Failed to install module #{remote} to #{target_dir}"
|
|
407
|
-
end
|
|
408
|
-
end
|
|
409
|
-
|
|
410
|
-
FileUtils::mkdir_p("spec/fixtures/manifests")
|
|
411
|
-
FileUtils::touch("spec/fixtures/manifests/site.pp")
|
|
412
|
-
end
|
|
413
|
-
|
|
414
|
-
desc "Clean up the fixtures directory"
|
|
415
|
-
task :spec_clean do
|
|
416
|
-
fixtures("repositories").each do |remote, opts|
|
|
417
|
-
target = opts["target"]
|
|
418
|
-
FileUtils::rm_rf(target)
|
|
419
|
-
end
|
|
420
|
-
|
|
421
|
-
fixtures("forge_modules").each do |remote, opts|
|
|
422
|
-
target = opts["target"]
|
|
423
|
-
FileUtils::rm_rf(target)
|
|
424
|
-
end
|
|
425
|
-
|
|
426
|
-
FileUtils::rm_rf(module_working_directory)
|
|
427
|
-
|
|
428
|
-
fixtures("symlinks").each do |source, opts|
|
|
429
|
-
target = opts["target"]
|
|
430
|
-
FileUtils::rm_f(target)
|
|
431
|
-
end
|
|
432
|
-
|
|
433
|
-
if File.zero?("spec/fixtures/manifests/site.pp")
|
|
434
|
-
FileUtils::rm_f("spec/fixtures/manifests/site.pp")
|
|
435
|
-
end
|
|
436
|
-
|
|
437
|
-
end
|
|
438
|
-
|
|
439
58
|
desc "Run spec tests and clean the fixtures directory if successful"
|
|
440
59
|
task :spec do |t, args|
|
|
441
60
|
begin
|
|
@@ -465,38 +84,6 @@ task :parallel_spec do
|
|
|
465
84
|
end
|
|
466
85
|
end
|
|
467
86
|
|
|
468
|
-
desc "List available beaker nodesets"
|
|
469
|
-
task 'beaker:sets' do
|
|
470
|
-
beaker_node_sets.each do |set|
|
|
471
|
-
puts set
|
|
472
|
-
end
|
|
473
|
-
end
|
|
474
|
-
|
|
475
|
-
# alias for compatibility
|
|
476
|
-
task 'beaker_nodes' => 'beaker:sets'
|
|
477
|
-
|
|
478
|
-
desc 'Try to use vagrant to login to the Beaker node'
|
|
479
|
-
task 'beaker:ssh', [:set, :node] do |_task, args|
|
|
480
|
-
set = args[:set] || ENV['BEAKER_set'] || ENV['RS_SET'] || 'default'
|
|
481
|
-
node = args[:node]
|
|
482
|
-
vagrant_ssh set, node
|
|
483
|
-
end
|
|
484
|
-
|
|
485
|
-
beaker_node_sets.each do |set|
|
|
486
|
-
desc "Run the Beaker acceptance tests for the node set '#{set}'"
|
|
487
|
-
task "beaker:#{set}" do
|
|
488
|
-
ENV['BEAKER_set'] = set
|
|
489
|
-
Rake::Task['beaker'].reenable
|
|
490
|
-
Rake::Task['beaker'].invoke
|
|
491
|
-
end
|
|
492
|
-
|
|
493
|
-
desc "Use vagrant to login to a node from the set '#{set}'"
|
|
494
|
-
task "beaker:ssh:#{set}", [:node] do |_task, args|
|
|
495
|
-
node = args[:node]
|
|
496
|
-
vagrant_ssh set, node
|
|
497
|
-
end
|
|
498
|
-
end
|
|
499
|
-
|
|
500
87
|
desc "Build puppet module package"
|
|
501
88
|
task :build do
|
|
502
89
|
# This will be deprecated once puppet-module is a face.
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
require 'rspec/core/rake_task'
|
|
2
|
+
|
|
3
|
+
module PuppetlabsSpecHelper; end
|
|
4
|
+
module PuppetlabsSpecHelper::Tasks; end
|
|
5
|
+
module PuppetlabsSpecHelper::Tasks::BeakerHelpers
|
|
6
|
+
# This is a helper for the self-symlink entry of fixtures.yml
|
|
7
|
+
def source_dir
|
|
8
|
+
Dir.pwd
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# cache the repositories and return a hash object
|
|
12
|
+
def repositories
|
|
13
|
+
unless @repositories
|
|
14
|
+
@repositories = fixtures('repositories')
|
|
15
|
+
end
|
|
16
|
+
@repositories
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# get the array of Beaker set names
|
|
20
|
+
# @return [Array<String>]
|
|
21
|
+
def beaker_node_sets
|
|
22
|
+
return @beaker_nodes if @beaker_nodes
|
|
23
|
+
@beaker_nodes = Dir['spec/acceptance/nodesets/*.yml'].sort.map do |node_set|
|
|
24
|
+
node_set.slice!('.yml')
|
|
25
|
+
File.basename(node_set)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Use "vagrant ssh" to login to the given node in the node set
|
|
30
|
+
# @param set [String] The name of the node set (yml file)
|
|
31
|
+
# @param node [String] The name of the node in the set. For multi-node sets.
|
|
32
|
+
def vagrant_ssh(set, node = nil)
|
|
33
|
+
vagrant_yml_dir = File.join '.vagrant', 'beaker_vagrant_files', "#{set}.yml"
|
|
34
|
+
vagrant_file = File.join vagrant_yml_dir, 'Vagrantfile'
|
|
35
|
+
unless File.file? vagrant_file
|
|
36
|
+
puts "There is no Vagrantfile at: '#{vagrant_file}'. Perhaps, the node is not created or is destroyed."
|
|
37
|
+
exit 1
|
|
38
|
+
end
|
|
39
|
+
Dir.chdir(vagrant_yml_dir) do
|
|
40
|
+
command = 'vagrant ssh'
|
|
41
|
+
command += " #{node}" if node
|
|
42
|
+
# Vagrant is not distributed as a normal gem
|
|
43
|
+
# and we should protect it from the current Ruby environment
|
|
44
|
+
env = {
|
|
45
|
+
'RUBYLIB' => nil,
|
|
46
|
+
'GEM_PATH' => nil,
|
|
47
|
+
'BUNDLE_BIN_PATH' => nil,
|
|
48
|
+
}
|
|
49
|
+
system env, command
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
include PuppetlabsSpecHelper::Tasks::BeakerHelpers
|
|
54
|
+
|
|
55
|
+
desc "Run beaker acceptance tests"
|
|
56
|
+
RSpec::Core::RakeTask.new(:beaker) do |t|
|
|
57
|
+
SetupBeaker.setup_beaker(t)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
class SetupBeaker
|
|
61
|
+
def self.setup_beaker(t)
|
|
62
|
+
t.rspec_opts = ['--color']
|
|
63
|
+
t.pattern = 'spec/acceptance'
|
|
64
|
+
# TEST_TIERS env variable is a comma separated list of tiers to run. e.g. low, medium, high
|
|
65
|
+
if ENV['TEST_TIERS']
|
|
66
|
+
test_tiers = ENV['TEST_TIERS'].split(',')
|
|
67
|
+
raise 'TEST_TIERS env variable must have at least 1 tier specified. low, medium or high (comma separated).' if test_tiers.count == 0
|
|
68
|
+
test_tiers.each do |tier|
|
|
69
|
+
tier_to_add = tier.strip.downcase
|
|
70
|
+
raise "#{tier_to_add} not a valid test tier." unless %w(low medium high).include?(tier_to_add)
|
|
71
|
+
tiers = "--tag tier_#{tier_to_add}"
|
|
72
|
+
t.rspec_opts.push(tiers)
|
|
73
|
+
end
|
|
74
|
+
else
|
|
75
|
+
puts 'TEST_TIERS env variable not defined. Defaulting to run all tests.'
|
|
76
|
+
end
|
|
77
|
+
return t
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
desc "List available beaker nodesets"
|
|
82
|
+
task 'beaker:sets' do
|
|
83
|
+
beaker_node_sets.each do |set|
|
|
84
|
+
puts set
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# alias for compatibility
|
|
89
|
+
task 'beaker_nodes' => 'beaker:sets'
|
|
90
|
+
|
|
91
|
+
desc 'Try to use vagrant to login to the Beaker node'
|
|
92
|
+
task 'beaker:ssh', [:set, :node] do |_task, args|
|
|
93
|
+
set = args[:set] || ENV['BEAKER_set'] || ENV['RS_SET'] || 'default'
|
|
94
|
+
node = args[:node]
|
|
95
|
+
vagrant_ssh set, node
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
beaker_node_sets.each do |set|
|
|
99
|
+
desc "Run the Beaker acceptance tests for the node set '#{set}'"
|
|
100
|
+
task "beaker:#{set}" do
|
|
101
|
+
ENV['BEAKER_set'] = set
|
|
102
|
+
Rake::Task['beaker'].reenable
|
|
103
|
+
Rake::Task['beaker'].invoke
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
desc "Use vagrant to login to a node from the set '#{set}'"
|
|
107
|
+
task "beaker:ssh:#{set}", [:node] do |_task, args|
|
|
108
|
+
node = args[:node]
|
|
109
|
+
vagrant_ssh set, node
|
|
110
|
+
end
|
|
111
|
+
end
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
require 'yaml'
|
|
2
|
+
|
|
3
|
+
module PuppetlabsSpecHelper; end
|
|
4
|
+
module PuppetlabsSpecHelper::Tasks; end
|
|
5
|
+
module PuppetlabsSpecHelper::Tasks::FixtureHelpers
|
|
6
|
+
# This is a helper for the self-symlink entry of fixtures.yml
|
|
7
|
+
def source_dir
|
|
8
|
+
Dir.pwd
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# cache the repositories and return a hash object
|
|
12
|
+
def repositories
|
|
13
|
+
unless @repositories
|
|
14
|
+
@repositories = fixtures('repositories')
|
|
15
|
+
end
|
|
16
|
+
@repositories
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def auto_symlink
|
|
20
|
+
{ File.basename(Dir.pwd).split('-').last => '#{source_dir}' }
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def fixtures(category)
|
|
24
|
+
if ENV['FIXTURES_YML']
|
|
25
|
+
fixtures_yaml = ENV['FIXTURES_YML']
|
|
26
|
+
elsif File.exists?('.fixtures.yml')
|
|
27
|
+
fixtures_yaml = '.fixtures.yml'
|
|
28
|
+
elsif File.exists?('.fixtures.yaml')
|
|
29
|
+
fixtures_yaml = '.fixtures.yaml'
|
|
30
|
+
else
|
|
31
|
+
fixtures_yaml = false
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
begin
|
|
35
|
+
if fixtures_yaml
|
|
36
|
+
fixtures = YAML.load_file(fixtures_yaml) || { 'fixtures' => {} }
|
|
37
|
+
else
|
|
38
|
+
fixtures = { 'fixtures' => {} }
|
|
39
|
+
end
|
|
40
|
+
rescue Errno::ENOENT
|
|
41
|
+
fail("Fixtures file not found: '#{fixtures_yaml}'")
|
|
42
|
+
rescue Psych::SyntaxError => e
|
|
43
|
+
fail("Found malformed YAML in '#{fixtures_yaml}' on line #{e.line} column #{e.column}: #{e.problem}")
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
unless fixtures.include?('fixtures')
|
|
47
|
+
# File is non-empty, but does not specify fixtures
|
|
48
|
+
fail("No 'fixtures' entries found in '#{fixtures_yaml}'; required")
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
if fixtures.include? 'defaults'
|
|
52
|
+
fixture_defaults = fixtures['defaults']
|
|
53
|
+
else
|
|
54
|
+
fixture_defaults = {}
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
fixtures = fixtures['fixtures']
|
|
58
|
+
|
|
59
|
+
if fixtures['symlinks'].nil?
|
|
60
|
+
fixtures['symlinks'] = auto_symlink
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
result = {}
|
|
64
|
+
if fixtures.include? category and fixtures[category] != nil
|
|
65
|
+
|
|
66
|
+
defaults = { "target" => "spec/fixtures/modules" }
|
|
67
|
+
|
|
68
|
+
# load defaults from the `.fixtures.yml` `defaults` section
|
|
69
|
+
# for the requested category and merge them into my defaults
|
|
70
|
+
if fixture_defaults.include? category
|
|
71
|
+
defaults = defaults.merge(fixture_defaults[category])
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
fixtures[category].each do |fixture, opts|
|
|
75
|
+
# convert a simple string fixture to a hash, by
|
|
76
|
+
# using the string fixture as the `repo` option of the hash.
|
|
77
|
+
if opts.instance_of?(String)
|
|
78
|
+
opts = { "repo" => opts }
|
|
79
|
+
end
|
|
80
|
+
# there should be a warning or something if it's not a hash...
|
|
81
|
+
if opts.instance_of?(Hash)
|
|
82
|
+
# merge our options into the defaults to get the
|
|
83
|
+
# final option list
|
|
84
|
+
opts = defaults.merge(opts)
|
|
85
|
+
|
|
86
|
+
real_target = eval('"'+opts["target"]+'"')
|
|
87
|
+
real_source = eval('"'+opts["repo"]+'"')
|
|
88
|
+
|
|
89
|
+
result[real_source] = { "target" => File.join(real_target,fixture), "ref" => opts["ref"], "branch" => opts["branch"], "scm" => opts["scm"], "flags" => opts["flags"], "subdir" => opts["subdir"]}
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
return result
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def clone_repo(scm, remote, target, subdir=nil, ref=nil, branch=nil, flags = nil)
|
|
97
|
+
args = []
|
|
98
|
+
case scm
|
|
99
|
+
when 'hg'
|
|
100
|
+
args.push('clone')
|
|
101
|
+
args.push('-b', branch) if branch
|
|
102
|
+
args.push(flags) if flags
|
|
103
|
+
args.push(remote, target)
|
|
104
|
+
when 'git'
|
|
105
|
+
args.push('clone')
|
|
106
|
+
args.push('--depth 1') unless ref
|
|
107
|
+
args.push('-b', branch) if branch
|
|
108
|
+
args.push(flags) if flags
|
|
109
|
+
args.push(remote, target)
|
|
110
|
+
else
|
|
111
|
+
fail "Unfortunately #{scm} is not supported yet"
|
|
112
|
+
end
|
|
113
|
+
result = system("#{scm} #{args.flatten.join ' '}")
|
|
114
|
+
unless File::exists?(target)
|
|
115
|
+
fail "Failed to clone #{scm} repository #{remote} into #{target}"
|
|
116
|
+
end
|
|
117
|
+
result
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def revision(scm, target, ref)
|
|
121
|
+
args = []
|
|
122
|
+
case scm
|
|
123
|
+
when 'hg'
|
|
124
|
+
args.push('update', '--clean', '-r', ref)
|
|
125
|
+
when 'git'
|
|
126
|
+
args.push('reset', '--hard', ref)
|
|
127
|
+
else
|
|
128
|
+
fail "Unfortunately #{scm} is not supported yet"
|
|
129
|
+
end
|
|
130
|
+
system("cd #{target} && #{scm} #{args.flatten.join ' '}")
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def remove_subdirectory(target, subdir)
|
|
134
|
+
unless subdir.nil?
|
|
135
|
+
Dir.mktmpdir {|tmpdir|
|
|
136
|
+
FileUtils.mv(Dir.glob("#{target}/#{subdir}/{.[^\.]*,*}"), tmpdir)
|
|
137
|
+
FileUtils.rm_rf("#{target}/#{subdir}")
|
|
138
|
+
FileUtils.mv(Dir.glob("#{tmpdir}/{.[^\.]*,*}"), "#{target}")
|
|
139
|
+
}
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# creates a logger so we can log events with certain levels
|
|
144
|
+
def logger
|
|
145
|
+
unless @logger
|
|
146
|
+
require 'logger'
|
|
147
|
+
if ENV['ENABLE_LOGGER']
|
|
148
|
+
level = Logger::DEBUG
|
|
149
|
+
else
|
|
150
|
+
level = Logger::INFO
|
|
151
|
+
end
|
|
152
|
+
@logger = Logger.new(STDERR)
|
|
153
|
+
@logger.level = level
|
|
154
|
+
end
|
|
155
|
+
@logger
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def module_working_directory
|
|
159
|
+
# The problem with the relative path is that PMT doesn't expand the path properly and so passing in a relative path here
|
|
160
|
+
# becomes something like C:\somewhere\backslashes/spec/fixtures/work-dir on Windows, and then PMT barfs itself.
|
|
161
|
+
# This has been reported as https://tickets.puppetlabs.com/browse/PUP-4884
|
|
162
|
+
File.expand_path(ENV['MODULE_WORKING_DIR'] ? ENV['MODULE_WORKING_DIR'] : 'spec/fixtures/work-dir')
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# returns the current thread count that is currently active
|
|
166
|
+
# a status of false or nil means the thread completed
|
|
167
|
+
# so when anything else we count that as a active thread
|
|
168
|
+
def current_thread_count(items)
|
|
169
|
+
active_threads = items.find_all do |item, opts|
|
|
170
|
+
if opts[:thread]
|
|
171
|
+
opts[:thread].status
|
|
172
|
+
else
|
|
173
|
+
false
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
logger.debug "Current thread count #{active_threads.count}"
|
|
177
|
+
active_threads.count
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# returns the max_thread_count
|
|
181
|
+
# because we may want to limit ssh or https connections
|
|
182
|
+
def max_thread_limit
|
|
183
|
+
unless @max_thread_limit
|
|
184
|
+
# the default thread count is 10 but can be
|
|
185
|
+
# raised by using environment variable MAX_FIXTURE_THREAD_COUNT
|
|
186
|
+
if ENV['MAX_FIXTURE_THREAD_COUNT'].to_i > 0
|
|
187
|
+
@max_thread_limit = ENV['MAX_FIXTURE_THREAD_COUNT'].to_i
|
|
188
|
+
else
|
|
189
|
+
@max_thread_limit = 10 # the default
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
@max_thread_limit
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def check_directory_for_symlinks(dir='.')
|
|
196
|
+
dir = Pathname.new(dir) unless dir.is_a?(Pathname)
|
|
197
|
+
results = []
|
|
198
|
+
|
|
199
|
+
dir.each_child(true) do |child|
|
|
200
|
+
if child.symlink?
|
|
201
|
+
results << child
|
|
202
|
+
elsif child.directory? && child.basename.to_s != '.git'
|
|
203
|
+
results.concat(check_directory_for_symlinks(child))
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
results
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
include PuppetlabsSpecHelper::Tasks::FixtureHelpers
|
|
211
|
+
|
|
212
|
+
desc "Create the fixtures directory"
|
|
213
|
+
task :spec_prep do
|
|
214
|
+
# Ruby only sets File::ALT_SEPARATOR on Windows and Rubys standard library
|
|
215
|
+
# uses this to check for Windows
|
|
216
|
+
is_windows = !!File::ALT_SEPARATOR
|
|
217
|
+
if is_windows
|
|
218
|
+
begin
|
|
219
|
+
require 'win32/dir'
|
|
220
|
+
rescue LoadError
|
|
221
|
+
$stderr.puts "win32-dir gem not installed, falling back to executing mklink directly"
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# git has a race condition creating that directory, that would lead to aborted clone operations
|
|
226
|
+
FileUtils::mkdir_p("spec/fixtures/modules")
|
|
227
|
+
|
|
228
|
+
repositories.each do |remote, opts|
|
|
229
|
+
scm = 'git'
|
|
230
|
+
target = opts["target"]
|
|
231
|
+
subdir = opts["subdir"]
|
|
232
|
+
ref = opts["ref"]
|
|
233
|
+
scm = opts["scm"] if opts["scm"]
|
|
234
|
+
branch = opts["branch"] if opts["branch"]
|
|
235
|
+
flags = opts["flags"]
|
|
236
|
+
# get the current active threads that are alive
|
|
237
|
+
count = current_thread_count(repositories)
|
|
238
|
+
if count < max_thread_limit
|
|
239
|
+
logger.debug "New Thread started for #{remote}"
|
|
240
|
+
# start up a new thread and store it in the opts hash
|
|
241
|
+
opts[:thread] = Thread.new do
|
|
242
|
+
clone_repo(scm, remote, target, subdir, ref, branch, flags)
|
|
243
|
+
revision(scm, target, ref) if ref
|
|
244
|
+
remove_subdirectory(target, subdir) if subdir
|
|
245
|
+
end
|
|
246
|
+
else
|
|
247
|
+
# the last thread started should be the longest wait
|
|
248
|
+
item, item_opts = repositories.find_all {|i,o| o.has_key?(:thread)}.last
|
|
249
|
+
logger.debug "Waiting on #{item}"
|
|
250
|
+
item_opts[:thread].join # wait for the thread to finish
|
|
251
|
+
# now that we waited lets try again
|
|
252
|
+
redo
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
# wait for all the threads to finish
|
|
257
|
+
repositories.each {|remote, opts| opts[:thread].join }
|
|
258
|
+
|
|
259
|
+
fixtures("symlinks").each do |target, link|
|
|
260
|
+
link = link['target']
|
|
261
|
+
unless File.symlink?(link)
|
|
262
|
+
logger.info("Creating symlink from #{link} to #{target}")
|
|
263
|
+
if is_windows
|
|
264
|
+
target = File.join(File.dirname(link), target) unless Pathname.new(target).absolute?
|
|
265
|
+
if Dir.respond_to?(:create_junction)
|
|
266
|
+
Dir.create_junction(link, target)
|
|
267
|
+
else
|
|
268
|
+
system("call mklink /J \"#{link.gsub('/', '\\')}\" \"#{target.gsub('/', '\\')}\"")
|
|
269
|
+
end
|
|
270
|
+
else
|
|
271
|
+
FileUtils::ln_sf(target, link)
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
fixtures("forge_modules").each do |remote, opts|
|
|
277
|
+
ref = ""
|
|
278
|
+
flags = ""
|
|
279
|
+
if opts.instance_of?(String)
|
|
280
|
+
target = opts
|
|
281
|
+
elsif opts.instance_of?(Hash)
|
|
282
|
+
target = opts["target"]
|
|
283
|
+
ref = " --version #{opts['ref']}" if not opts['ref'].nil?
|
|
284
|
+
flags = " #{opts['flags']}" if opts['flags']
|
|
285
|
+
end
|
|
286
|
+
next if File::exists?(target)
|
|
287
|
+
|
|
288
|
+
working_dir = module_working_directory
|
|
289
|
+
target_dir = File.expand_path('spec/fixtures/modules')
|
|
290
|
+
|
|
291
|
+
command = "puppet module install" + ref + flags + \
|
|
292
|
+
" --ignore-dependencies" \
|
|
293
|
+
" --force" \
|
|
294
|
+
" --module_working_dir \"#{working_dir}\"" \
|
|
295
|
+
" --target-dir \"#{target_dir}\" \"#{remote}\""
|
|
296
|
+
|
|
297
|
+
unless system(command)
|
|
298
|
+
fail "Failed to install module #{remote} to #{target_dir}"
|
|
299
|
+
end
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
FileUtils::mkdir_p("spec/fixtures/manifests")
|
|
303
|
+
FileUtils::touch("spec/fixtures/manifests/site.pp")
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
desc "Clean up the fixtures directory"
|
|
307
|
+
task :spec_clean do
|
|
308
|
+
fixtures("repositories").each do |remote, opts|
|
|
309
|
+
target = opts["target"]
|
|
310
|
+
FileUtils::rm_rf(target)
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
fixtures("forge_modules").each do |remote, opts|
|
|
314
|
+
target = opts["target"]
|
|
315
|
+
FileUtils::rm_rf(target)
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
FileUtils::rm_rf(module_working_directory)
|
|
319
|
+
|
|
320
|
+
fixtures("symlinks").each do |source, opts|
|
|
321
|
+
target = opts["target"]
|
|
322
|
+
FileUtils::rm_f(target)
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
if File.zero?("spec/fixtures/manifests/site.pp")
|
|
326
|
+
FileUtils::rm_f("spec/fixtures/manifests/site.pp")
|
|
327
|
+
end
|
|
328
|
+
end
|
|
@@ -12,6 +12,7 @@ Gem::Specification.new do |spec|
|
|
|
12
12
|
spec.summary = %q{Standard tasks and configuration for module spec tests.}
|
|
13
13
|
spec.description = %q{Contains rake tasks and a standard spec_helper for running spec tests on puppet modules.}
|
|
14
14
|
spec.homepage = "http://github.com/puppetlabs/puppetlabs_spec_helper"
|
|
15
|
+
spec.license = "Apache-2.0"
|
|
15
16
|
|
|
16
17
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
17
18
|
spec.bindir = "exe"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: puppetlabs_spec_helper
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.7.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Puppet, Inc.
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: exe
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2018-
|
|
12
|
+
date: 2018-04-12 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: mocha
|
|
@@ -192,12 +192,15 @@ files:
|
|
|
192
192
|
- lib/puppetlabs_spec_helper/puppetlabs_spec/puppet_internals.rb
|
|
193
193
|
- lib/puppetlabs_spec_helper/puppetlabs_spec_helper.rb
|
|
194
194
|
- lib/puppetlabs_spec_helper/rake_tasks.rb
|
|
195
|
+
- lib/puppetlabs_spec_helper/tasks/beaker.rb
|
|
196
|
+
- lib/puppetlabs_spec_helper/tasks/fixtures.rb
|
|
195
197
|
- lib/puppetlabs_spec_helper/version.rb
|
|
196
198
|
- puppet_spec_helper.rb
|
|
197
199
|
- puppetlabs_spec_helper.gemspec
|
|
198
200
|
- puppetlabs_spec_helper.rb
|
|
199
201
|
homepage: http://github.com/puppetlabs/puppetlabs_spec_helper
|
|
200
|
-
licenses:
|
|
202
|
+
licenses:
|
|
203
|
+
- Apache-2.0
|
|
201
204
|
metadata: {}
|
|
202
205
|
post_install_message:
|
|
203
206
|
rdoc_options: []
|
|
@@ -215,7 +218,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
215
218
|
version: '0'
|
|
216
219
|
requirements: []
|
|
217
220
|
rubyforge_project:
|
|
218
|
-
rubygems_version: 2.
|
|
221
|
+
rubygems_version: 2.6.8
|
|
219
222
|
signing_key:
|
|
220
223
|
specification_version: 4
|
|
221
224
|
summary: Standard tasks and configuration for module spec tests.
|