chefspec 0.6.1 → 0.7.0

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