chefspec 1.3.1 → 2.0.0

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