chefspec 3.4.0 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +2 -19
- data/CHANGELOG.md +32 -1
- data/CONTRIBUTING.md +1 -1
- data/README.md +37 -9
- data/chefspec.gemspec +2 -3
- data/examples/render_file/spec/default_spec.rb +32 -17
- data/examples/server/recipes/render_with_cached.rb +3 -0
- data/examples/server/spec/client_spec.rb +1 -1
- data/examples/server/spec/data_bag_spec.rb +1 -1
- data/examples/server/spec/environment_spec.rb +1 -1
- data/examples/server/spec/node_spec.rb +1 -1
- data/examples/server/spec/render_with_cached_spec.rb +16 -0
- data/examples/server/spec/role_spec.rb +1 -1
- data/features/server.feature +10 -12
- data/features/support/executor.rb +2 -0
- data/gemfiles/{chef-11.0.0.gemfile → chef-11.12.0.gemfile} +1 -1
- data/gemfiles/chef-master.gemfile +1 -1
- data/lib/chefspec.rb +1 -0
- data/lib/chefspec/api/erl_call.rb +5 -5
- data/lib/chefspec/api/execute.rb +5 -5
- data/lib/chefspec/api/powershell_script.rb +5 -5
- data/lib/chefspec/api/ruby_block.rb +2 -2
- data/lib/chefspec/api/script.rb +13 -2
- data/lib/chefspec/cacher.rb +2 -1
- data/lib/chefspec/coverage.rb +10 -2
- data/lib/chefspec/expect_exception.rb +0 -2
- data/lib/chefspec/extensions/chef/lwrp_base.rb +5 -1
- data/lib/chefspec/extensions/chef/resource/freebsd_package.rb +19 -0
- data/lib/chefspec/librarian.rb +5 -2
- data/lib/chefspec/macros.rb +3 -3
- data/lib/chefspec/matchers/do_nothing_matcher.rb +4 -2
- data/lib/chefspec/matchers/include_recipe_matcher.rb +2 -2
- data/lib/chefspec/matchers/link_to_matcher.rb +11 -5
- data/lib/chefspec/matchers/notifications_matcher.rb +2 -2
- data/lib/chefspec/matchers/render_file_matcher.rb +9 -3
- data/lib/chefspec/matchers/resource_matcher.rb +2 -2
- data/lib/chefspec/matchers/state_attrs_matcher.rb +2 -2
- data/lib/chefspec/matchers/subscribes_matcher.rb +4 -4
- data/lib/chefspec/renderer.rb +1 -1
- data/lib/chefspec/rspec.rb +1 -0
- data/lib/chefspec/runner.rb +2 -1
- data/lib/chefspec/server.rb +90 -19
- data/lib/chefspec/version.rb +1 -1
- data/spec/unit/cacher_spec.rb +1 -1
- data/spec/unit/expect_exception_spec.rb +6 -6
- data/spec/unit/extensions/lwrp_base_spec.rb +9 -1
- data/spec/unit/macros_spec.rb +6 -6
- data/spec/unit/matchers/include_recipe_matcher_spec.rb +6 -6
- data/spec/unit/matchers/link_to_matcher_spec.rb +31 -15
- data/spec/unit/matchers/notifications_matcher_spec.rb +4 -4
- data/spec/unit/matchers/render_file_matcher_spec.rb +19 -10
- data/spec/unit/matchers/state_attrs_matcher_spec.rb +28 -24
- data/spec/unit/matchers/subscribes_matcher_spec.rb +7 -7
- data/spec/unit/renderer_spec.rb +7 -7
- data/spec/unit/runner_spec.rb +39 -9
- metadata +10 -25
- data/gemfiles/chef-11.2.0.gemfile +0 -5
- data/gemfiles/chef-11.4.4.gemfile +0 -5
- data/gemfiles/chef-11.6.0.gemfile +0 -5
- data/gemfiles/chef-11.8.0.gemfile +0 -5
@@ -15,19 +15,19 @@ module ChefSpec::API
|
|
15
15
|
# The Examples section demonstrates the different ways to test a
|
16
16
|
# +powershell_script+ resource with ChefSpec.
|
17
17
|
#
|
18
|
-
# @example Assert that a +powershell_script+ was
|
18
|
+
# @example Assert that a +powershell_script+ was run
|
19
19
|
# expect(chef_run).to run_powershell_script('/tmp')
|
20
20
|
#
|
21
|
-
# @example Assert that a +powershell_script+ was
|
21
|
+
# @example Assert that a +powershell_script+ was run with predicate matchers
|
22
22
|
# expect(chef_run).to run_powershell_script('/tmp').with_user('svargo')
|
23
23
|
#
|
24
|
-
# @example Assert that a +powershell_script+ was
|
24
|
+
# @example Assert that a +powershell_script+ was run with attributes
|
25
25
|
# expect(chef_run).to run_powershell_script('/tmp').with(user: 'svargo')
|
26
26
|
#
|
27
|
-
# @example Assert that a +powershell_script+ was
|
27
|
+
# @example Assert that a +powershell_script+ was run using a regex
|
28
28
|
# expect(chef_run).to run_powershell_script('/tmp').with(user: /sva(.+)/)
|
29
29
|
#
|
30
|
-
# @example Assert that a +powershell_script+ was _not_
|
30
|
+
# @example Assert that a +powershell_script+ was _not_ run
|
31
31
|
# expect(chef_run).to_not run_powershell_script('/tmp')
|
32
32
|
#
|
33
33
|
#
|
@@ -18,10 +18,10 @@ module ChefSpec::API
|
|
18
18
|
# The Examples section demonstrates the different ways to test a
|
19
19
|
# +ruby_block+ resource with ChefSpec.
|
20
20
|
#
|
21
|
-
# @example Assert that a +ruby_block+ was
|
21
|
+
# @example Assert that a +ruby_block+ was run
|
22
22
|
# expect(chef_run).to run_ruby_block('do_something')
|
23
23
|
#
|
24
|
-
# @example Assert that a +ruby_block+ was _not_
|
24
|
+
# @example Assert that a +ruby_block+ was _not_ run
|
25
25
|
# expect(chef_run).to_not run_ruby_block('do_something')
|
26
26
|
#
|
27
27
|
#
|
data/lib/chefspec/api/script.rb
CHANGED
@@ -1,8 +1,6 @@
|
|
1
1
|
module ChefSpec::API
|
2
2
|
# @since 1.0.0
|
3
3
|
module ScriptMatchers
|
4
|
-
ChefSpec::Runner.define_runner_method :script
|
5
|
-
|
6
4
|
#
|
7
5
|
# Assert that a +bash+ resource exists in the Chef run with the
|
8
6
|
# action +:run+. Given a Chef Recipe that runs "command" using
|
@@ -40,6 +38,8 @@ module ChefSpec::API
|
|
40
38
|
ChefSpec::Matchers::ResourceMatcher.new(:bash, :run, resource_name)
|
41
39
|
end
|
42
40
|
|
41
|
+
ChefSpec::Runner.define_runner_method :bash
|
42
|
+
|
43
43
|
#
|
44
44
|
# Assert that a +csh+ resource exists in the Chef run with the
|
45
45
|
# action +:run+. Given a Chef Recipe that runs "command" using
|
@@ -77,6 +77,8 @@ module ChefSpec::API
|
|
77
77
|
ChefSpec::Matchers::ResourceMatcher.new(:csh, :run, resource_name)
|
78
78
|
end
|
79
79
|
|
80
|
+
ChefSpec::Runner.define_runner_method :csh
|
81
|
+
|
80
82
|
#
|
81
83
|
# Assert that a +perl+ resource exists in the Chef run with the
|
82
84
|
# action +:run+. Given a Chef Recipe that runs "command" using
|
@@ -114,6 +116,8 @@ module ChefSpec::API
|
|
114
116
|
ChefSpec::Matchers::ResourceMatcher.new(:perl, :run, resource_name)
|
115
117
|
end
|
116
118
|
|
119
|
+
ChefSpec::Runner.define_runner_method :perl
|
120
|
+
|
117
121
|
#
|
118
122
|
# Assert that a +python+ resource exists in the Chef run with the
|
119
123
|
# action +:run+. Given a Chef Recipe that runs "command" using
|
@@ -151,6 +155,8 @@ module ChefSpec::API
|
|
151
155
|
ChefSpec::Matchers::ResourceMatcher.new(:python, :run, resource_name)
|
152
156
|
end
|
153
157
|
|
158
|
+
ChefSpec::Runner.define_runner_method :python
|
159
|
+
|
154
160
|
#
|
155
161
|
# Assert that a +ruby+ resource exists in the Chef run with the
|
156
162
|
# action +:run+. Given a Chef Recipe that runs "command" using
|
@@ -188,6 +194,8 @@ module ChefSpec::API
|
|
188
194
|
ChefSpec::Matchers::ResourceMatcher.new(:ruby, :run, resource_name)
|
189
195
|
end
|
190
196
|
|
197
|
+
ChefSpec::Runner.define_runner_method :ruby
|
198
|
+
|
191
199
|
#
|
192
200
|
# Assert that a +script+ resource exists in the Chef run with the
|
193
201
|
# action +:run+. Given a Chef Recipe that runs "command" using
|
@@ -224,5 +232,8 @@ module ChefSpec::API
|
|
224
232
|
def run_script(resource_name)
|
225
233
|
ChefSpec::Matchers::ResourceMatcher.new(:script, :run, resource_name)
|
226
234
|
end
|
235
|
+
|
236
|
+
|
237
|
+
ChefSpec::Runner.define_runner_method :script
|
227
238
|
end
|
228
239
|
end
|
data/lib/chefspec/cacher.rb
CHANGED
@@ -34,7 +34,8 @@ module ChefSpec
|
|
34
34
|
FINALIZER = lambda { |id| @@cache.delete(id) }
|
35
35
|
|
36
36
|
def cached(name, &block)
|
37
|
-
location
|
37
|
+
location = ancestors.first.metadata[:location]
|
38
|
+
location ||= ancestors.first.metadata[:parent_example_group][:location]
|
38
39
|
|
39
40
|
define_method(name) do
|
40
41
|
key = [location, name.to_s].join('.')
|
data/lib/chefspec/coverage.rb
CHANGED
@@ -161,11 +161,19 @@ module ChefSpec
|
|
161
161
|
end
|
162
162
|
|
163
163
|
def source_file
|
164
|
-
@source_file ||=
|
164
|
+
@source_file ||= if @resource.source_line
|
165
|
+
shortname(@resource.source_line.split(':').first)
|
166
|
+
else
|
167
|
+
'Unknown'
|
168
|
+
end
|
165
169
|
end
|
166
170
|
|
167
171
|
def source_line
|
168
|
-
@source_line ||= @resource.source_line
|
172
|
+
@source_line ||= if @resource.source_line
|
173
|
+
@resource.source_line.split(':', 2).last.to_i
|
174
|
+
else
|
175
|
+
'Unknown'
|
176
|
+
end
|
169
177
|
end
|
170
178
|
|
171
179
|
def touch!
|
@@ -39,7 +39,11 @@ class Chef
|
|
39
39
|
[self, superclass].each do |resource_holder|
|
40
40
|
look_in_parents = false
|
41
41
|
if resource_holder.const_defined?(class_name, look_in_parents)
|
42
|
-
resource_holder.send(:remove_const, class_name)
|
42
|
+
old_class = resource_holder.send(:remove_const, class_name)
|
43
|
+
|
44
|
+
if resource_holder.respond_to?(:resource_classes)
|
45
|
+
resource_holder.resource_classes.delete(old_class)
|
46
|
+
end
|
43
47
|
end
|
44
48
|
end
|
45
49
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'chef/resource/freebsd_package'
|
2
|
+
|
3
|
+
class Chef
|
4
|
+
class Resource
|
5
|
+
class FreebsdPackage < Chef::Resource::Package
|
6
|
+
#
|
7
|
+
# Chef decided it was a good idea to just shellout inside of a resource.
|
8
|
+
# Not only is that a horrible fucking idea, but I got flak when I asked
|
9
|
+
# to change it. So we are just going to monkey patch the fucking thing so
|
10
|
+
# it does not shell out.
|
11
|
+
#
|
12
|
+
# @return [false]
|
13
|
+
#
|
14
|
+
def supports_pkgng?
|
15
|
+
false
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/chefspec/librarian.rb
CHANGED
@@ -25,7 +25,7 @@ module ChefSpec
|
|
25
25
|
#
|
26
26
|
def setup!
|
27
27
|
env = ::Librarian::Chef::Environment.new(project_path: Dir.pwd)
|
28
|
-
env.config_db.local['path'] = @tmpdir
|
28
|
+
@originalpath, env.config_db.local['path'] = env.config_db.local['path'], @tmpdir
|
29
29
|
::Librarian::Action::Resolve.new(env).run
|
30
30
|
::Librarian::Action::Install.new(env).run
|
31
31
|
|
@@ -33,9 +33,12 @@ module ChefSpec
|
|
33
33
|
end
|
34
34
|
|
35
35
|
#
|
36
|
-
# Remove the temporary directory.
|
36
|
+
# Remove the temporary directory and restore the librarian-chef cookbook path.
|
37
37
|
#
|
38
38
|
def teardown!
|
39
|
+
env = ::Librarian::Chef::Environment.new(project_path: Dir.pwd)
|
40
|
+
env.config_db.local['path'] = @originalpath
|
41
|
+
|
39
42
|
FileUtils.rm_rf(@tmpdir) if File.exists?(@tmpdir)
|
40
43
|
end
|
41
44
|
end
|
data/lib/chefspec/macros.rb
CHANGED
@@ -44,11 +44,11 @@ module ChefSpec
|
|
44
44
|
scope = self.is_a?(Class) ? self : self.class
|
45
45
|
|
46
46
|
metahash = scope.metadata
|
47
|
-
while metahash.has_key?(:
|
48
|
-
metahash = metahash[:
|
47
|
+
while metahash.has_key?(:parent_example_group)
|
48
|
+
metahash = metahash[:parent_example_group]
|
49
49
|
end
|
50
50
|
|
51
|
-
metahash[:
|
51
|
+
metahash[:description].to_s
|
52
52
|
end
|
53
53
|
|
54
54
|
#
|
@@ -4,6 +4,8 @@ module ChefSpec::Matchers
|
|
4
4
|
@resource = resource
|
5
5
|
|
6
6
|
if @resource
|
7
|
+
ChefSpec::Coverage.cover!(@resource)
|
8
|
+
|
7
9
|
actions = @resource.performed_actions
|
8
10
|
actions.empty? || actions == [:nothing]
|
9
11
|
else
|
@@ -15,7 +17,7 @@ module ChefSpec::Matchers
|
|
15
17
|
'do nothing'
|
16
18
|
end
|
17
19
|
|
18
|
-
def
|
20
|
+
def failure_message
|
19
21
|
if @resource
|
20
22
|
message = %|expected #{@resource} to do nothing, but the following |
|
21
23
|
message << %|actions were performed:|
|
@@ -35,7 +37,7 @@ module ChefSpec::Matchers
|
|
35
37
|
end
|
36
38
|
end
|
37
39
|
|
38
|
-
def
|
40
|
+
def failure_message_when_negated
|
39
41
|
if @resource
|
40
42
|
message = %|expected #{@resource} to do something, but no actions |
|
41
43
|
message << %|were performed.|
|
@@ -13,11 +13,11 @@ module ChefSpec::Matchers
|
|
13
13
|
%Q{include recipe "#{@recipe_name}"}
|
14
14
|
end
|
15
15
|
|
16
|
-
def
|
16
|
+
def failure_message
|
17
17
|
%Q{expected #{loaded_recipes.inspect} to include "#{@recipe_name}"}
|
18
18
|
end
|
19
19
|
|
20
|
-
def
|
20
|
+
def failure_message_when_negated
|
21
21
|
%Q{expected "#{@recipe_name}" to not be included}
|
22
22
|
end
|
23
23
|
|
@@ -7,16 +7,22 @@ module ChefSpec::Matchers
|
|
7
7
|
def matches?(link)
|
8
8
|
@link = link
|
9
9
|
|
10
|
-
@link
|
11
|
-
|
12
|
-
|
10
|
+
if @link
|
11
|
+
ChefSpec::Coverage.cover!(@link)
|
12
|
+
|
13
|
+
@link.is_a?(Chef::Resource::Link) &&
|
14
|
+
@link.performed_action?(:create) &&
|
15
|
+
@path === @link.to
|
16
|
+
else
|
17
|
+
false
|
18
|
+
end
|
13
19
|
end
|
14
20
|
|
15
21
|
def description
|
16
22
|
%Q{link to "#{@path}"}
|
17
23
|
end
|
18
24
|
|
19
|
-
def
|
25
|
+
def failure_message
|
20
26
|
if @link.nil?
|
21
27
|
%Q{expected "link[#{@path}]" with action :create to be in Chef run}
|
22
28
|
else
|
@@ -24,7 +30,7 @@ module ChefSpec::Matchers
|
|
24
30
|
end
|
25
31
|
end
|
26
32
|
|
27
|
-
def
|
33
|
+
def failure_message_when_negated
|
28
34
|
%Q{expected "#{@link}" to not link to "#{@path}"}
|
29
35
|
end
|
30
36
|
end
|
@@ -51,7 +51,7 @@ module ChefSpec::Matchers
|
|
51
51
|
message
|
52
52
|
end
|
53
53
|
|
54
|
-
def
|
54
|
+
def failure_message
|
55
55
|
if @resource
|
56
56
|
message = %Q{expected "#{@resource}" to notify "#{@expected_resource_type}[#{@expected_resource_name}]"}
|
57
57
|
message << " with action :#{@action}" if @action
|
@@ -77,7 +77,7 @@ module ChefSpec::Matchers
|
|
77
77
|
end
|
78
78
|
end
|
79
79
|
|
80
|
-
def
|
80
|
+
def failure_message_when_negated
|
81
81
|
if @resource
|
82
82
|
message = %Q{expected "#{@resource}" to not notify "#{@expected_resource_type}[#{@expected_resource_name}]"}
|
83
83
|
message << ", but it did."
|
@@ -6,7 +6,13 @@ module ChefSpec::Matchers
|
|
6
6
|
|
7
7
|
def matches?(runner)
|
8
8
|
@runner = runner
|
9
|
-
|
9
|
+
|
10
|
+
if resource
|
11
|
+
ChefSpec::Coverage.cover!(resource)
|
12
|
+
has_create_action? && matches_content?
|
13
|
+
else
|
14
|
+
false
|
15
|
+
end
|
10
16
|
end
|
11
17
|
|
12
18
|
def with_content(expected_content)
|
@@ -26,7 +32,7 @@ module ChefSpec::Matchers
|
|
26
32
|
message
|
27
33
|
end
|
28
34
|
|
29
|
-
def
|
35
|
+
def failure_message
|
30
36
|
message = %Q{expected Chef run to render "#{@path}"}
|
31
37
|
if @expected_content
|
32
38
|
message << " matching:"
|
@@ -41,7 +47,7 @@ module ChefSpec::Matchers
|
|
41
47
|
message
|
42
48
|
end
|
43
49
|
|
44
|
-
def
|
50
|
+
def failure_message_when_negated
|
45
51
|
message = %Q{expected file "#{@path}"}
|
46
52
|
if @expected_content
|
47
53
|
message << " matching:"
|
@@ -50,7 +50,7 @@ module ChefSpec::Matchers
|
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
53
|
-
def
|
53
|
+
def failure_message
|
54
54
|
if resource
|
55
55
|
if resource.performed_action?(@expected_action)
|
56
56
|
if unmatched_parameters.empty?
|
@@ -79,7 +79,7 @@ module ChefSpec::Matchers
|
|
79
79
|
end
|
80
80
|
end
|
81
81
|
|
82
|
-
def
|
82
|
+
def failure_message_when_negated
|
83
83
|
if resource
|
84
84
|
message = %Q{expected "#{resource.to_s}" actions #{resource.performed_actions.inspect} to not exist}
|
85
85
|
else
|
@@ -18,7 +18,7 @@ module ChefSpec::Matchers
|
|
18
18
|
%Q{have state attributes #{@expected_attrs.inspect}}
|
19
19
|
end
|
20
20
|
|
21
|
-
def
|
21
|
+
def failure_message
|
22
22
|
if @resource
|
23
23
|
"expected #{state_attrs.inspect} to equal #{@expected_attrs.inspect}"
|
24
24
|
else
|
@@ -32,7 +32,7 @@ module ChefSpec::Matchers
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
-
def
|
35
|
+
def failure_message_when_negated
|
36
36
|
if @resource
|
37
37
|
"expected #{state_attrs.inspect} to not equal " \
|
38
38
|
"#{@expected_attrs.inspect}"
|
@@ -52,12 +52,12 @@ module ChefSpec::Matchers
|
|
52
52
|
@instance.description
|
53
53
|
end
|
54
54
|
|
55
|
-
def
|
56
|
-
@instance.
|
55
|
+
def failure_message
|
56
|
+
@instance.failure_message
|
57
57
|
end
|
58
58
|
|
59
|
-
def
|
60
|
-
@instance.
|
59
|
+
def failure_message_when_negated
|
60
|
+
@instance.failure_message_when_negated
|
61
61
|
end
|
62
62
|
end
|
63
63
|
end
|
data/lib/chefspec/renderer.rb
CHANGED
@@ -108,7 +108,7 @@ module ChefSpec
|
|
108
108
|
def content_from_cookbook_file(chef_run, cookbook_file)
|
109
109
|
cookbook_name = cookbook_file.cookbook || cookbook_file.cookbook_name
|
110
110
|
cookbook = cookbook_collection(chef_run.node)[cookbook_name]
|
111
|
-
File.read(cookbook.preferred_filename_on_disk_location(chef_run.node, :files, cookbook_file.source
|
111
|
+
File.read(cookbook.preferred_filename_on_disk_location(chef_run.node, :files, cookbook_file.source))
|
112
112
|
end
|
113
113
|
|
114
114
|
# The cookbook collection for the current Chef run context. Handles
|
data/lib/chefspec/rspec.rb
CHANGED
data/lib/chefspec/runner.rb
CHANGED
@@ -80,6 +80,7 @@ module ChefSpec
|
|
80
80
|
Chef::Config[:cache_type] = 'Memory'
|
81
81
|
Chef::Config[:client_key] = nil
|
82
82
|
Chef::Config[:cookbook_path] = Array(options[:cookbook_path])
|
83
|
+
Chef::Config[:no_lazy_load] = true
|
83
84
|
Chef::Config[:role_path] = Array(options[:role_path])
|
84
85
|
Chef::Config[:force_logger] = true
|
85
86
|
Chef::Config[:solo] = true
|
@@ -270,7 +271,7 @@ module ChefSpec
|
|
270
271
|
calling_spec = kaller.find { |line| line =~ /\/spec/ }
|
271
272
|
raise Error::CookbookPathNotFound if calling_spec.nil?
|
272
273
|
|
273
|
-
bits = calling_spec.split(
|
274
|
+
bits = calling_spec.split(/:[0-9]/, 2).first.split(File::SEPARATOR)
|
274
275
|
spec_dir = bits.index('spec') || 0
|
275
276
|
|
276
277
|
File.expand_path(File.join(bits.slice(0, spec_dir), '..'))
|
data/lib/chefspec/server.rb
CHANGED
@@ -61,6 +61,13 @@ module ChefSpec
|
|
61
61
|
instance.send(m, *args, &block)
|
62
62
|
end
|
63
63
|
|
64
|
+
#
|
65
|
+
# RSpec 3 checks +respond_to?+ for some odd reason.
|
66
|
+
#
|
67
|
+
def self.respond_to_missing?(m, include_private = false)
|
68
|
+
instance.respond_to?(m, include_private) || super
|
69
|
+
end
|
70
|
+
|
64
71
|
#
|
65
72
|
# @macro entity
|
66
73
|
# @method create_$1(name, data = {})
|
@@ -105,11 +112,11 @@ module ChefSpec
|
|
105
112
|
# Convert it to JSON
|
106
113
|
data = JSON.fast_generate(data)
|
107
114
|
|
108
|
-
|
115
|
+
load_data(name, '#{key}', data)
|
109
116
|
end
|
110
117
|
|
111
118
|
def #{method}(name)
|
112
|
-
data =
|
119
|
+
data = get('#{key}', name)
|
113
120
|
json = JSON.parse(data)
|
114
121
|
|
115
122
|
if #{klass}.respond_to?(:json_create)
|
@@ -122,37 +129,45 @@ module ChefSpec
|
|
122
129
|
end
|
123
130
|
|
124
131
|
def #{key}
|
125
|
-
|
132
|
+
get('#{key}')
|
126
133
|
end
|
127
134
|
|
128
135
|
def has_#{method}?(name)
|
129
|
-
|
136
|
+
!get('#{key}', name).nil?
|
130
137
|
rescue ChefZero::DataStore::DataNotFoundError
|
131
138
|
false
|
132
139
|
end
|
133
140
|
EOH
|
134
141
|
end
|
135
142
|
|
143
|
+
entity :client, Chef::Client, 'clients'
|
144
|
+
entity :data_bag, Chef::DataBag, 'data'
|
145
|
+
entity :environment, Chef::Environment, 'environments'
|
146
|
+
entity :node, Chef::Node, 'nodes'
|
147
|
+
entity :role, Chef::Role, 'roles'
|
148
|
+
|
136
149
|
include Singleton
|
137
150
|
|
138
151
|
attr_reader :server
|
139
152
|
|
140
153
|
#
|
141
154
|
# Create a new instance of the +ChefSpec::Server+ singleton. This method
|
142
|
-
# also starts the Chef Zero server in the background
|
155
|
+
# also starts the Chef Zero server in the background under the organization
|
156
|
+
# "chefspec".
|
143
157
|
#
|
144
158
|
def initialize
|
145
159
|
@server = ChefZero::Server.new(
|
160
|
+
# Set the log level from RSpec, defaulting to warn
|
146
161
|
log_level: RSpec.configuration.log_level || :warn,
|
162
|
+
|
163
|
+
# Set a random port so ChefSpec may be run in multiple jobs
|
164
|
+
port: port,
|
165
|
+
|
166
|
+
# Disable the "old" way - this is actually +multi_tenant: true+
|
167
|
+
single_org: false,
|
147
168
|
)
|
148
169
|
end
|
149
170
|
|
150
|
-
entity :client, Chef::Client, 'clients'
|
151
|
-
entity :data_bag, Chef::DataBag, 'data'
|
152
|
-
entity :environment, Chef::Environment, 'environments'
|
153
|
-
entity :node, Chef::Node, 'nodes'
|
154
|
-
entity :role, Chef::Role, 'roles'
|
155
|
-
|
156
171
|
#
|
157
172
|
# Create a new data_bag on the Chef Server. This overrides the method
|
158
173
|
# created by {entity}
|
@@ -163,7 +178,7 @@ module ChefSpec
|
|
163
178
|
# the data to load into the data bag
|
164
179
|
#
|
165
180
|
def create_data_bag(name, data = {})
|
166
|
-
|
181
|
+
load_data(name, 'data', data)
|
167
182
|
end
|
168
183
|
|
169
184
|
#
|
@@ -197,7 +212,7 @@ module ChefSpec
|
|
197
212
|
data = JSON.fast_generate(data)
|
198
213
|
end
|
199
214
|
|
200
|
-
|
215
|
+
load_data(name, 'nodes', data)
|
201
216
|
end
|
202
217
|
|
203
218
|
#
|
@@ -217,6 +232,15 @@ module ChefSpec
|
|
217
232
|
end
|
218
233
|
end
|
219
234
|
|
235
|
+
#
|
236
|
+
# The URL where ChefZero is listening (including the organization).
|
237
|
+
#
|
238
|
+
# @return [String]
|
239
|
+
#
|
240
|
+
def chef_server_url
|
241
|
+
@chef_server_url ||= File.join(@server.url, 'organizations', organization)
|
242
|
+
end
|
243
|
+
|
220
244
|
#
|
221
245
|
# Start the Chef Zero server in the background, updating the +Chef::Config+
|
222
246
|
# with the proper +chef_server_url+.
|
@@ -224,7 +248,7 @@ module ChefSpec
|
|
224
248
|
def start!
|
225
249
|
unless @server.running?
|
226
250
|
@server.start_background
|
227
|
-
Chef::Config[:chef_server_url] =
|
251
|
+
Chef::Config[:chef_server_url] = chef_server_url
|
228
252
|
end
|
229
253
|
end
|
230
254
|
|
@@ -233,6 +257,7 @@ module ChefSpec
|
|
233
257
|
#
|
234
258
|
def reset!
|
235
259
|
@server.clear_data
|
260
|
+
@server.data_store.create_dir(['organizations'], organization)
|
236
261
|
end
|
237
262
|
|
238
263
|
#
|
@@ -246,6 +271,15 @@ module ChefSpec
|
|
246
271
|
|
247
272
|
private
|
248
273
|
|
274
|
+
#
|
275
|
+
# The name of the Chef organization.
|
276
|
+
#
|
277
|
+
# @return [String]
|
278
|
+
#
|
279
|
+
def organization
|
280
|
+
RSpec.configuration.organization
|
281
|
+
end
|
282
|
+
|
249
283
|
#
|
250
284
|
# The directory where any cache information (such as private keys) should
|
251
285
|
# be stored. This cache is destroyed at the end of the run.
|
@@ -260,16 +294,52 @@ module ChefSpec
|
|
260
294
|
#
|
261
295
|
# Shortcut method for loading data into Chef Zero.
|
262
296
|
#
|
263
|
-
# @param [String, Symbol] key
|
264
|
-
# the key to load
|
265
297
|
# @param [String] name
|
266
298
|
# the name or id of the item to load
|
299
|
+
# @param [String, Symbol] key
|
300
|
+
# the key to load
|
267
301
|
# @param [Hash] data
|
268
302
|
# the data for the object, which will be converted to JSON and uploaded
|
269
303
|
# to the server
|
270
304
|
#
|
271
|
-
def load_data(
|
272
|
-
@server.load_data(key
|
305
|
+
def load_data(name, key, data = {})
|
306
|
+
@server.load_data({ key => { name => data } }, organization)
|
307
|
+
end
|
308
|
+
|
309
|
+
#
|
310
|
+
# Get the path to an item in the data store.
|
311
|
+
#
|
312
|
+
def get(*args)
|
313
|
+
if args.size == 1
|
314
|
+
@server.data_store.list(with_organization(*args))
|
315
|
+
else
|
316
|
+
@server.data_store.get(with_organization(*args))
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
#
|
321
|
+
# Prefix the given args with the organization. This is used by the data
|
322
|
+
# store to fetch elements.
|
323
|
+
#
|
324
|
+
# @return [Array<String>]
|
325
|
+
#
|
326
|
+
def with_organization(*args)
|
327
|
+
['organizations', organization, *args]
|
328
|
+
end
|
329
|
+
|
330
|
+
#
|
331
|
+
# A randomly assigned, open port for run the Chef Zero server.
|
332
|
+
#
|
333
|
+
# @return [Fixnum]
|
334
|
+
#
|
335
|
+
def port
|
336
|
+
return @port if @port
|
337
|
+
|
338
|
+
@server = TCPServer.new('127.0.0.1', 0)
|
339
|
+
@port = @server.addr[1].to_i
|
340
|
+
@server.close
|
341
|
+
|
342
|
+
return @port
|
273
343
|
end
|
274
344
|
end
|
275
345
|
end
|
@@ -277,7 +347,8 @@ end
|
|
277
347
|
ChefSpec::Server.start!
|
278
348
|
|
279
349
|
RSpec.configure do |config|
|
280
|
-
config.
|
350
|
+
config.before(:each) { ChefSpec::Server.reset! }
|
351
|
+
config.after(:each) { ChefSpec::Server.reset! }
|
281
352
|
end
|
282
353
|
|
283
354
|
at_exit { ChefSpec::Server.stop! }
|