chefspec 7.3.3 → 7.3.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/Gemfile +23 -0
- data/Rakefile +77 -0
- data/chefspec.gemspec +29 -0
- data/lib/chefspec/version.rb +1 -1
- data/spec/spec_helper.rb +13 -0
- data/spec/support/hash.rb +35 -0
- data/spec/unit/cacher_spec.rb +70 -0
- data/spec/unit/coverage/filters_spec.rb +60 -0
- data/spec/unit/deprecations_spec.rb +53 -0
- data/spec/unit/errors_spec.rb +57 -0
- data/spec/unit/expect_exception_spec.rb +32 -0
- data/spec/unit/macros_spec.rb +119 -0
- data/spec/unit/matchers/do_nothing_matcher.rb +5 -0
- data/spec/unit/matchers/include_recipe_matcher_spec.rb +38 -0
- data/spec/unit/matchers/link_to_matcher_spec.rb +55 -0
- data/spec/unit/matchers/notifications_matcher_spec.rb +40 -0
- data/spec/unit/matchers/render_file_matcher_spec.rb +68 -0
- data/spec/unit/matchers/resource_matcher_spec.rb +5 -0
- data/spec/unit/matchers/state_attrs_matcher_spec.rb +68 -0
- data/spec/unit/matchers/subscribes_matcher_spec.rb +65 -0
- data/spec/unit/renderer_spec.rb +69 -0
- data/spec/unit/server_runner_spec.rb +28 -0
- data/spec/unit/solo_runner_spec.rb +171 -0
- data/spec/unit/stubs/command_registry_spec.rb +27 -0
- data/spec/unit/stubs/command_stub_spec.rb +61 -0
- data/spec/unit/stubs/data_bag_item_registry_spec.rb +39 -0
- data/spec/unit/stubs/data_bag_item_stub_spec.rb +36 -0
- data/spec/unit/stubs/data_bag_registry_spec.rb +39 -0
- data/spec/unit/stubs/data_bag_stub_spec.rb +35 -0
- data/spec/unit/stubs/registry_spec.rb +29 -0
- data/spec/unit/stubs/search_registry_spec.rb +39 -0
- data/spec/unit/stubs/search_stub_spec.rb +36 -0
- data/spec/unit/stubs/stub_spec.rb +64 -0
- metadata +34 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '087946db9144fc3c278e7b18e1afefd129d6f964f1008114b00ab5bbe5fbb34e'
|
4
|
+
data.tar.gz: 47809ae0412a69c75c8e2e0eb8f7109adfe86befc62270aa5e3b4659a0d5737b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0e988f0d741d4dce1f20c21cf6d8d19eaa6cae90261eaa9e090e99483ef6a249c54a544017fda8aba6bf67d3a7e753c9614c42e75c464733382969eb811ebe67
|
7
|
+
data.tar.gz: 7279c57f503a0b662d840608f79a8cd5b445e19fe3a7302043b3162bd044369a61729ea69098ae9e064539d54e8d7c9691a7922659b5ab5eeca027660178ce21
|
data/Gemfile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
gemspec
|
4
|
+
|
5
|
+
group :development do
|
6
|
+
gem 'rake'
|
7
|
+
gem 'redcarpet'
|
8
|
+
gem 'yard'
|
9
|
+
gem 'pry'
|
10
|
+
gem 'pry-byebug'
|
11
|
+
end
|
12
|
+
|
13
|
+
if ENV["GEMFILE_MOD"]
|
14
|
+
puts "GEMFILE_MOD: #{ENV['GEMFILE_MOD']}"
|
15
|
+
instance_eval(ENV["GEMFILE_MOD"])
|
16
|
+
else
|
17
|
+
gem 'chef', git: "https://github.com/chef/chef"
|
18
|
+
gem 'ohai', git: "https://github.com/chef/ohai"
|
19
|
+
end
|
20
|
+
|
21
|
+
# If you want to load debugging tools into the bundle exec sandbox,
|
22
|
+
# add these additional dependencies into Gemfile.local
|
23
|
+
eval_gemfile(__FILE__ + ".local") if File.exist?(__FILE__ + ".local")
|
data/Rakefile
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require 'rspec/core'
|
3
|
+
require 'rspec/core/rake_task'
|
4
|
+
require 'yard/rake/yardoc_task'
|
5
|
+
require 'tmpdir'
|
6
|
+
require 'rspec'
|
7
|
+
require 'chefspec'
|
8
|
+
|
9
|
+
require 'chef/version'
|
10
|
+
|
11
|
+
YARD::Rake::YardocTask.new
|
12
|
+
|
13
|
+
RSpec::Core::RakeTask.new(:unit) do |t|
|
14
|
+
t.rspec_opts = [].tap do |a|
|
15
|
+
a.push('--color')
|
16
|
+
a.push('--format progress')
|
17
|
+
end.join(' ')
|
18
|
+
end
|
19
|
+
|
20
|
+
failed = []
|
21
|
+
start_time = nil
|
22
|
+
|
23
|
+
namespace :acceptance do |ns|
|
24
|
+
begin
|
25
|
+
Dir.foreach("examples") do |dir|
|
26
|
+
next if dir == '.' or dir == '..'
|
27
|
+
desc "#{dir} acceptance tests"
|
28
|
+
task dir.to_sym do
|
29
|
+
start_time ||= Time.now
|
30
|
+
Dir.mktmpdir do |tmp|
|
31
|
+
FileUtils.cp_r("examples/#{dir}", tmp)
|
32
|
+
|
33
|
+
pwd = Dir.pwd
|
34
|
+
|
35
|
+
Dir.chdir "#{tmp}/#{dir}" do
|
36
|
+
puts "rspec examples/#{dir}"
|
37
|
+
|
38
|
+
#
|
39
|
+
# This bit of mildly awful magic below is to load each file into an in-memory
|
40
|
+
# RSpec runner while keeping a persistent ChefZero server alive.
|
41
|
+
#
|
42
|
+
load "#{pwd}/lib/chefspec/rspec.rb"
|
43
|
+
|
44
|
+
RSpec.configure do |config|
|
45
|
+
config.color = true
|
46
|
+
config.run_all_when_everything_filtered = true
|
47
|
+
config.filter_run(:focus)
|
48
|
+
config.before(:suite) do
|
49
|
+
ChefSpec::ZeroServer.setup!
|
50
|
+
end
|
51
|
+
config.after(:each) do
|
52
|
+
ChefSpec::ZeroServer.reset!
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
RSpec.clear_examples
|
57
|
+
exitstatus = RSpec::Core::Runner.run(["spec"])
|
58
|
+
RSpec.reset
|
59
|
+
failed << dir unless exitstatus == 0
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
rescue Errno::ENOENT # examples dir is probably missing
|
65
|
+
puts "The rake acceptance tests require a full git checkout of chefspec including all examples files!"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
task acceptance: Rake.application.tasks.select { |t| t.name.start_with?("acceptance:") } do
|
70
|
+
puts "Acceptance tests took #{Time.now - start_time} seconds"
|
71
|
+
raise "some tests failed: #{failed.join(', ')}" unless failed.empty?
|
72
|
+
end
|
73
|
+
|
74
|
+
desc 'Run all tests'
|
75
|
+
task :test => [:unit, :acceptance]
|
76
|
+
|
77
|
+
task :default => [:test]
|
data/chefspec.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
lib = File.expand_path('../lib/', __FILE__)
|
2
|
+
$:.unshift lib unless $:.include?(lib)
|
3
|
+
require 'chefspec/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'chefspec'
|
7
|
+
s.version = ChefSpec::VERSION
|
8
|
+
s.authors = ['Andrew Crump', 'Seth Vargo']
|
9
|
+
s.email = ['andrew.crump@ieee.org', 'sethvargo@gmail.com']
|
10
|
+
s.summary = 'Write RSpec examples and generate coverage reports for ' \
|
11
|
+
'Chef recipes!'
|
12
|
+
s.description = 'ChefSpec is a unit testing and resource coverage ' \
|
13
|
+
'(code coverage) framework for testing Chef cookbooks ' \
|
14
|
+
'ChefSpec makes it easy to write examples and get fast ' \
|
15
|
+
'feedback on cookbook changes without the need for ' \
|
16
|
+
'virtual machines or cloud servers.'
|
17
|
+
s.homepage = 'https://github.com/chefspec/chefspec'
|
18
|
+
s.license = 'MIT'
|
19
|
+
|
20
|
+
# Packaging
|
21
|
+
s.files = %w{LICENSE Rakefile Gemfile chefspec.gemspec} + Dir.glob("{lib,templates,spec}/**/*", File::FNM_DOTMATCH).reject { |f| File.directory?(f) }
|
22
|
+
s.require_paths = ['lib']
|
23
|
+
|
24
|
+
s.required_ruby_version = '>= 2.2'
|
25
|
+
|
26
|
+
s.add_dependency 'chef', '>= 12.16.42'
|
27
|
+
s.add_dependency 'fauxhai', '>= 4'
|
28
|
+
s.add_dependency 'rspec', '~> 3.0'
|
29
|
+
end
|
data/lib/chefspec/version.rb
CHANGED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'chefspec'
|
2
|
+
require 'support/hash'
|
3
|
+
|
4
|
+
|
5
|
+
ChefSpec::Coverage.start! do
|
6
|
+
set_template 'table.erb'
|
7
|
+
end
|
8
|
+
|
9
|
+
RSpec.configure do |config|
|
10
|
+
config.expect_with(:rspec) { |c| c.syntax = :expect }
|
11
|
+
config.filter_run(focus: true)
|
12
|
+
config.run_all_when_everything_filtered = true
|
13
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
#
|
2
|
+
# An extension of a Hash that allows mash-style like lookups.
|
3
|
+
#
|
4
|
+
# @private
|
5
|
+
#
|
6
|
+
class Hash
|
7
|
+
# Like, seriously Windows?
|
8
|
+
undef_method(:timeout)
|
9
|
+
|
10
|
+
#
|
11
|
+
# Monkey-patch to allow mash-style look ups for tests
|
12
|
+
#
|
13
|
+
def method_missing(m, *args, &block)
|
14
|
+
if has_key?(m.to_sym)
|
15
|
+
self[m.to_sym]
|
16
|
+
elsif has_key?(m.to_s)
|
17
|
+
self[m.to_s]
|
18
|
+
else
|
19
|
+
super
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
#
|
24
|
+
# Monkey-patch to stdlib Hash to correspond to Mash-style lookup
|
25
|
+
#
|
26
|
+
# @see Hash#respond_to?
|
27
|
+
#
|
28
|
+
def respond_to?(m, include_private = false)
|
29
|
+
if has_key?(m.to_sym) || has_key?(m.to_s)
|
30
|
+
true
|
31
|
+
else
|
32
|
+
super
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'chefspec/cacher'
|
3
|
+
|
4
|
+
describe ChefSpec::Cacher do
|
5
|
+
let(:klass) do
|
6
|
+
Class.new(RSpec::Core::ExampleGroup) do
|
7
|
+
extend ChefSpec::Cacher
|
8
|
+
|
9
|
+
def self.metadata
|
10
|
+
{ parent_example_group: { location: 'spec' } }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:cache) { described_class.class_variable_get(:@@cache) }
|
16
|
+
let(:preserve_cache) { false }
|
17
|
+
|
18
|
+
before(:each) { described_class.class_variable_set(:@@cache, {}) unless preserve_cache }
|
19
|
+
|
20
|
+
describe 'cached' do
|
21
|
+
it 'lazily defines the results for the cache' do
|
22
|
+
klass.cached(:chef_run)
|
23
|
+
expect(klass).to be_method_defined(:chef_run)
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'adds the item to the cache when called' do
|
27
|
+
runner = double(:runner)
|
28
|
+
klass.cached(:chef_run) { runner }
|
29
|
+
klass.new.chef_run
|
30
|
+
|
31
|
+
expect(cache[Thread.current.object_id]).to have_key('spec.chef_run')
|
32
|
+
expect(cache[Thread.current.object_id]['spec.chef_run']).to eq(runner)
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'when multithreaded environment' do
|
36
|
+
it 'is thread safe' do
|
37
|
+
(1..2).each do |n|
|
38
|
+
Thread.new do
|
39
|
+
klass.cached(:chef_run) { n }
|
40
|
+
expect(klass.new.chef_run).to eq(n)
|
41
|
+
end.join
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'when example groups are defined by looping' do
|
47
|
+
let(:preserve_cache) { true }
|
48
|
+
|
49
|
+
['first', 'second', 'third'].each do |iteration|
|
50
|
+
context "on the #{iteration} iteration" do
|
51
|
+
context 'in caching context' do
|
52
|
+
cached(:cached_iteration) { iteration }
|
53
|
+
it 'caches the iteration for this context' do
|
54
|
+
expect(cached_iteration).to eq iteration
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe 'cached!' do
|
63
|
+
it 'loads the value at runtime' do
|
64
|
+
expect(klass).to receive(:cached).with(:chef_run).once
|
65
|
+
expect(klass).to receive(:before).once
|
66
|
+
|
67
|
+
klass.cached!(:chef_run) { }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
# Note: These specs don't use Berkshelf code directly as this project doesn't
|
4
|
+
# have a direct dependency on Berkshelf and loading it would impact the
|
5
|
+
# perfance of these specs. While not ideal, the test doubles provide enough of
|
6
|
+
# a standin for Berkshelf to exercise the `#matches?` behavior.
|
7
|
+
describe ChefSpec::Coverage::BerkshelfFilter do
|
8
|
+
let(:dependencies) do
|
9
|
+
[double('Berkshelf::Dependency', metadata?: true, name: "cookbookery")]
|
10
|
+
end
|
11
|
+
let(:berksfile) { double('Berkshelf::Berksfile', dependencies: dependencies) }
|
12
|
+
let(:resource) { Chef::Resource.new('theone') }
|
13
|
+
subject { described_class.new(berksfile) }
|
14
|
+
|
15
|
+
describe '#matches?' do
|
16
|
+
it 'returns truthy if resource source_line is nil' do
|
17
|
+
expect(subject.matches?(resource)).to be_truthy
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'when resource#source_line is under target cookbook' do
|
21
|
+
it 'normal unix path returns truthy' do
|
22
|
+
resource.source_line =
|
23
|
+
'/path/to/cookbooks/nope/recipes/default.rb:22'
|
24
|
+
expect(subject.matches?(resource)).to be_truthy
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'normal windows path returns truthy' do
|
28
|
+
resource.source_line =
|
29
|
+
'C:\\path\\to\\cookbooks\\nope\\recipes\\default.rb:22'
|
30
|
+
expect(subject.matches?(resource)).to be_truthy
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'mixed windows path returns truthy' do
|
34
|
+
resource.source_line =
|
35
|
+
'C:\\path\\to\\cookbooks/nope/recipes/default.rb:22'
|
36
|
+
expect(subject.matches?(resource)).to be_truthy
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'when resource#source_line is not under target cookbook' do
|
41
|
+
it 'normal unix path returns falsey' do
|
42
|
+
resource.source_line =
|
43
|
+
'/path/to/cookbooks/cookbookery/recipes/default.rb:22'
|
44
|
+
expect(subject.matches?(resource)).to be_falsey
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'normal windows path returns falsey' do
|
48
|
+
resource.source_line =
|
49
|
+
'C:\\path\\to\\cookbooks\\cookbookery\\recipes\\default.rb:22'
|
50
|
+
expect(subject.matches?(resource)).to be_falsey
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'mixed windows path returns falsey' do
|
54
|
+
resource.source_line =
|
55
|
+
'C:\\path\\to\\cookbooks/cookbookery/recipes/default.rb:22'
|
56
|
+
expect(subject.matches?(resource)).to be_falsey
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ChefSpec::Runner do
|
4
|
+
before do
|
5
|
+
allow_any_instance_of(ChefSpec::SoloRunner)
|
6
|
+
.to receive(:dry_run?)
|
7
|
+
.and_return(true)
|
8
|
+
allow(ChefSpec::Runner).to receive(:deprecated)
|
9
|
+
end
|
10
|
+
|
11
|
+
describe '#define_runner_method' do
|
12
|
+
before do
|
13
|
+
allow(ChefSpec).to receive(:define_matcher)
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'prints a deprecation' do
|
17
|
+
expect(ChefSpec::Runner).to receive(:deprecated)
|
18
|
+
.with("`ChefSpec::Runner.define_runner_method' is deprecated."\
|
19
|
+
" It is being used in the my_custom_resource resource matcher." \
|
20
|
+
" Please use `ChefSpec.define_matcher' instead.")
|
21
|
+
ChefSpec::Runner.define_runner_method(:my_custom_resource)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'calls ChefSpec#define_matcher' do
|
25
|
+
expect(ChefSpec).to receive(:define_matcher).with(:my_custom_resource).once
|
26
|
+
ChefSpec::Runner.define_runner_method(:my_custom_resource)
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe ChefSpec::Server do
|
33
|
+
before do
|
34
|
+
allow(ChefSpec::Server).to receive(:deprecated)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'prints a deprecation for any method called' do
|
38
|
+
expect(ChefSpec::Server).to receive(:deprecated)
|
39
|
+
.with("`ChefSpec::Server.any_method' is deprecated. There is no longer" \
|
40
|
+
" a global Chef Server instance. Please use a ChefSpec::SoloRunner" \
|
41
|
+
" instead. More documentation can be found in the ChefSpec README."
|
42
|
+
)
|
43
|
+
expect {
|
44
|
+
ChefSpec::Server.any_method
|
45
|
+
}.to raise_error(ChefSpec::Error::NoConversionError)
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'raises non-conversion error for any method called' do
|
49
|
+
expect{ChefSpec::Server.any_method}
|
50
|
+
.to raise_error(ChefSpec::Error::NoConversionError)
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module ChefSpec::Error
|
4
|
+
describe CommandNotStubbed do
|
5
|
+
let(:instance) { described_class.new(args: ['cat']) }
|
6
|
+
|
7
|
+
it 'raises an exception with the correct message' do
|
8
|
+
instance
|
9
|
+
expect { raise instance }.to raise_error { |error|
|
10
|
+
expect(error).to be_a(described_class)
|
11
|
+
expect(error.message).to eq <<-EOH.gsub(/^ {10}/, '')
|
12
|
+
Executing a real command is disabled. Unregistered command:
|
13
|
+
|
14
|
+
command("cat")
|
15
|
+
|
16
|
+
You can stub this command with:
|
17
|
+
|
18
|
+
stub_command("cat").and_return(...)
|
19
|
+
EOH
|
20
|
+
}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe CookbookPathNotFound do
|
25
|
+
let(:instance) { described_class.new }
|
26
|
+
|
27
|
+
it 'raises an exception with the correct message' do
|
28
|
+
expect { raise instance }.to raise_error { |error|
|
29
|
+
expect(error).to be_a(described_class)
|
30
|
+
expect(error.message).to eq <<-EOH.gsub(/^ {10}/, '')
|
31
|
+
I could not find or infer a cookbook_path from your current working directory.
|
32
|
+
Please make sure you put your specs (tests) under a directory named 'spec' or
|
33
|
+
manually set the cookbook path in the RSpec configuration.
|
34
|
+
EOH
|
35
|
+
}
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe GemLoadError do
|
40
|
+
let(:instance) { described_class.new(gem: 'bacon', name: 'bacon') }
|
41
|
+
|
42
|
+
it 'raises an exception with the correct message' do
|
43
|
+
expect { raise instance }.to raise_error { |error|
|
44
|
+
expect(error).to be_a(described_class)
|
45
|
+
expect(error.message).to eq <<-EOH.gsub(/^ {10}/, '')
|
46
|
+
I could not load the 'bacon' gem! You must have the gem installed
|
47
|
+
on your local system before you can use the bacon plugin.
|
48
|
+
You can install bacon by running:
|
49
|
+
|
50
|
+
gem install bacon
|
51
|
+
|
52
|
+
or add bacon to your Gemfile and run the `bundle` command to install.
|
53
|
+
EOH
|
54
|
+
}
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|