chefspec 7.3.3 → 7.3.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|