halite 1.8.1 → 1.8.2

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