chefspec 0.6.1 → 0.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.
- data/lib/chefspec.rb +12 -9
- data/lib/chefspec/chef_runner.rb +13 -4
- data/lib/chefspec/matchers/cron.rb +7 -0
- data/lib/chefspec/minitest.rb +199 -0
- data/lib/chefspec/version.rb +1 -1
- metadata +79 -71
data/lib/chefspec.rb
CHANGED
@@ -1,14 +1,17 @@
|
|
1
1
|
require 'chef'
|
2
|
-
require 'rspec'
|
3
2
|
require 'chefspec/chef_runner'
|
4
3
|
require 'chefspec/version'
|
5
|
-
|
6
|
-
require 'chefspec/matchers/
|
7
|
-
require 'chefspec/matchers/
|
8
|
-
require 'chefspec/matchers/
|
9
|
-
require 'chefspec/matchers/
|
10
|
-
require 'chefspec/matchers/
|
11
|
-
require 'chefspec/matchers/
|
12
|
-
require 'chefspec/matchers/
|
4
|
+
if defined?(RSpec)
|
5
|
+
require 'chefspec/matchers/cron'
|
6
|
+
require 'chefspec/matchers/execute'
|
7
|
+
require 'chefspec/matchers/file'
|
8
|
+
require 'chefspec/matchers/link'
|
9
|
+
require 'chefspec/matchers/log'
|
10
|
+
require 'chefspec/matchers/package'
|
11
|
+
require 'chefspec/matchers/service'
|
12
|
+
require 'chefspec/matchers/shared'
|
13
|
+
require 'chefspec/matchers/file_content'
|
14
|
+
end
|
15
|
+
require 'chefspec/minitest'
|
13
16
|
require 'chefspec/monkey_patches/hash'
|
14
17
|
require 'chefspec/monkey_patches/provider'
|
data/lib/chefspec/chef_runner.rb
CHANGED
@@ -14,6 +14,7 @@ module ChefSpec
|
|
14
14
|
@resources = []
|
15
15
|
|
16
16
|
attr_accessor :resources
|
17
|
+
attr_reader :run_context
|
17
18
|
attr_reader :node
|
18
19
|
|
19
20
|
# Instantiate a new runner to run examples with.
|
@@ -85,11 +86,11 @@ module ChefSpec
|
|
85
86
|
|
86
87
|
@resources = []
|
87
88
|
if @client.respond_to?(:setup_run_context) # 0.10.x
|
88
|
-
run_context = @client.setup_run_context
|
89
|
+
@run_context = @client.setup_run_context
|
89
90
|
else
|
90
|
-
run_context = Chef::RunContext.new(@client.node, Chef::CookbookCollection.new(Chef::CookbookLoader.new)) # 0.9.x
|
91
|
+
@run_context = Chef::RunContext.new(@client.node, Chef::CookbookCollection.new(Chef::CookbookLoader.new)) # 0.9.x
|
91
92
|
end
|
92
|
-
runner = Chef::Runner.new(run_context)
|
93
|
+
runner = Chef::Runner.new(@run_context)
|
93
94
|
runner.converge
|
94
95
|
self
|
95
96
|
end
|
@@ -134,6 +135,14 @@ module ChefSpec
|
|
134
135
|
find_resource('link', target_file)
|
135
136
|
end
|
136
137
|
|
138
|
+
# Find a crontab entry declared with the given name
|
139
|
+
#
|
140
|
+
# @param [String] name of a crontab
|
141
|
+
# @return [Chef::Resource::Cron] The matching cron resource, or Nil
|
142
|
+
def cron(name)
|
143
|
+
find_resource('cron', name)
|
144
|
+
end
|
145
|
+
|
137
146
|
# This runner as a string.
|
138
147
|
#
|
139
148
|
# @return [String] Currently includes the run_list. Format of the string may change between versions of this gem.
|
@@ -161,7 +170,7 @@ module ChefSpec
|
|
161
170
|
#
|
162
171
|
# @return [String] The path to the cookbooks directory
|
163
172
|
def default_cookbook_path
|
164
|
-
Pathname.new(File.join(caller(2).first.split(':').slice(0..-3).
|
173
|
+
Pathname.new(File.join(caller(2).first.split(':').slice(0..-3).join(':'), '..', '..', '..')).cleanpath
|
165
174
|
end
|
166
175
|
|
167
176
|
# Find the resource with the declared type and name
|
@@ -0,0 +1,199 @@
|
|
1
|
+
module ChefSpec
|
2
|
+
# Supports running minitest-chef-handler examples without a real converge.
|
3
|
+
#
|
4
|
+
# This is experimental and comes with the following caveats:
|
5
|
+
#
|
6
|
+
# * This support is intended only to run existing examples at present. This
|
7
|
+
# means that it has not been tested with examples that explicitly create a
|
8
|
+
# new ChefRunner.
|
9
|
+
# * Examples that shell out or access the file system using Ruby will fail.
|
10
|
+
# This support only ensures that minitest-chef-handler matchers work.
|
11
|
+
# * Only a subset of minitest-chef-handler matchers are currently supported
|
12
|
+
# , equivalent to the built-in RSpec matchers.
|
13
|
+
# * It is assumed that your spec class includes the `MiniTest::Chef` modules
|
14
|
+
# directly. Add this include for ChefSpec mode:
|
15
|
+
#
|
16
|
+
# include ChefSpec::MiniTest
|
17
|
+
module MiniTest
|
18
|
+
|
19
|
+
# minitest-chef-handler declares methods for each resource that use
|
20
|
+
# `load_current_resource` to fetch the current state of the node. We override
|
21
|
+
# these and instantiate fresh resources.
|
22
|
+
def self.override_minitest_resources(run_context, within_module)
|
23
|
+
::Chef::Resource.constants.each do |resource|
|
24
|
+
if Chef::Resource.const_get(resource).respond_to?(:ancestors) and
|
25
|
+
Chef::Resource.const_get(resource).ancestors.include? Chef::Resource
|
26
|
+
method_name = Chef::Mixin::ConvertToClassName.
|
27
|
+
convert_to_snake_case(resource.to_s).to_sym
|
28
|
+
within_module.send(:define_method, method_name) do |name|
|
29
|
+
Chef::Resource.const_get(resource).new(name).tap do |r|
|
30
|
+
r.run_context = run_context
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# minitest-chef-handler patches `Chef::Resource` to handle file uid and gid
|
38
|
+
# conversion. In our instance these values are not populated by the
|
39
|
+
# provider and will instead be whatever was specified against the resource
|
40
|
+
# so we remove this conversion.
|
41
|
+
def self.remove_file_id_conversion
|
42
|
+
::Chef::Resource.class_eval do
|
43
|
+
def resource_value(attribute)
|
44
|
+
send(attribute)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.override_minitest_assertions(chef_run)
|
50
|
+
|
51
|
+
remove_file_id_conversion
|
52
|
+
|
53
|
+
::MiniTest::Chef::Assertions.class_eval do
|
54
|
+
|
55
|
+
def assert_includes_content(file, content)
|
56
|
+
assert file_includes_content?(file, content),
|
57
|
+
"Expected file '#{file.path}' to include the specified content"
|
58
|
+
file
|
59
|
+
end
|
60
|
+
|
61
|
+
def refute_includes_content(file, content)
|
62
|
+
refute file_includes_content?(file, content),
|
63
|
+
"Expected file '#{file.path}' not to include the specified content"
|
64
|
+
file
|
65
|
+
end
|
66
|
+
|
67
|
+
def assert_path_exists(file_or_dir)
|
68
|
+
paths = file_resources + resources_by_type(:directory)
|
69
|
+
actual_resource = paths.find{|file| file_or_dir.path == file.path and
|
70
|
+
! Array(file.action).include?(:delete)}
|
71
|
+
assert actual_resource, "Expected path '#{file_or_dir.path}' to exist"
|
72
|
+
actual_resource
|
73
|
+
end
|
74
|
+
|
75
|
+
def refute_path_exists(file_or_dir)
|
76
|
+
paths = file_resources + resources_by_type(:directory)
|
77
|
+
actual_resource = paths.find{|file| file_or_dir.path == file.path and
|
78
|
+
Array(file.action).include?(:delete)}
|
79
|
+
assert actual_resource, "Expected path '#{file_or_dir.path}' not to exist"
|
80
|
+
actual_resource
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
def same_resource_type?(expected_resource, actual_resource)
|
86
|
+
case actual_resource.resource_name.to_s
|
87
|
+
when /file$/
|
88
|
+
expected_resource.resource_name == :file
|
89
|
+
else
|
90
|
+
expected_resource.resource_name == actual_resource.resource_name
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def find_resource(expected_resource, field)
|
95
|
+
resources.find do |actual_resource|
|
96
|
+
same_resource_type?(expected_resource, actual_resource) and
|
97
|
+
expected_resource.send(field) == actual_resource.send(field)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def self.override_assertion(assert_name, field, wont_actions = [])
|
102
|
+
[:assert, :refute].each do |prefix|
|
103
|
+
define_method("#{prefix}_#{assert_name}") do |expected_resource|
|
104
|
+
actual_resource = find_resource(expected_resource, field)
|
105
|
+
is_wont = false
|
106
|
+
if actual_resource
|
107
|
+
is_wont = ! (Array(actual_resource.action) & wont_actions).empty?
|
108
|
+
end
|
109
|
+
# If we are refuting then the assertion is actually positive,
|
110
|
+
# we are for example asserting that the package has the `:remove`
|
111
|
+
# action.
|
112
|
+
if prefix == :assert || is_wont
|
113
|
+
assert actual_resource
|
114
|
+
else
|
115
|
+
refute actual_resource
|
116
|
+
end
|
117
|
+
actual_resource
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
override_assertion :installed, :package_name, [:remove, :purge]
|
123
|
+
override_assertion :enabled, :enabled, [:disable]
|
124
|
+
override_assertion :running, :running, [:stop]
|
125
|
+
|
126
|
+
def file_resources
|
127
|
+
resources.select{|r| r.resource_name.to_s.end_with?('file')} +
|
128
|
+
resources.select{|r| r.resource_name == :template}
|
129
|
+
end
|
130
|
+
|
131
|
+
def resources_by_type(type)
|
132
|
+
resources.select{|r| r.resource_name == type}
|
133
|
+
end
|
134
|
+
|
135
|
+
def cookbook_file_content(file_resource)
|
136
|
+
file = cookbook_files(file_resource.cookbook_name).find do |f|
|
137
|
+
Pathname.new(f).basename.to_s == file_resource.path
|
138
|
+
end
|
139
|
+
File.read(file)
|
140
|
+
end
|
141
|
+
|
142
|
+
def cookbook_files(cookbook)
|
143
|
+
run_context.cookbook_collection[cookbook].file_filenames
|
144
|
+
end
|
145
|
+
|
146
|
+
def file_includes_content?(file, content)
|
147
|
+
file_resources.any? do |f|
|
148
|
+
f.path == file.path &&
|
149
|
+
case f.resource_name
|
150
|
+
when :cookbook_file
|
151
|
+
cookbook_file_content(f)
|
152
|
+
when :file
|
153
|
+
f.content
|
154
|
+
when :template
|
155
|
+
render(f, node)
|
156
|
+
else raise NotImplementedError,
|
157
|
+
":#{f.resource_name} not supported for comparison"
|
158
|
+
end.include?(content)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def self.share_object(spec_mod, name, obj)
|
166
|
+
spec_mod.send(:define_method, name) do
|
167
|
+
obj
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def self.included(other_mod)
|
172
|
+
self.support_fake_converge(other_mod) if spec_module?(other_mod)
|
173
|
+
end
|
174
|
+
|
175
|
+
def self.support_fake_converge(spec_mod)
|
176
|
+
chef_run = ChefSpec::ChefRunner.new(
|
177
|
+
:cookbook_path => default_cookbook_path).converge recipe_for_module(spec_mod)
|
178
|
+
override_minitest_resources(chef_run.run_context, spec_mod)
|
179
|
+
override_minitest_assertions(chef_run)
|
180
|
+
share_object(spec_mod, :node, chef_run.node)
|
181
|
+
share_object(spec_mod, :resources, chef_run.resources)
|
182
|
+
share_object(spec_mod, :run_context, chef_run.run_context)
|
183
|
+
end
|
184
|
+
|
185
|
+
def self.recipe_for_module(mod)
|
186
|
+
mod.to_s.split('::')[-2..-1].join('::')
|
187
|
+
end
|
188
|
+
|
189
|
+
def self.spec_module?(mod)
|
190
|
+
# minitest-chef-handler module names are of the form:
|
191
|
+
# `recipe::example::default`
|
192
|
+
recipe_for_module(mod) == recipe_for_module(mod).downcase
|
193
|
+
end
|
194
|
+
|
195
|
+
def self.default_cookbook_path
|
196
|
+
Pathname.new(File.join(caller(3).first.split(':').slice(0..-3).first, "..", "..", "..")).cleanpath
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
data/lib/chefspec/version.rb
CHANGED
metadata
CHANGED
@@ -1,79 +1,89 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: chefspec
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.7.0
|
5
5
|
prerelease:
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 6
|
9
|
-
- 1
|
10
|
-
version: 0.6.1
|
11
6
|
platform: ruby
|
12
|
-
authors:
|
7
|
+
authors:
|
13
8
|
- Andrew Crump
|
14
9
|
autorequire:
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
12
|
+
date: 2012-08-27 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: chef
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
22
17
|
none: false
|
23
|
-
requirements:
|
24
|
-
- -
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
hash: 35
|
27
|
-
segments:
|
28
|
-
- 0
|
29
|
-
- 9
|
30
|
-
- 12
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
31
21
|
version: 0.9.12
|
32
|
-
requirement: *id001
|
33
22
|
type: :runtime
|
34
23
|
prerelease: false
|
35
|
-
|
36
|
-
|
37
|
-
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.9.12
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: erubis
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
38
33
|
none: false
|
39
|
-
requirements:
|
40
|
-
- -
|
41
|
-
- !ruby/object:Gem::Version
|
42
|
-
|
43
|
-
segments:
|
44
|
-
- 0
|
45
|
-
version: "0"
|
46
|
-
requirement: *id002
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
47
38
|
type: :runtime
|
48
39
|
prerelease: false
|
49
|
-
|
50
|
-
- !ruby/object:Gem::Dependency
|
51
|
-
version_requirements: &id003 !ruby/object:Gem::Requirement
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
41
|
none: false
|
53
|
-
requirements:
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: minitest-chef-handler
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
54
51
|
- - ~>
|
55
|
-
- !ruby/object:Gem::Version
|
56
|
-
|
57
|
-
segments:
|
58
|
-
- 2
|
59
|
-
- 10
|
60
|
-
- 0
|
61
|
-
version: 2.10.0
|
62
|
-
requirement: *id003
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.6.0
|
63
54
|
type: :runtime
|
64
55
|
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.6.0
|
62
|
+
- !ruby/object:Gem::Dependency
|
65
63
|
name: rspec
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 2.11.0
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 2.11.0
|
66
78
|
description: Write RSpec examples for Opscode Chef recipes
|
67
79
|
email:
|
68
80
|
executables: []
|
69
|
-
|
70
81
|
extensions: []
|
71
|
-
|
72
82
|
extra_rdoc_files: []
|
73
|
-
|
74
|
-
files:
|
83
|
+
files:
|
75
84
|
- lib/chef/knife/cookbook_create_specs.rb
|
76
85
|
- lib/chefspec/chef_runner.rb
|
86
|
+
- lib/chefspec/matchers/cron.rb
|
77
87
|
- lib/chefspec/matchers/execute.rb
|
78
88
|
- lib/chefspec/matchers/file.rb
|
79
89
|
- lib/chefspec/matchers/file_content.rb
|
@@ -82,43 +92,41 @@ files:
|
|
82
92
|
- lib/chefspec/matchers/package.rb
|
83
93
|
- lib/chefspec/matchers/service.rb
|
84
94
|
- lib/chefspec/matchers/shared.rb
|
95
|
+
- lib/chefspec/minitest.rb
|
85
96
|
- lib/chefspec/monkey_patches/hash.rb
|
86
97
|
- lib/chefspec/monkey_patches/provider.rb
|
87
98
|
- lib/chefspec/version.rb
|
88
99
|
- lib/chefspec.rb
|
89
100
|
homepage: http://acrmp.github.com/chefspec
|
90
|
-
licenses:
|
101
|
+
licenses:
|
91
102
|
- MIT
|
92
103
|
post_install_message:
|
93
104
|
rdoc_options: []
|
94
|
-
|
95
|
-
require_paths:
|
105
|
+
require_paths:
|
96
106
|
- lib
|
97
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
107
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
98
108
|
none: false
|
99
|
-
requirements:
|
100
|
-
- -
|
101
|
-
- !ruby/object:Gem::Version
|
102
|
-
|
103
|
-
segments:
|
109
|
+
requirements:
|
110
|
+
- - ! '>='
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: '0'
|
113
|
+
segments:
|
104
114
|
- 0
|
105
|
-
|
106
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
115
|
+
hash: -516424648685498603
|
116
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
107
117
|
none: false
|
108
|
-
requirements:
|
109
|
-
- -
|
110
|
-
- !ruby/object:Gem::Version
|
111
|
-
|
112
|
-
segments:
|
118
|
+
requirements:
|
119
|
+
- - ! '>='
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
version: '0'
|
122
|
+
segments:
|
113
123
|
- 0
|
114
|
-
|
124
|
+
hash: -516424648685498603
|
115
125
|
requirements: []
|
116
|
-
|
117
126
|
rubyforge_project:
|
118
|
-
rubygems_version: 1.8.
|
127
|
+
rubygems_version: 1.8.19
|
119
128
|
signing_key:
|
120
129
|
specification_version: 3
|
121
|
-
summary: chefspec-0.
|
130
|
+
summary: chefspec-0.7.0
|
122
131
|
test_files: []
|
123
|
-
|
124
132
|
has_rdoc:
|