halite 1.8.1 → 1.8.2

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.
Files changed (43) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +48 -22
  3. data/CHANGELOG.md +4 -0
  4. data/gemfiles/chef-12.16.gemfile +19 -0
  5. data/gemfiles/chef-12.17.gemfile +19 -0
  6. data/gemfiles/chef-12.18.gemfile +19 -0
  7. data/gemfiles/chef-12.19.gemfile +19 -0
  8. data/gemfiles/chef-12.20.gemfile +19 -0
  9. data/gemfiles/chef-12.21.gemfile +19 -0
  10. data/gemfiles/chef-12.gemfile +2 -2
  11. data/gemfiles/chef-13.0.gemfile +19 -0
  12. data/gemfiles/chef-13.1.gemfile +19 -0
  13. data/gemfiles/chef-13.10.gemfile +19 -0
  14. data/gemfiles/chef-13.2.gemfile +19 -0
  15. data/gemfiles/chef-13.3.gemfile +19 -0
  16. data/gemfiles/chef-13.4.gemfile +19 -0
  17. data/gemfiles/{chef-12.0.gemfile → chef-13.5.gemfile} +2 -2
  18. data/gemfiles/{chef-12.1.gemfile → chef-13.6.gemfile} +2 -2
  19. data/gemfiles/chef-13.7.gemfile +19 -0
  20. data/gemfiles/{chef-12.2.gemfile → chef-13.8.gemfile} +2 -2
  21. data/gemfiles/{chef-12.3.gemfile → chef-13.9.gemfile} +2 -2
  22. data/gemfiles/chef-13.gemfile +2 -2
  23. data/gemfiles/chef-14.0.gemfile +19 -0
  24. data/gemfiles/chef-14.1.gemfile +19 -0
  25. data/gemfiles/chef-14.2.gemfile +19 -0
  26. data/gemfiles/chef-14.3.gemfile +19 -0
  27. data/gemfiles/chef-14.4.gemfile +19 -0
  28. data/gemfiles/{chef-12.4.0.gemfile → chef-14.gemfile} +2 -2
  29. data/lib/halite/spec_helper.rb +37 -37
  30. data/lib/halite/spec_helper/patcher.rb +6 -129
  31. data/lib/halite/spec_helper/runner.rb +30 -35
  32. data/lib/halite/version.rb +1 -1
  33. data/spec/example_resources/custom.rb +29 -0
  34. data/spec/example_resources/simple.rb +4 -10
  35. data/spec/runner_spec.rb +17 -55
  36. data/spec/spec_helper.rb +2 -0
  37. data/spec/spec_helper_spec.rb +34 -12
  38. metadata +28 -13
  39. data/gemfiles/chef-12.4.gemfile +0 -19
  40. data/gemfiles/chef-12.5.gemfile +0 -19
  41. data/gemfiles/chef-12.6.gemfile +0 -19
  42. data/gemfiles/chef-12.7.gemfile +0 -19
  43. data/gemfiles/chef-13.7.16.gemfile +0 -21
@@ -0,0 +1,19 @@
1
+ #
2
+ # Copyright 2018, Noah Kantrowitz
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+ eval_gemfile File.expand_path('../../Gemfile', __FILE__)
18
+
19
+ gem 'chef', '~> 14.0.202'
@@ -0,0 +1,19 @@
1
+ #
2
+ # Copyright 2018, Noah Kantrowitz
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+ eval_gemfile File.expand_path('../../Gemfile', __FILE__)
18
+
19
+ gem 'chef', '~> 14.1.12'
@@ -0,0 +1,19 @@
1
+ #
2
+ # Copyright 2018, Noah Kantrowitz
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+ eval_gemfile File.expand_path('../../Gemfile', __FILE__)
18
+
19
+ gem 'chef', '~> 14.2.0'
@@ -0,0 +1,19 @@
1
+ #
2
+ # Copyright 2018, Noah Kantrowitz
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+ eval_gemfile File.expand_path('../../Gemfile', __FILE__)
18
+
19
+ gem 'chef', '~> 14.3.37'
@@ -0,0 +1,19 @@
1
+ #
2
+ # Copyright 2018, Noah Kantrowitz
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+ eval_gemfile File.expand_path('../../Gemfile', __FILE__)
18
+
19
+ gem 'chef', '~> 14.4.56'
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright 2015, Noah Kantrowitz
2
+ # Copyright 2018, Noah Kantrowitz
3
3
  #
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
5
5
  # you may not use this file except in compliance with the License.
@@ -16,4 +16,4 @@
16
16
 
17
17
  eval_gemfile File.expand_path('../../Gemfile', __FILE__)
18
18
 
19
- gem 'chef', '12.4.0'
19
+ gem 'chef', '~> 14.4'
@@ -55,6 +55,8 @@ module Halite
55
55
  autoload :Patcher, 'halite/spec_helper/patcher'
56
56
  autoload :Runner, 'halite/spec_helper/runner'
57
57
  extend RSpec::SharedContext
58
+ def self.described_class; nil; end
59
+ include ChefSpec::API
58
60
 
59
61
  # @!attribute [r] step_into
60
62
  # Resource names to step in to when running this example.
@@ -91,29 +93,36 @@ module Halite
91
93
  # @example Enable Fauxhai attributes
92
94
  # let(:chefspec_options) { {platform: 'ubuntu', version: '12.04'} }
93
95
  let(:chefspec_options) { Hash.new }
94
- # @!attribute [r] chef_runner
95
- # ChefSpec runner for this example.
96
- # @return [ChefSpec::SoloRunner]
97
- let(:chef_runner) do
98
- Halite::SpecHelper::Runner.new(
99
- {
100
- step_into: step_into,
101
- default_attributes: default_attributes,
102
- normal_attributes: normal_attributes,
103
- override_attributes: override_attributes,
104
- halite_gemspec: halite_gemspec,
105
- # Default platform and version.
106
- platform: 'ubuntu',
107
- version: '16.04',
108
- }.merge(chefspec_options)
109
- )
96
+
97
+ # Cross-link the Halite and ChefSpec data.
98
+ let(:chefspec_platform) do
99
+ chefspec_options[:platform] || 'ubuntu'
100
+ end
101
+ let(:chefspec_platform_version) do
102
+ chefspec_options[:version]
103
+ end
104
+
105
+ # Merge in extra options data.
106
+ def chef_runner_options
107
+ super.tap do |options|
108
+ options[:halite_gemspec] = halite_gemspec
109
+ # And some legacy data.
110
+ options[:default_attributes].update(default_attributes)
111
+ options[:normal_attributes].update(normal_attributes)
112
+ options[:override_attributes].update(override_attributes)
113
+ options.update(chefspec_options)
114
+ end
115
+ end
116
+
117
+ # Custom runner class.
118
+ def chef_runner_class
119
+ Halite::SpecHelper::Runner
120
+ end
121
+
122
+ # Don't try to converge any recipes, even by default.
123
+ let(:chef_run) do
124
+ chef_runner.converge
110
125
  end
111
- # @!attribute [r] chef_run
112
- # Trigger a Chef converge. By default no resources are converged. This is
113
- # normally overwritten by the {#recipe} helper.
114
- # @return [ChefSpec::SoloRunner]
115
- # @see #recipe
116
- let(:chef_run) { chef_runner.converge() }
117
126
 
118
127
  # An alias for slightly more semantic meaning, just forces the lazy #subject
119
128
  # to run.
@@ -172,7 +181,7 @@ module Halite
172
181
  # end
173
182
  def recipe(*recipe_names, subject: true, &block)
174
183
  # Keep the actual logic in a let in case I want to define the subject as something else
175
- let(:chef_run) { chef_runner.converge(*recipe_names, &block) }
184
+ let(:chef_run) { recipe_names.empty? ? chef_runner.converge_block(&block) : chef_runner.converge(*recipe_names) }
176
185
  subject { chef_run } if subject
177
186
  end
178
187
 
@@ -192,7 +201,8 @@ module Halite
192
201
  # end
193
202
  # it { is_expected.to run_ruby_block('test') }
194
203
  # end
195
- def step_into(name, resource_name=nil, unwrap_notifying_block: true)
204
+ def step_into(name=nil, resource_name=nil, unwrap_notifying_block: true)
205
+ return super() if name.nil?
196
206
  resource_class = if name.is_a?(Class)
197
207
  name
198
208
  elsif resources[name.to_sym]
@@ -210,16 +220,6 @@ module Halite
210
220
  Chef::Mixin::ConvertToClassName.convert_to_snake_case(resource_class.name.split('::').last)
211
221
  end
212
222
 
213
- # Add a resource-level matcher to ChefSpec.
214
- ChefSpec.define_matcher(resource_name)
215
-
216
- # Figure out the available actions and create ChefSpec matchers.
217
- resource_class.new(nil, nil).allowed_actions.each do |action|
218
- define_method("#{action}_#{resource_name}") do |instance_name|
219
- ChefSpec::Matchers::ResourceMatcher.new(resource_name, action, instance_name)
220
- end
221
- end
222
-
223
223
  # Patch notifying_block from Poise::Provider to just run directly.
224
224
  # This is not a great solution but it is better than nothing for right
225
225
  # now. In the future this should maybe do an internal converge but using
@@ -238,7 +238,7 @@ module Halite
238
238
  end
239
239
 
240
240
  # Add to the let variable passed in to ChefSpec.
241
- before { step_into << resource_name }
241
+ super(resource_name)
242
242
  end
243
243
 
244
244
  # Define a resource class for use in an example group. By default the
@@ -333,7 +333,7 @@ module Halite
333
333
  around do |ex|
334
334
  if patch && resource(name) == resource_class
335
335
  # We haven't been overridden from a nested scope.
336
- Patcher.patch(name, resource_class, Chef::Resource) { ex.run }
336
+ Patcher.patch(name, resource_class) { ex.run }
337
337
  else
338
338
  ex.run
339
339
  end
@@ -424,7 +424,7 @@ module Halite
424
424
  around do |ex|
425
425
  if patch && provider(name) == provider_class
426
426
  # We haven't been overridden from a nested scope.
427
- Patcher.patch(name, provider_class, Chef::Provider) { ex.run }
427
+ Patcher.patch(name, provider_class) { ex.run }
428
428
  else
429
429
  ex.run
430
430
  end
@@ -26,30 +26,16 @@ module Halite
26
26
  # @since 1.0.0
27
27
  # @api private
28
28
  module Patcher
29
- # Flag to disable module-name patching.
30
- DISABLE_PATCH_MODULE = ::Gem::Requirement.create('>= 13').satisfied_by?(::Gem::Version.create(Chef::VERSION))
31
-
32
29
  # Patch a class in to Chef for the duration of a block.
33
30
  #
34
31
  # @param name [String, Symbol] Name to create in snake-case (eg. :my_name).
35
32
  # @param klass [Class] Class to patch in.
36
- # @param mod [Module] Optional module to create a constant in.
37
33
  # @param block [Proc] Block to execute while the patch is available.
38
34
  # @return [void]
39
- def self.patch(name, klass, mod=nil, &block)
40
- patch_descendants_tracker(klass) do
41
- patch_node_map(name, klass) do
42
- patch_priority_map(name, klass) do
43
- patch_handler_map(name, klass) do
44
- patch_recipe_dsl(name, klass) do
45
- if mod
46
- patch_module(mod, name, klass, &block)
47
- else
48
- block.call
49
- end
50
- end
51
- end
52
- end
35
+ def self.patch(name, klass, &block)
36
+ patch_handler_map(name, klass) do
37
+ patch_recipe_dsl(name, klass) do
38
+ block.call
53
39
  end
54
40
  end
55
41
  end
@@ -65,10 +51,8 @@ module Halite
65
51
  def self.post_create_cleanup(name, klass)
66
52
  # Remove from DSL.
67
53
  Chef::DSL::Resources.remove_resource_dsl(name) if defined?(Chef::DSL::Resources.remove_resource_dsl)
68
- # Remove from DescendantsTracker.
69
- Chef::Mixin::DescendantsTracker.direct_descendants(klass.superclass).delete(klass)
70
- # Remove from the priority and handler maps.
71
- {priority: priority_map_for(klass), handler: handler_map_for(klass)}.each do |type, map|
54
+ # Remove from the handler map.
55
+ {handler: handler_map_for(klass)}.each do |type, map|
72
56
  if map
73
57
  # Make sure we add name in there too because anonymous classes don't
74
58
  # get a handler map registration by default.
@@ -78,78 +62,6 @@ module Halite
78
62
  klass.instance_variable_set(:"@halite_original_#{type}_keys", removed_keys)
79
63
  end
80
64
  end
81
- # Remove from the global node map.
82
- if defined?(Chef::Resource.node_map)
83
- removed_keys = remove_from_node_map(Chef::Resource.node_map, klass)
84
- # Used down in patch_node_map.
85
- klass.instance_variable_set(:@halite_original_nodemap_keys, removed_keys)
86
- end
87
- end
88
-
89
- # Patch an object in to a global namespace for the duration of a block.
90
- #
91
- # @param mod [Module] Namespace to patch in to.
92
- # @param name [String, Symbol] Name to create in snake-case (eg. :my_name).
93
- # @param obj Object to patch in.
94
- # @param block [Proc] Block to execute while the name is available.
95
- # @return [void]
96
- def self.patch_module(mod, name, obj, &block)
97
- return block.call if DISABLE_PATCH_MODULE
98
- class_name = Chef::Mixin::ConvertToClassName.convert_to_class_name(name.to_s)
99
- if mod.const_defined?(class_name, false)
100
- old_class = mod.const_get(class_name, false)
101
- # We are only allowed to patch over things installed by patch_module
102
- raise "#{mod.name}::#{class_name} is already defined" if !old_class.instance_variable_get(:@poise_patch_module)
103
- # Remove it before setting to avoid the redefinition warning
104
- mod.send(:remove_const, class_name)
105
- end
106
- # Tag our objects so we know we are allowed to overwrite those, but not other stuff.
107
- obj.instance_variable_set(:@poise_patch_module, true)
108
- mod.const_set(class_name, obj)
109
- begin
110
- block.call
111
- ensure
112
- # Same as above, have to remove before set because warnings
113
- mod.send(:remove_const, class_name)
114
- mod.const_set(class_name, old_class) if old_class
115
- end
116
- end
117
-
118
- # Patch an object in to Chef's DescendantsTracker system for the duration
119
- # of a code block.
120
- #
121
- # @param klass [Class] Class to patch in.
122
- # @param block [Proc] Block to execute while the patch is available.
123
- # @return [void]
124
- def self.patch_descendants_tracker(klass, &block)
125
- begin
126
- # Re-add to tracking.
127
- Chef::Mixin::DescendantsTracker.store_inherited(klass.superclass, klass)
128
- block.call
129
- ensure
130
- # Clean up after ourselves.
131
- Chef::Mixin::DescendantsTracker.direct_descendants(klass.superclass).delete(klass)
132
- end
133
- end
134
-
135
- # Patch a class in to its node_map. This is not used in 12.4+.
136
- #
137
- # @param name [Symbol] Name to patch in.
138
- # @param klass [Class] Resource class to patch in.
139
- # @param block [Proc] Block to execute while the patch is available.
140
- # @return [void]
141
- def self.patch_node_map(name, klass, &block)
142
- return block.call unless defined?(klass.node_map)
143
- begin
144
- # Technically this is set to true on >=12.4, but this should work.
145
- keys = klass.instance_variable_get(:@halite_original_nodemap_keys) | [name.to_sym]
146
- keys.each do |key|
147
- klass.node_map.set(key, klass)
148
- end
149
- block.call
150
- ensure
151
- remove_from_node_map(klass.node_map, klass)
152
- end
153
65
  end
154
66
 
155
67
  # Patch a resource in to Chef's recipe DSL for the duration of a code
@@ -169,28 +81,6 @@ module Halite
169
81
  end
170
82
  end
171
83
 
172
- # Patch a class in to the correct priority map for the duration of a code
173
- # block. This is a no-op before Chef 12.4.
174
- #
175
- # @since 1.0.4
176
- # @param name [Symbol] Name to patch in.
177
- # @param klass [Class] Resource or provider class to patch in.
178
- # @param block [Proc] Block to execute while the patch is available.
179
- # @return [void]
180
- def self.patch_priority_map(name, klass, &block)
181
- priority_map = priority_map_for(klass)
182
- return block.call unless priority_map
183
- begin
184
- # Unlike patch_node_map, this has to be an array!
185
- klass.instance_variable_get(:@halite_original_priority_keys).each do |key|
186
- priority_map.set(key, [klass])
187
- end
188
- block.call
189
- ensure
190
- remove_from_node_map(priority_map, klass)
191
- end
192
- end
193
-
194
84
  # Patch a class in to the correct handler map for the duration of a code
195
85
  # block. This is a no-op before Chef 12.4.1.
196
86
  #
@@ -214,19 +104,6 @@ module Halite
214
104
 
215
105
  private
216
106
 
217
- # Find the global priority map for a class.
218
- #
219
- # @since 1.0.4
220
- # @param klass [Class] Resource or provider class to look up.
221
- # @return [nil, Chef::Platform::ResourcePriorityMap, Chef::Platform::ProviderPriorityMap]
222
- def self.priority_map_for(klass)
223
- if defined?(Chef.resource_priority_map) && klass < Chef::Resource
224
- Chef.resource_priority_map
225
- elsif defined?(Chef.provider_priority_map) && klass < Chef::Provider
226
- Chef.provider_priority_map
227
- end
228
- end
229
-
230
107
  # Find the global handler map for a class.
231
108
  #
232
109
  # @since 1.0.7
@@ -30,45 +30,19 @@ module Halite
30
30
  #
31
31
  # @since 1.0.0
32
32
  class Runner < ChefSpec::SoloRunner
33
- def self.converge(*recipe_names, &block)
34
- options = if recipe_names.last.is_a?(Hash)
35
- # Was called with options
36
- recipe_names.pop
37
- else
38
- {}
39
- end
40
- new(options).tap do |instance|
41
- instance.converge(*recipe_names, &block)
42
- end
33
+ def initialize(options={})
34
+ # Store the gemspec for later use
35
+ @halite_gemspec = options[:halite_gemspec]
36
+ super
43
37
  end
44
38
 
45
- def initialize(options={})
46
- # Repeating the detault platform.
47
- options[:platform] ||= 'ubuntu'
48
- options[:version] ||= '16.04'
49
- super(options) do |node|
50
- # Allow inserting arbitrary attribute data in to the node
51
- node.attributes.default = Chef::Mixin::DeepMerge.merge(node.attributes.default, options[:default_attributes]) if options[:default_attributes]
52
- node.attributes.normal = Chef::Mixin::DeepMerge.merge(node.attributes.normal, options[:normal_attributes]) if options[:normal_attributes]
53
- node.attributes.override = Chef::Mixin::DeepMerge.merge(node.attributes.override, options[:override_attributes]) if options[:override_attributes]
54
- # Store the gemspec for later use
55
- @halite_gemspec = options[:halite_gemspec]
56
- end
39
+ def preload!
57
40
  end
58
41
 
59
- def converge(*recipe_names, &block)
60
- raise Halite::Error.new('Cannot pass both recipe names and a recipe block to converge') if !recipe_names.empty? && block
61
- super(*recipe_names) do
42
+ def converge(*args, &block)
43
+ super(*args) do |node|
62
44
  add_halite_cookbooks(node, @halite_gemspec) if @halite_gemspec
63
- if block
64
- cookbook_name = if @halite_gemspec
65
- Halite::Gem.new(Array(@halite_gemspec).first).cookbook_name + '_spec'
66
- else
67
- nil
68
- end
69
- recipe = Chef::Recipe.new(cookbook_name, nil, run_context)
70
- recipe.instance_exec(&block)
71
- end
45
+ block.call(node) if block
72
46
  end
73
47
  end
74
48
 
@@ -96,10 +70,31 @@ module Halite
96
70
  end
97
71
  end
98
72
 
73
+ # Override the normal cookbook loading behavior.
74
+ def cookbook
75
+ if @halite_gemspec
76
+ halite_gem = Halite::Gem.new(Array(@halite_gemspec).first)
77
+ Chef::Cookbook::Metadata.new.tap do |metadata|
78
+ metadata.name(halite_gem.cookbook_name)
79
+ end
80
+ else
81
+ super
82
+ end
83
+ end
84
+
99
85
  # Don't try to autodetect the calling cookbook.
100
- def calling_cookbook_path(_kaller)
86
+ def calling_cookbook_path(*args)
101
87
  File.expand_path('../empty', __FILE__)
102
88
  end
89
+
90
+ # Inject a better chefspec_cookbook_root option.
91
+ def apply_chef_config!
92
+ super
93
+ if @halite_gemspec
94
+ Chef::Config[:chefspec_cookbook_root] = Array(@halite_gemspec).first.full_gem_path
95
+ end
96
+ end
97
+
103
98
  end
104
99
  end
105
100
  end