chefspec 1.3.1 → 2.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 499bad18b2da5ab00aedf8c46c95c6045e95f81c
4
+ data.tar.gz: f4e98dc5b9a45a149174f0d0e20b3c22e3781b00
5
+ SHA512:
6
+ metadata.gz: cd4ac9f716914dfc745cfa45f9461d714d2f8e487fd33d28f00e886d54be9f234c18e71c6799b3e92f90581d60bd73acdac7ad35870ee1f3bfbef302faf1266e
7
+ data.tar.gz: 90ba125ef150adc1643f5dfabe85a893f5501b63cc7a8fce4e815012f78d7825d2743aef0d59c7238c3fbf9e863e26e094a294afc86a069b11782b92d58785e0
@@ -0,0 +1,34 @@
1
+ class Chef
2
+ module ExpectException
3
+ class << self
4
+ def expected?(chef_message, exception, *args)
5
+ @b.call(chef_message, exception)
6
+ end
7
+
8
+ def expect(klass, message)
9
+ expect_block do |chef_message, exception|
10
+ match?(exception, klass, message)
11
+ end
12
+ end
13
+
14
+ def expect_block(&block)
15
+ @b = block
16
+ end
17
+
18
+ def clear
19
+ @b = lambda{|cm, e| false}
20
+ clear_seen
21
+ end
22
+
23
+ def clear_seen
24
+ @seen = []
25
+ end
26
+
27
+ def match?(exception, klass, message)
28
+ exception.class == klass and exception.message == message
29
+ end
30
+ end
31
+
32
+ clear
33
+ end
34
+ end
@@ -1,15 +1,10 @@
1
1
  if defined?(Chef::Formatters::Base)
2
2
  class Chef
3
3
  module Formatters
4
- # A specific formatter for Chef 11. This base for this formatter was
5
- # taken from Chef::Formatters:Min and all the output was then removed.
6
- #
7
- # @author Seth Vargo <sethvargo@gmail.com>
8
- class ChefSpec < Formatters::Base
4
+ class ChefSpec < Base
9
5
  cli_name(:chefspec)
10
6
 
11
- attr_reader :updated_resources
12
- attr_reader :updates_by_resource
7
+ attr_reader :updated_resources, :updates_by_resource
13
8
 
14
9
  def initialize(out, err)
15
10
  super
@@ -17,6 +12,10 @@ if defined?(Chef::Formatters::Base)
17
12
  @updates_by_resource = Hash.new {|h, k| h[k] = []}
18
13
  end
19
14
 
15
+ def error_expected?(message, exception, *args)
16
+ ExpectException.expected?(message, exception, *args)
17
+ end
18
+
20
19
  # Called at the very start of a Chef Run
21
20
  def run_start(version)
22
21
  puts "Starting Chef Client, version #{version}"
@@ -28,6 +27,7 @@ if defined?(Chef::Formatters::Base)
28
27
 
29
28
  # called at the end of a failed run
30
29
  def run_failed(exception)
30
+ return if error_expected?(:run_failed, exception)
31
31
  puts "chef client failed. #{@updated_resources.size} resources updated"
32
32
  end
33
33
 
@@ -48,7 +48,7 @@ if defined?(Chef::Formatters::Base)
48
48
 
49
49
  # Failed to register this client with the server.
50
50
  def registration_failed(node_name, exception, config)
51
- super
51
+ super unless error_expected?(:registration_failed, exception, config, node_name)
52
52
  end
53
53
 
54
54
  def node_load_start(node_name, config)
@@ -56,6 +56,11 @@ if defined?(Chef::Formatters::Base)
56
56
 
57
57
  # Failed to load node data from the server
58
58
  def node_load_failed(node_name, exception, config)
59
+ super unless error_expected?(:node_load_failed, exception)
60
+ end
61
+
62
+ def run_list_expand_failed(expanded_run_list, exception)
63
+ super unless error_expected?(:run_list_expand_failed, exception, expanded_run_list)
59
64
  end
60
65
 
61
66
  # Default and override attrs from roles have been computed, but not yet applied.
@@ -70,6 +75,11 @@ if defined?(Chef::Formatters::Base)
70
75
  # Called when there is an error getting the cookbook collection from the
71
76
  # server.
72
77
  def cookbook_resolution_failed(expanded_run_list, exception)
78
+ super unless error_expected?(:cookbook_resolution_failed, exception, expanded_run_list)
79
+ end
80
+
81
+ def cookbook_sync_failed(cookbooks, exception)
82
+ super unless error_expected?(:cookbook_sync_failed, exception, cookbooks)
73
83
  end
74
84
 
75
85
  # Called when the cookbook collection is returned from the server.
@@ -116,8 +126,28 @@ if defined?(Chef::Formatters::Base)
116
126
  def file_loaded(path)
117
127
  end
118
128
 
119
- def file_load_failed(path, exception)
120
- super
129
+ def file_load_failed(path, exception, message = :file_load_failed, &block)
130
+ super(path, exception, &block) unless error_expected?(message, exception, path)
131
+ end
132
+
133
+ def library_file_load_failed(path, exception)
134
+ file_load_failed(path, exception, :library_file_load_failed)
135
+ end
136
+
137
+ def lwrp_file_load_failed(path, exception)
138
+ file_load_failed(path, exception, :lwrp_file_load_failed)
139
+ end
140
+
141
+ def attribute_file_load_failed(path, exception)
142
+ file_load_failed(path, exception, :attribute_file_load_failed)
143
+ end
144
+
145
+ def definition_file_load_failed(path, exception)
146
+ file_load_failed(path, exception, :definition_file_load_failed)
147
+ end
148
+
149
+ def recipe_file_load_failed(path, exception)
150
+ file_load_failed(path, exception, :recipe_file_load_failed)
121
151
  end
122
152
 
123
153
  # Called when recipes have been loaded.
@@ -138,10 +168,12 @@ if defined?(Chef::Formatters::Base)
138
168
 
139
169
  # Called when a resource fails, but will retry.
140
170
  def resource_failed_retriable(resource, action, retry_count, exception)
171
+ super unless error_expected?(:resource_failed_retriable, exception, retry_count, action, resource)
141
172
  end
142
173
 
143
174
  # Called when a resource fails and will not be retried.
144
175
  def resource_failed(resource, action, exception)
176
+ super unless error_expected?(:resource, exception, exception, resource)
145
177
  end
146
178
 
147
179
  # Called when a resource action has been skipped b/c of a conditional
@@ -160,6 +192,10 @@ if defined?(Chef::Formatters::Base)
160
192
 
161
193
  ## TODO: callback for assertion fallback in why run
162
194
 
195
+ def recipe_not_found(exception)
196
+ super unless error_expected?(:recipe_not_found, exception)
197
+ end
198
+
163
199
  # Called when a change has been made to a resource. May be called multiple
164
200
  # times per resource, e.g., a file may have its content updated, and then
165
201
  # its permissions updated.
@@ -191,7 +227,6 @@ if defined?(Chef::Formatters::Base)
191
227
  # callback for it.
192
228
  def msg(message)
193
229
  end
194
-
195
230
  end
196
231
  end
197
232
  end
data/lib/chefspec.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'chef'
2
2
  require 'chef/formatters/chefspec'
3
+ require 'chef/expect_exception'
3
4
  require 'chefspec/chef_runner'
4
5
  require 'chefspec/version'
5
6
 
@@ -20,6 +21,7 @@ if defined?(RSpec)
20
21
  require 'chefspec/matchers/env'
21
22
  require 'chefspec/matchers/include_recipe'
22
23
  require 'chefspec/matchers/script'
24
+ require 'chefspec/matchers/python'
23
25
 
24
26
  require 'chefspec/helpers/describe'
25
27
  RSpec.configure do |c|
@@ -32,3 +34,15 @@ require 'chefspec/monkey_patches/conditional'
32
34
  require 'chefspec/monkey_patches/hash'
33
35
  require 'chefspec/monkey_patches/lwrp_base'
34
36
  require 'chefspec/monkey_patches/provider'
37
+
38
+ module ChefSpec
39
+ class << self
40
+ def chef_11?
41
+ Gem::Requirement.new('~> 11.0').satisfied_by?(Gem::Version.new(Chef::VERSION))
42
+ end
43
+
44
+ def chef_10?
45
+ Gem::Requirement.new('~> 10.0').satisfied_by?(Gem::Version.new(Chef::VERSION))
46
+ end
47
+ end
48
+ end
@@ -18,6 +18,20 @@ module ChefSpec
18
18
 
19
19
  @resources = []
20
20
 
21
+ @needs_formatter_registered = Chef::Config.respond_to?(:add_formatter)
22
+ @nfr_mutex = Mutex.new
23
+
24
+ def self.register_formatter
25
+ return unless @needs_formatter_registered
26
+ @nfr_mutex.synchronize do
27
+ return unless @needs_formatter_registered
28
+ @needs_formatter_registered = false
29
+ # As of Chef 11, Chef uses custom formatters which munge the RSpec output.
30
+ # This uses a custom formatter which basically tells Chef to shut up.
31
+ Chef::Config.add_formatter('chefspec')
32
+ end
33
+ end
34
+
21
35
  attr_accessor :resources
22
36
  attr_reader :step_into
23
37
  attr_reader :run_context
@@ -126,9 +140,7 @@ module ChefSpec
126
140
  @dummy_config = Tempfile.new 'chef-config'
127
141
  Chef::Config[:config_file] = @dummy_config.path
128
142
 
129
- # As of Chef 11, Chef uses custom formatters which munge the RSpec output.
130
- # This uses a custom formatter which basically tells Chef to shut up.
131
- Chef::Config.add_formatter('chefspec') if Chef::Config.respond_to?(:add_formatter)
143
+ self.class.register_formatter
132
144
 
133
145
  Chef::Log.verbose = true if Chef::Log.respond_to?(:verbose)
134
146
  Chef::Log.level(@options[:log_level])
@@ -188,7 +200,7 @@ module ChefSpec
188
200
  end
189
201
 
190
202
  FILE_RESOURCES = %w(directory cookbook_file file template link remote_directory remote_file)
191
- PACKAGE_RESOURCES = %w(package apt_package dpkg_package easy_install_package freebsd_package macports_package portage_package rpm_package chef_gem solaris_package yum_package zypper_package)
203
+ PACKAGE_RESOURCES = %w(package apt_package dpkg_package easy_install_package freebsd_package macports_package portage_package rpm_package chef_gem solaris_package yum_package zypper_package python_pip)
192
204
  SCRIPT_RESOURCES = %w(script powershell bash csh perl python ruby)
193
205
  MISC_RESOURCES = %w(cron env user execute service log route ruby_block git subversion group mount ohai ifconfig deploy http_request)
194
206
 
@@ -2,7 +2,11 @@ module ChefSpec
2
2
  module Helpers
3
3
  module Describe
4
4
  def described_recipe
5
- self.class.metadata[:example_group][:description_args].first
5
+ metahash = self.class.metadata
6
+ while metahash.has_key? :example_group
7
+ metahash = metahash[:example_group]
8
+ end
9
+ metahash[:description_args].first
6
10
  end
7
11
 
8
12
  def described_cookbook
@@ -22,7 +22,7 @@ module ChefSpec
22
22
 
23
23
  def expected_resource?(resource,command)
24
24
  resource_type(resource) == 'execute' &&
25
- resource.command == command
25
+ command === resource.command
26
26
  end
27
27
 
28
28
  def expected_attributes?(resource)
@@ -11,73 +11,72 @@ module ChefSpec
11
11
  end
12
12
  end
13
13
 
14
- RSpec::Matchers.define :create_remote_file do |path|
15
- match do |chef_run|
16
- if @attributes
17
- chef_run.resources.any? do |resource|
18
- expected_remote_file?(resource,path) &&
19
- expected_attributes?(resource)
20
- end
21
- else
22
- chef_run.resources.any? do |resource|
23
- expected_remote_file?(resource,path)
14
+ {:create_remote_file => [:create], :create_remote_file_if_missing => [:create_if_missing]}.each do |matcher, corr_action|
15
+ RSpec::Matchers.define matcher do |path|
16
+ match do |chef_run|
17
+ if @attributes
18
+ chef_run.resources.any? do |resource|
19
+ expected_remote_file?(resource,path,corr_action) &&
20
+ expected_attributes?(resource)
21
+ end
22
+ else
23
+ chef_run.resources.any? do |resource|
24
+ expected_remote_file?(resource,path,corr_action)
25
+ end
24
26
  end
25
27
  end
26
- end
27
28
 
28
- chain :with do |attributes|
29
- @attributes = attributes
30
- end
29
+ chain :with do |attributes|
30
+ @attributes = attributes
31
+ end
31
32
 
32
- def expected_remote_file?(resource,path)
33
- # The resource action *might* be an array!
34
- # (see https://tickets.opscode.com/browse/CHEF-2094)
35
- action = resource.action.is_a?(Array) ? resource.action.first :
36
- resource.action
37
- resource_type(resource) == 'remote_file' &&
38
- resource.path == path &&
39
- action.to_sym == :create
40
- end
33
+ def expected_remote_file?(resource,path,corr_action)
34
+ resource_type(resource) == 'remote_file' &&
35
+ resource.path == path &&
36
+ !(corr_action & Array(resource.action).map(&:to_sym)).empty?
37
+ end
41
38
 
42
- def expected_attributes?(resource)
43
- @attributes.all? do |attribute,expected|
44
- actual = resource.send(attribute)
45
- attribute.to_sym == :source ? equal_source?(actual, expected) :
46
- actual == expected
39
+ def expected_attributes?(resource)
40
+ @attributes.all? do |attribute,expected|
41
+ actual = resource.send(attribute)
42
+ attribute.to_sym == :source ? equal_source?(actual, expected) :
43
+ actual == expected
44
+ end
47
45
  end
48
- end
49
46
 
50
- # Compare two remote_file source attributes for equality.
51
- #
52
- # @param actual [String, Array<String>] The actual source.
53
- # @param expected [String, Array<String>] The expected source.
54
- # @return [Boolean] true if they are equal or false if not.
55
- def equal_source?(actual, expected)
56
- # NOTE: Chef stores the source attribute internally as an array since
57
- # version 11 in order to support mirrors.
58
- # (see http://docs.opscode.com/breaking_changes_chef_11.html#remote-file-mirror-support-may-break-subclasses)
47
+ # Compare two remote_file source attributes for equality.
48
+ #
49
+ # @param actual [String, Array<String>] The actual source.
50
+ # @param expected [String, Array<String>] The expected source.
51
+ # @return [Boolean] true if they are equal or false if not.
52
+ def equal_source?(actual, expected)
53
+ # NOTE: Chef stores the source attribute internally as an array since
54
+ # version 11 in order to support mirrors.
55
+ # (see http://docs.opscode.com/breaking_changes_chef_11.html#remote-file-mirror-support-may-break-subclasses)
59
56
 
60
- # Handle wrong formated expectation for Chef versions >= 11.
61
- if actual.is_a?(Array) && expected.is_a?(String)
62
- actual == [expected]
57
+ # Handle wrong formated expectation for Chef versions >= 11.
58
+ if actual.is_a?(Array) && expected.is_a?(String)
59
+ actual == [expected]
63
60
 
64
- # Handle wrong formated expectation for Chef versions < 11.
65
- elsif actual.is_a?(String) && expected.is_a?(Array)
66
- [actual] == expected
61
+ # Handle wrong formated expectation for Chef versions < 11.
62
+ elsif actual.is_a?(String) && expected.is_a?(Array)
63
+ [actual] == expected
67
64
 
68
- # Else assume the actual matches the expected type (String or Array).
69
- else
70
- actual == expected
65
+ # Else assume the actual matches the expected type (String or Array).
66
+ else
67
+ actual == expected
68
+ end
71
69
  end
72
- end
73
70
 
74
- failure_message_for_should do |actual|
75
- message = "No remote_file named '#{path}' found"
76
- message << " with:\n#{@attributes}" unless @attributes.nil?
77
- end
71
+ failure_message_for_should do |actual|
72
+ message = "No remote_file named '#{path}' for action #{corr_action} found"
73
+ message << " with:\n#{@attributes}" unless @attributes.nil?
74
+ message
75
+ end
78
76
 
79
- failure_message_for_should_not do |actual|
80
- "Found remote_file named '#{path}' that should not exist."
77
+ failure_message_for_should_not do |actual|
78
+ "Found remote_file named '#{path}' that should not exist."
79
+ end
81
80
  end
82
81
  end
83
82
  end
@@ -2,34 +2,30 @@ require 'chefspec/matchers/shared'
2
2
 
3
3
  module ChefSpec
4
4
  module Matchers
5
- RSpec::Matchers.define :create_file_with_content do |path, content|
5
+ RSpec::Matchers.define :create_file_with_content do |path, expected|
6
6
  match do |chef_run|
7
- chef_run.resources.any? do |resource|
8
- if resource.name == path
9
- if (Array(resource.action).map { |action| action.to_sym } & [:create, :create_if_missing]).any?
10
- case resource_type(resource)
11
- when 'template'
12
- template_finder = template_finder(chef_run.run_context, resource, chef_run.node)
13
- @actual_content = render(resource, chef_run.node, template_finder)
14
- when 'file'
15
- @actual_content = resource.content
16
- when 'cookbook_file'
17
- cookbook_name = resource.cookbook || resource.cookbook_name
18
- cookbook = chef_run.run_context.cookbook_collection[cookbook_name]
19
- @actual_content = File.read(cookbook.preferred_filename_on_disk_location(chef_run.node, :files, resource.source, resource.path))
20
- end
7
+ chef_run.resources.select { |resource| resource.name == path }.any? do |resource|
8
+ unless ([:create, :create_if_missing] & Array(resource.action).map(&:to_sym)).empty?
9
+ @actual_content = case resource_type(resource)
10
+ when 'template'
11
+ content_from_template(chef_run, resource)
12
+ when 'file'
13
+ content_from_file(chef_run, resource)
14
+ when 'cookbook_file'
15
+ content_from_cookbook_file(chef_run, resource)
16
+ end
21
17
 
22
- if content.is_a?(Regexp)
23
- @actual_content.to_s =~ content
24
- else
25
- @actual_content.to_s.include? content
26
- end
18
+ if expected.is_a?(Regexp)
19
+ @actual_content.to_s =~ expected
20
+ else
21
+ @actual_content.to_s.include?(expected)
27
22
  end
28
23
  end
29
24
  end
30
25
  end
26
+
31
27
  failure_message_for_should do |actual|
32
- "File content:\n#{@actual_content} does not match expected:\n#{content}"
28
+ "File content:\n#{@actual_content} does not match expected:\n#{expected}"
33
29
  end
34
30
  end
35
31
  end
@@ -2,11 +2,7 @@ require 'chefspec/matchers/shared'
2
2
 
3
3
  module ChefSpec
4
4
  module Matchers
5
-
6
- CHEF_GEM_SUPPORTED = defined?(::Chef::Resource::ChefGem)
7
- PACKAGE_TYPES = [:package, :gem_package, :chef_gem, :yum_package]
8
- PACKAGE_TYPES << :chef_gem if CHEF_GEM_SUPPORTED
9
- define_resource_matchers([:install, :remove, :upgrade, :purge], PACKAGE_TYPES, :package_name)
5
+ define_resource_matchers([:install, :remove, :upgrade, :purge], [:package, :gem_package, :chef_gem, :yum_package], :package_name)
10
6
 
11
7
  RSpec::Matchers.define :install_package_at_version do |package_name, version|
12
8
  match do |chef_run|
@@ -15,6 +11,7 @@ module ChefSpec
15
11
  end
16
12
  end
17
13
  end
14
+
18
15
  RSpec::Matchers.define :install_yum_package_at_version do |package_name, version|
19
16
  match do |chef_run|
20
17
  chef_run.resources.any? do |resource|
@@ -22,6 +19,7 @@ module ChefSpec
22
19
  end
23
20
  end
24
21
  end
22
+
25
23
  RSpec::Matchers.define :install_gem_package_at_version do |package_name, version|
26
24
  match do |chef_run|
27
25
  chef_run.resources.any? do |resource|
@@ -29,12 +27,13 @@ module ChefSpec
29
27
  end
30
28
  end
31
29
  end
30
+
32
31
  RSpec::Matchers.define :install_chef_gem_at_version do |package_name, version|
33
32
  match do |chef_run|
34
33
  chef_run.resources.any? do |resource|
35
34
  resource_type(resource) == 'chef_gem' and resource.package_name == package_name and resource.action.to_s.include? 'install' and resource.version == version
36
35
  end
37
36
  end
38
- end if CHEF_GEM_SUPPORTED
37
+ end
39
38
  end
40
39
  end
@@ -0,0 +1,7 @@
1
+ require 'chefspec/matchers/shared'
2
+
3
+ module ChefSpec
4
+ module Matchers
5
+ define_resource_matchers([:install, :upgrade, :remove, :purge], [:python_pip], :name)
6
+ end
7
+ end
@@ -5,9 +5,9 @@ module ChefSpec
5
5
  RSpec::Matchers.define :execute_ruby_block do |block_name|
6
6
  match do |chef_run|
7
7
  chef_run.resources.any? do |resource|
8
- resource_type(resource) == 'ruby_block' and resource.name == block_name
8
+ resource_type(resource) == 'ruby_block' and block_name === resource.name
9
9
  end
10
10
  end
11
11
  end
12
12
  end
13
- end
13
+ end
@@ -3,6 +3,7 @@ begin
3
3
  require 'chef/provider/template_finder'
4
4
  rescue LoadError
5
5
  end
6
+
6
7
  # Given a resource return the unqualified type it is
7
8
  #
8
9
  # @param [String] resource A Chef Resource
@@ -29,10 +30,11 @@ def define_resource_matchers(actions, resource_types, name_attribute)
29
30
  RSpec::Matchers.define "#{action}_#{resource_type}".to_sym do |name|
30
31
  match do |chef_run|
31
32
  accepted_types = [resource_type.to_s]
32
- accepted_types << 'template' if action.to_s == 'create' and resource_type.to_s == 'file'
33
+ accepted_types += ['template', 'cookbook_file'] if action.to_s == 'create' and resource_type.to_s == 'file'
33
34
  chef_run.resources.any? do |resource|
34
- accepted_types.include? resource_type(resource) and resource.send(name_attribute) == name and
35
- resource_actions(resource).include? action.to_s
35
+ (accepted_types.include? resource_type(resource) and
36
+ name === resource.send(name_attribute) and
37
+ resource_actions(resource).include? action.to_s)
36
38
  end
37
39
  end
38
40
  failure_message_for_should do |actual|
@@ -45,39 +47,83 @@ def define_resource_matchers(actions, resource_types, name_attribute)
45
47
  end
46
48
  end
47
49
 
48
- # Render a template.
50
+ # Compute the contents of a template using Chef's templating logic.
51
+ #
52
+ # @param [Chef::RunContext] chef_run
53
+ # the run context for the node
54
+ # @param [Chef::Provider::Template] template
55
+ # the template resource
49
56
  #
50
- # @param [Chef::Resource::Template] template The template to render
51
- # @param [Chef::Node] node The node which may be required to render the template
52
- # @param [Chef::Provider::TemplateFinder] a TemplateFinder use for rendering templates containing partials
53
- # @return [String] The result result of rendering the template
54
- def render(template, node, template_finder)
55
- # Duplicates functionality in the Chef Template provider
56
- context = {}; context.merge!(template.variables)
57
- context[:node] = node
58
- unless template_finder.nil?
59
- context[:template_finder] = template_finder
60
- Erubis::Context.send(:include, Chef::Mixin::Template::ChefContext)
57
+ # @return [String]
58
+ def content_from_template(chef_run, template)
59
+ cookbook_name = template.cookbook || template.cookbook_name
60
+ template_location = cookbook_collection(chef_run.node)[cookbook_name].preferred_filename_on_disk_location(chef_run.node, :templates, template.source)
61
+
62
+ if Chef::Mixin::Template.const_defined?(:TemplateContext) # Chef 11+
63
+ template_context = Chef::Mixin::Template::TemplateContext.new([])
64
+ template_context.update({
65
+ :node => chef_run.node,
66
+ :template_finder => template_finder(chef_run, cookbook_name),
67
+ }.merge(template.variables))
68
+ template_context.render_template(template_location)
69
+ else
70
+ template.provider.new(template, chef_run.run_context).send(:render_with_context, template_location) do |file|
71
+ File.read(file.path)
72
+ end
61
73
  end
62
- Erubis::Eruby.new(IO.read(template_path(template, node))).evaluate(context)
63
74
  end
64
75
 
65
- # Given a template, return the path on disk.
76
+ # Get the contents of a file resource.
66
77
  #
67
- # @param [Chef::Resource::Template] template The template
68
- # @return [String] The path on disk
69
- def template_path(template, node)
70
- cookbook_name = template.cookbook || template.cookbook_name
78
+ # @param [Chef::RunContext] chef_run
79
+ # the run context for the node
80
+ # @param [Chef::Provider::File] file
81
+ # the file resource
82
+ #
83
+ # @return [String]
84
+ def content_from_file(chef_run, file)
85
+ file.content
86
+ end
87
+
88
+ # Get the contents of a cookbook file using Chef.
89
+ #
90
+ # @param [Chef::RunContext] chef_run
91
+ # the run context for the node
92
+ # @param [Chef::Provider::CookbookFile] cookbook_file
93
+ # the file resource
94
+ def content_from_cookbook_file(chef_run, cookbook_file)
95
+ cookbook_name = cookbook_file.cookbook || cookbook_file.cookbook_name
96
+ cookbook = chef_run.run_context.cookbook_collection[cookbook_name]
97
+ File.read(cookbook.preferred_filename_on_disk_location(chef_run.node, :files, cookbook_file.source, cookbook_file.path))
98
+ end
99
+
100
+ # The cookbook collection for the current Chef run context. Handles
101
+ # the differing cases between Chef 10 and Chef 11.
102
+ #
103
+ # @param [Chef::Node] node
104
+ # the Chef node to get the cookbook collection from
105
+ #
106
+ # @return [Array<Chef::Cookbook>]
107
+ def cookbook_collection(node)
71
108
  if node.respond_to?(:run_context)
72
- cookbook = node.run_context.cookbook_collection[cookbook_name] # Chef 11+
109
+ node.run_context.cookbook_collection # Chef 11+
73
110
  else
74
- cookbook = node.cookbook_collection[cookbook_name] # Chef 10 and lower
111
+ node.cookbook_collection # Chef 10
75
112
  end
76
- cookbook.preferred_filename_on_disk_location(node, :templates, template.source)
77
113
  end
78
114
 
79
- def template_finder(run_context, template, node)
80
- if Chef::Provider.const_defined?(:TemplateFinder)
81
- Chef::Provider::TemplateFinder.new(run_context,template.cookbook_name, node)
115
+ # Return a new instance of the TemplateFinder if we are running on Chef 11.
116
+ #
117
+ # @param [Chef::RunContext] chef_run
118
+ # the run context for the noe
119
+ # @param [String] cookbook_name
120
+ # the name of the cookbook
121
+ #
122
+ # @return [Chef::Provider::TemplateFinder, nil]
123
+ def template_finder(chef_run, cookbook_name)
124
+ if Chef::Provider.const_defined?(:TemplateFinder) # Chef 11+
125
+ Chef::Provider::TemplateFinder.new(chef_run.run_context, cookbook_name, chef_run.node)
126
+ else
127
+ nil
82
128
  end
83
129
  end
@@ -134,13 +134,6 @@ module ChefSpec
134
134
  resources.select{|r| r.resource_name == type}
135
135
  end
136
136
 
137
- def cookbook_file_content(file_resource)
138
- file = cookbook_files(file_resource.cookbook_name).find do |f|
139
- Pathname.new(f).basename.to_s == file_resource.path
140
- end
141
- File.read(file)
142
- end
143
-
144
137
  def cookbook_files(cookbook)
145
138
  run_context.cookbook_collection[cookbook].file_filenames
146
139
  end
@@ -150,11 +143,11 @@ module ChefSpec
150
143
  f.path == file.path &&
151
144
  case f.resource_name
152
145
  when :cookbook_file
153
- cookbook_file_content(f)
146
+ content_from_cookbook_file(chef_run, f)
154
147
  when :file
155
- f.content
148
+ content_from_file(chef_run, f)
156
149
  when :template
157
- render(f, node, template_finder(run_context, f, node))
150
+ content_from_template(chef_run, f)
158
151
  else raise NotImplementedError,
159
152
  ":#{f.resource_name} not supported for comparison"
160
153
  end.include?(content)
@@ -179,6 +172,7 @@ module ChefSpec
179
172
  :cookbook_path => default_cookbook_path).converge recipe_for_module(spec_mod)
180
173
  override_minitest_resources(chef_run.run_context, spec_mod)
181
174
  override_minitest_assertions(chef_run)
175
+ share_object(spec_mod, :chef_run, chef_run)
182
176
  share_object(spec_mod, :node, chef_run.node)
183
177
  share_object(spec_mod, :resources, chef_run.resources)
184
178
  share_object(spec_mod, :run_context, chef_run.run_context)
@@ -1,14 +1,21 @@
1
1
  # Ruby stdlib Hash class
2
2
  class Hash
3
-
4
3
  # Monkey-patch to stdlib Hash to give us Mash style lookup
5
- # @param [Symbol] method_id The method name
6
- def method_missing(method_id, *)
7
- key = method_id.id2name
8
- if has_key?(key)
9
- self[key]
10
- elsif has_key?(key.to_sym)
11
- self[key.to_sym]
4
+ def method_missing(m, *args, &block)
5
+ if has_key?(m.to_sym)
6
+ self[m.to_sym]
7
+ elsif has_key?(m.to_s)
8
+ self[m.to_s]
9
+ else
10
+ super
11
+ end
12
+ end
13
+
14
+ # Monkey-patch to stdlib Hash to correspond to Mash-style lookup
15
+ # @see {Hash#respond_to?}
16
+ def respond_to?(m)
17
+ if has_key?(m.to_sym) || has_key?(m.to_s)
18
+ true
12
19
  else
13
20
  super
14
21
  end
@@ -1,4 +1,4 @@
1
1
  module ChefSpec
2
2
  # The gem version
3
- VERSION = '1.3.1'
3
+ VERSION = '2.0.0'
4
4
  end
metadata CHANGED
@@ -1,90 +1,74 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chefspec
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.1
5
- prerelease:
4
+ version: 2.0.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Andrew Crump
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-06-11 00:00:00.000000000 Z
11
+ date: 2013-08-22 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: chef
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - '>='
20
18
  - !ruby/object:Gem::Version
21
19
  version: '10.0'
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
24
+ - - '>='
28
25
  - !ruby/object:Gem::Version
29
26
  version: '10.0'
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: erubis
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ! '>='
31
+ - - '>='
36
32
  - !ruby/object:Gem::Version
37
33
  version: '0'
38
34
  type: :runtime
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ! '>='
38
+ - - '>='
44
39
  - !ruby/object:Gem::Version
45
40
  version: '0'
46
41
  - !ruby/object:Gem::Dependency
47
42
  name: fauxhai
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
- - - ! '>='
52
- - !ruby/object:Gem::Version
53
- version: 0.1.1
54
- - - <
45
+ - - ~>
55
46
  - !ruby/object:Gem::Version
56
- version: '2.0'
47
+ version: '1.1'
57
48
  type: :runtime
58
49
  prerelease: false
59
50
  version_requirements: !ruby/object:Gem::Requirement
60
- none: false
61
51
  requirements:
62
- - - ! '>='
63
- - !ruby/object:Gem::Version
64
- version: 0.1.1
65
- - - <
52
+ - - ~>
66
53
  - !ruby/object:Gem::Version
67
- version: '2.0'
54
+ version: '1.1'
68
55
  - !ruby/object:Gem::Dependency
69
56
  name: minitest-chef-handler
70
57
  requirement: !ruby/object:Gem::Requirement
71
- none: false
72
58
  requirements:
73
- - - ! '>='
59
+ - - '>='
74
60
  - !ruby/object:Gem::Version
75
61
  version: 0.6.0
76
62
  type: :runtime
77
63
  prerelease: false
78
64
  version_requirements: !ruby/object:Gem::Requirement
79
- none: false
80
65
  requirements:
81
- - - ! '>='
66
+ - - '>='
82
67
  - !ruby/object:Gem::Version
83
68
  version: 0.6.0
84
69
  - !ruby/object:Gem::Dependency
85
70
  name: rspec
86
71
  requirement: !ruby/object:Gem::Requirement
87
- none: false
88
72
  requirements:
89
73
  - - ~>
90
74
  - !ruby/object:Gem::Version
@@ -92,7 +76,6 @@ dependencies:
92
76
  type: :runtime
93
77
  prerelease: false
94
78
  version_requirements: !ruby/object:Gem::Requirement
95
- none: false
96
79
  requirements:
97
80
  - - ~>
98
81
  - !ruby/object:Gem::Version
@@ -100,105 +83,94 @@ dependencies:
100
83
  - !ruby/object:Gem::Dependency
101
84
  name: rake
102
85
  requirement: !ruby/object:Gem::Requirement
103
- none: false
104
86
  requirements:
105
- - - ! '>='
87
+ - - '>='
106
88
  - !ruby/object:Gem::Version
107
89
  version: '0'
108
90
  type: :development
109
91
  prerelease: false
110
92
  version_requirements: !ruby/object:Gem::Requirement
111
- none: false
112
93
  requirements:
113
- - - ! '>='
94
+ - - '>='
114
95
  - !ruby/object:Gem::Version
115
96
  version: '0'
116
97
  - !ruby/object:Gem::Dependency
117
98
  name: yard
118
99
  requirement: !ruby/object:Gem::Requirement
119
- none: false
120
100
  requirements:
121
101
  - - ~>
122
102
  - !ruby/object:Gem::Version
123
- version: 0.8.1
103
+ version: '0.8'
124
104
  type: :development
125
105
  prerelease: false
126
106
  version_requirements: !ruby/object:Gem::Requirement
127
- none: false
128
107
  requirements:
129
108
  - - ~>
130
109
  - !ruby/object:Gem::Version
131
- version: 0.8.1
110
+ version: '0.8'
132
111
  - !ruby/object:Gem::Dependency
133
112
  name: aruba
134
113
  requirement: !ruby/object:Gem::Requirement
135
- none: false
136
114
  requirements:
137
115
  - - ~>
138
116
  - !ruby/object:Gem::Version
139
- version: 0.4.11
117
+ version: '0.5'
140
118
  type: :development
141
119
  prerelease: false
142
120
  version_requirements: !ruby/object:Gem::Requirement
143
- none: false
144
121
  requirements:
145
122
  - - ~>
146
123
  - !ruby/object:Gem::Version
147
- version: 0.4.11
124
+ version: '0.5'
148
125
  - !ruby/object:Gem::Dependency
149
126
  name: cucumber
150
127
  requirement: !ruby/object:Gem::Requirement
151
- none: false
152
128
  requirements:
153
129
  - - ~>
154
130
  - !ruby/object:Gem::Version
155
- version: 1.2.0
131
+ version: '1.3'
156
132
  type: :development
157
133
  prerelease: false
158
134
  version_requirements: !ruby/object:Gem::Requirement
159
- none: false
160
135
  requirements:
161
136
  - - ~>
162
137
  - !ruby/object:Gem::Version
163
- version: 1.2.0
138
+ version: '1.3'
164
139
  - !ruby/object:Gem::Dependency
165
140
  name: i18n
166
141
  requirement: !ruby/object:Gem::Requirement
167
- none: false
168
142
  requirements:
169
143
  - - ~>
170
144
  - !ruby/object:Gem::Version
171
- version: 0.6.1
145
+ version: '0.6'
172
146
  type: :development
173
147
  prerelease: false
174
148
  version_requirements: !ruby/object:Gem::Requirement
175
- none: false
176
149
  requirements:
177
150
  - - ~>
178
151
  - !ruby/object:Gem::Version
179
- version: 0.6.1
152
+ version: '0.6'
180
153
  - !ruby/object:Gem::Dependency
181
154
  name: simplecov
182
155
  requirement: !ruby/object:Gem::Requirement
183
- none: false
184
156
  requirements:
185
157
  - - ~>
186
158
  - !ruby/object:Gem::Version
187
- version: 0.7.1
159
+ version: '0.7'
188
160
  type: :development
189
161
  prerelease: false
190
162
  version_requirements: !ruby/object:Gem::Requirement
191
- none: false
192
163
  requirements:
193
164
  - - ~>
194
165
  - !ruby/object:Gem::Version
195
- version: 0.7.1
166
+ version: '0.7'
196
167
  description: Write RSpec examples for Opscode Chef recipes
197
168
  email:
198
169
  executables: []
199
170
  extensions: []
200
171
  extra_rdoc_files: []
201
172
  files:
173
+ - lib/chef/expect_exception.rb
202
174
  - lib/chef/formatters/chefspec.rb
203
175
  - lib/chef/knife/cookbook_create_specs.rb
204
176
  - lib/chefspec/chef_runner.rb
@@ -214,6 +186,7 @@ files:
214
186
  - lib/chefspec/matchers/log.rb
215
187
  - lib/chefspec/matchers/notifications.rb
216
188
  - lib/chefspec/matchers/package.rb
189
+ - lib/chefspec/matchers/python.rb
217
190
  - lib/chefspec/matchers/ruby_block.rb
218
191
  - lib/chefspec/matchers/script.rb
219
192
  - lib/chefspec/matchers/service.rb
@@ -229,33 +202,26 @@ files:
229
202
  homepage: http://acrmp.github.com/chefspec
230
203
  licenses:
231
204
  - MIT
205
+ metadata: {}
232
206
  post_install_message:
233
207
  rdoc_options: []
234
208
  require_paths:
235
209
  - lib
236
210
  required_ruby_version: !ruby/object:Gem::Requirement
237
- none: false
238
211
  requirements:
239
- - - ! '>='
212
+ - - '>='
240
213
  - !ruby/object:Gem::Version
241
- version: '0'
242
- segments:
243
- - 0
244
- hash: 1265930440020953415
214
+ version: '1.9'
245
215
  required_rubygems_version: !ruby/object:Gem::Requirement
246
- none: false
247
216
  requirements:
248
- - - ! '>='
217
+ - - '>='
249
218
  - !ruby/object:Gem::Version
250
219
  version: '0'
251
- segments:
252
- - 0
253
- hash: 1265930440020953415
254
220
  requirements: []
255
221
  rubyforge_project:
256
- rubygems_version: 1.8.23
222
+ rubygems_version: 2.0.3
257
223
  signing_key:
258
- specification_version: 3
259
- summary: chefspec-1.3.1
224
+ specification_version: 4
225
+ summary: chefspec-2.0.0
260
226
  test_files: []
261
227
  has_rdoc: