chefspec 2.0.1 → 3.0.0.beta.1

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 (110) hide show
  1. checksums.yaml +4 -4
  2. data/lib/chefspec.rb +30 -44
  3. data/lib/chefspec/api.rb +74 -0
  4. data/lib/chefspec/api/apt_package.rb +192 -0
  5. data/lib/chefspec/api/batch.rb +43 -0
  6. data/lib/chefspec/api/chef_gem.rb +191 -0
  7. data/lib/chefspec/api/cookbook_file.rb +166 -0
  8. data/lib/chefspec/api/cron.rb +80 -0
  9. data/lib/chefspec/api/deploy.rb +117 -0
  10. data/lib/chefspec/api/directory.rb +80 -0
  11. data/lib/chefspec/api/dpkg_package.rb +117 -0
  12. data/lib/chefspec/api/easy_install_package.rb +154 -0
  13. data/lib/chefspec/api/env.rb +117 -0
  14. data/lib/chefspec/api/erl_call.rb +43 -0
  15. data/lib/chefspec/api/execute.rb +43 -0
  16. data/lib/chefspec/api/file.rb +166 -0
  17. data/lib/chefspec/api/freebsd_package.rb +80 -0
  18. data/lib/chefspec/api/gem_package.rb +191 -0
  19. data/lib/chefspec/api/git.rb +117 -0
  20. data/lib/chefspec/api/group.rb +154 -0
  21. data/lib/chefspec/api/http_request.rb +228 -0
  22. data/lib/chefspec/api/ifconfig.rb +154 -0
  23. data/lib/chefspec/api/include_recipe.rb +26 -0
  24. data/lib/chefspec/api/ips_package.rb +117 -0
  25. data/lib/chefspec/api/link.rb +102 -0
  26. data/lib/chefspec/api/log.rb +43 -0
  27. data/lib/chefspec/api/macports_package.rb +154 -0
  28. data/lib/chefspec/api/mdadm.rb +117 -0
  29. data/lib/chefspec/api/mount.rb +192 -0
  30. data/lib/chefspec/api/notifications.rb +38 -0
  31. data/lib/chefspec/api/ohai.rb +43 -0
  32. data/lib/chefspec/api/package.rb +192 -0
  33. data/lib/chefspec/api/pacman_package.rb +155 -0
  34. data/lib/chefspec/api/portage_package.rb +155 -0
  35. data/lib/chefspec/api/powershell_script.rb +43 -0
  36. data/lib/chefspec/api/registry_key.rb +166 -0
  37. data/lib/chefspec/api/remote_directory.rb +120 -0
  38. data/lib/chefspec/api/remote_file.rb +166 -0
  39. data/lib/chefspec/api/render_file.rb +32 -0
  40. data/lib/chefspec/api/route.rb +80 -0
  41. data/lib/chefspec/api/rpm_package.rb +117 -0
  42. data/lib/chefspec/api/ruby_block.rb +37 -0
  43. data/lib/chefspec/api/script.rb +228 -0
  44. data/lib/chefspec/api/service.rb +246 -0
  45. data/lib/chefspec/api/smartos_package.rb +117 -0
  46. data/lib/chefspec/api/solaris_package.rb +80 -0
  47. data/lib/chefspec/api/subversion.rb +154 -0
  48. data/lib/chefspec/api/template.rb +166 -0
  49. data/lib/chefspec/api/user.rb +228 -0
  50. data/lib/chefspec/api/yum_package.rb +154 -0
  51. data/lib/chefspec/berkshelf.rb +37 -0
  52. data/lib/chefspec/deprecations.rb +151 -0
  53. data/lib/chefspec/errors.rb +99 -0
  54. data/lib/chefspec/expect_exception.rb +45 -0
  55. data/lib/chefspec/extensions/chef/client.rb +15 -0
  56. data/lib/chefspec/extensions/chef/conditional.rb +11 -0
  57. data/lib/chefspec/extensions/chef/data_query.rb +29 -0
  58. data/lib/chefspec/extensions/chef/lwrp_base.rb +44 -0
  59. data/lib/chefspec/extensions/chef/resource.rb +27 -0
  60. data/lib/chefspec/extensions/chef/securable.rb +19 -0
  61. data/lib/chefspec/formatter.rb +270 -0
  62. data/lib/chefspec/macros.rb +217 -0
  63. data/lib/chefspec/matchers.rb +9 -0
  64. data/lib/chefspec/matchers/include_recipe_matcher.rb +45 -0
  65. data/lib/chefspec/matchers/link_to_matcher.rb +28 -0
  66. data/lib/chefspec/matchers/notifications_matcher.rb +92 -0
  67. data/lib/chefspec/matchers/render_file_matcher.rb +72 -0
  68. data/lib/chefspec/matchers/resource_matcher.rb +143 -0
  69. data/lib/chefspec/renderer.rb +137 -0
  70. data/lib/chefspec/rspec.rb +17 -0
  71. data/lib/chefspec/runner.rb +274 -0
  72. data/lib/chefspec/stubs/command_registry.rb +11 -0
  73. data/lib/chefspec/stubs/command_stub.rb +37 -0
  74. data/lib/chefspec/stubs/data_bag_item_registry.rb +13 -0
  75. data/lib/chefspec/stubs/data_bag_item_stub.rb +25 -0
  76. data/lib/chefspec/stubs/data_bag_registry.rb +13 -0
  77. data/lib/chefspec/stubs/data_bag_stub.rb +23 -0
  78. data/lib/chefspec/stubs/registry.rb +32 -0
  79. data/lib/chefspec/stubs/search_registry.rb +13 -0
  80. data/lib/chefspec/stubs/search_stub.rb +25 -0
  81. data/lib/chefspec/stubs/stub.rb +37 -0
  82. data/lib/chefspec/version.rb +1 -2
  83. metadata +100 -103
  84. data/lib/chef/expect_exception.rb +0 -34
  85. data/lib/chef/formatters/chefspec.rb +0 -233
  86. data/lib/chef/knife/cookbook_create_specs.rb +0 -107
  87. data/lib/chefspec/chef_runner.rb +0 -275
  88. data/lib/chefspec/helpers/describe.rb +0 -17
  89. data/lib/chefspec/matchers/cron.rb +0 -7
  90. data/lib/chefspec/matchers/env.rb +0 -8
  91. data/lib/chefspec/matchers/execute.rb +0 -33
  92. data/lib/chefspec/matchers/file.rb +0 -83
  93. data/lib/chefspec/matchers/file_content.rb +0 -32
  94. data/lib/chefspec/matchers/group.rb +0 -8
  95. data/lib/chefspec/matchers/include_recipe.rb +0 -20
  96. data/lib/chefspec/matchers/link.rb +0 -14
  97. data/lib/chefspec/matchers/log.rb +0 -21
  98. data/lib/chefspec/matchers/notifications.rb +0 -43
  99. data/lib/chefspec/matchers/package.rb +0 -39
  100. data/lib/chefspec/matchers/python.rb +0 -7
  101. data/lib/chefspec/matchers/ruby_block.rb +0 -13
  102. data/lib/chefspec/matchers/script.rb +0 -34
  103. data/lib/chefspec/matchers/service.rb +0 -25
  104. data/lib/chefspec/matchers/shared.rb +0 -132
  105. data/lib/chefspec/matchers/user.rb +0 -8
  106. data/lib/chefspec/minitest.rb +0 -195
  107. data/lib/chefspec/monkey_patches/conditional.rb +0 -19
  108. data/lib/chefspec/monkey_patches/hash.rb +0 -23
  109. data/lib/chefspec/monkey_patches/lwrp_base.rb +0 -45
  110. data/lib/chefspec/monkey_patches/provider.rb +0 -43
@@ -0,0 +1,19 @@
1
+ require 'chef/mixin/securable'
2
+
3
+ class Chef
4
+ module Mixin
5
+ module Securable
6
+ # In Chef, this module is only included if the RUBY_PLATFORM is
7
+ # Windows-like. In ChefSpec, we want to include this, regardless of the
8
+ # platform, becuase this module holds the `inherits` attribute, which is
9
+ # critical in testing Windows resources.
10
+ include WindowsSecurableAttributes
11
+
12
+ def self.included(including_class)
13
+ including_class.extend(WindowsMacros)
14
+ including_class.rights_attribute(:rights)
15
+ including_class.rights_attribute(:deny_rights)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,270 @@
1
+ require 'chef/formatters/base'
2
+ require 'chef/formatters/error_mapper'
3
+
4
+ module ChefSpec
5
+ class ChefFormatter < Chef::Formatters::Base
6
+ cli_name :chefspec
7
+
8
+ # Called at the very start of a Chef Run
9
+ def run_start(version); end
10
+
11
+ def run_started(run_status); end
12
+
13
+ # Called at the end a successful Chef run.
14
+ def run_completed(node); end
15
+
16
+ # Called at the end of a failed Chef run.
17
+ def run_failed(exception); end
18
+
19
+ # Called right after ohai runs.
20
+ def ohai_completed(node); end
21
+
22
+ # Already have a client key, assuming this node has registered.
23
+ def skipping_registration(node_name, config); end
24
+
25
+ # About to attempt to register as +node_name+
26
+ def registration_start(node_name, config); end
27
+
28
+ def registration_completed; end
29
+
30
+ # Failed to register this client with the server.
31
+ def registration_failed(node_name, exception, config)
32
+ expecting_exception(exception) do
33
+ description = Chef::Formatters::ErrorMapper.registration_failed(node_name, exception, config)
34
+ display_error(description)
35
+ end
36
+ end
37
+
38
+ # Called before Chef client loads the node data from the server
39
+ def node_load_start(node_name, config); end
40
+
41
+ # Failed to load node data from the server
42
+ def node_load_failed(node_name, exception, config)
43
+ expecting_exception(exception) do
44
+ description = Chef::Formatters::ErrorMapper.node_load_failed(node_name, exception, config)
45
+ display_error(description)
46
+ end
47
+ end
48
+
49
+ # Error expanding the run list
50
+ def run_list_expand_failed(node, exception)
51
+ expecting_exception(exception) do
52
+ description = Chef::Formatters::ErrorMapper.run_list_expand_failed(node, exception)
53
+ display_error(description)
54
+ end
55
+ end
56
+
57
+ # Called after Chef client has loaded the node data.
58
+ # Default and override attrs from roles have been computed, but not yet applied.
59
+ # Normal attrs from JSON have been added to the node.
60
+ def node_load_completed(node, expanded_run_list, config); end
61
+
62
+ # Called before the cookbook collection is fetched from the server.
63
+ def cookbook_resolution_start(expanded_run_list); end
64
+
65
+ # Called when there is an error getting the cookbook collection from the
66
+ # server.
67
+ def cookbook_resolution_failed(expanded_run_list, exception)
68
+ expecting_exception(exception) do
69
+ description = Chef::Formatters::ErrorMapper.cookbook_resolution_failed(expanded_run_list, exception)
70
+ display_error(description)
71
+ end
72
+ end
73
+
74
+ # Called when the cookbook collection is returned from the server.
75
+ def cookbook_resolution_complete(cookbook_collection); end
76
+
77
+ # Called before unneeded cookbooks are removed
78
+ def cookbook_clean_start; end
79
+
80
+ # Called after the file at +path+ is removed. It may be removed if the
81
+ # cookbook containing it was removed from the run list, or if the file was
82
+ # removed from the cookbook.
83
+ def removed_cookbook_file(path); end
84
+
85
+ # Called when cookbook cleaning is finished.
86
+ def cookbook_clean_complete; end
87
+
88
+ # Called before cookbook sync starts
89
+ def cookbook_sync_start(cookbook_count); end
90
+
91
+ # Called when cookbook +cookbook_name+ has been sync'd
92
+ def synchronized_cookbook(cookbook_name); end
93
+
94
+ # Called when an individual file in a cookbook has been updated
95
+ def updated_cookbook_file(cookbook_name, path); end
96
+
97
+ # Called when an error occurs during cookbook sync
98
+ def cookbook_sync_failed(cookbooks, exception)
99
+ expecting_exception(exception) do
100
+ description = Chef::Formatters::ErrorMapper.cookbook_sync_failed(cookbooks, exception)
101
+ display_error(description)
102
+ end
103
+ end
104
+
105
+ # Called after all cookbooks have been sync'd.
106
+ def cookbook_sync_complete; end
107
+
108
+ # Called when library file loading starts
109
+ def library_load_start(file_count); end
110
+
111
+ # Called when library file has been loaded
112
+ def library_file_loaded(path); end
113
+
114
+ # Called when a library file has an error on load.
115
+ def library_file_load_failed(path, exception)
116
+ file_load_failed(path, exception)
117
+ end
118
+
119
+ # Called when library file loading has finished
120
+ def library_load_complete; end
121
+
122
+ # Called when LWRP loading starts
123
+ def lwrp_load_start(lwrp_file_count); end
124
+
125
+ # Called after a LWR or LWP has been loaded
126
+ def lwrp_file_loaded(path); end
127
+
128
+ # Called after a LWR or LWP file errors on load
129
+ def lwrp_file_load_failed(path, exception)
130
+ file_load_failed(path, exception)
131
+ end
132
+
133
+ # Called when LWRPs are finished loading
134
+ def lwrp_load_complete; end
135
+
136
+ # Called before attribute files are loaded
137
+ def attribute_load_start(attribute_file_count); end
138
+
139
+ # Called after the attribute file is loaded
140
+ def attribute_file_loaded(path); end
141
+
142
+ # Called when an attribute file fails to load.
143
+ def attribute_file_load_failed(path, exception)
144
+ file_load_failed(path, exception)
145
+ end
146
+
147
+ # Called when attribute file loading is finished
148
+ def attribute_load_complete; end
149
+
150
+ # Called before resource definitions are loaded
151
+ def definition_load_start(definition_file_count); end
152
+
153
+ # Called when a resource definition has been loaded
154
+ def definition_file_loaded(path); end
155
+
156
+ # Called when a resource definition file fails to load
157
+ def definition_file_load_failed(path, exception)
158
+ file_load_failed(path, exception)
159
+ end
160
+
161
+ # Called when resource defintions are done loading
162
+ def definition_load_complete; end
163
+
164
+ # Called before recipes are loaded
165
+ def recipe_load_start(recipe_count); end
166
+
167
+ # Called after the recipe has been loaded
168
+ def recipe_file_loaded(path); end
169
+
170
+ # Called after a recipe file fails to load
171
+ def recipe_file_load_failed(path, exception)
172
+ file_load_failed(path, exception)
173
+ end
174
+
175
+ # Called when a recipe cannot be resolved
176
+ def recipe_not_found(exception)
177
+ expecting_exception(exception) do
178
+ description = Chef::Formatters::ErrorMapper.file_load_failed(nil, exception)
179
+ display_error(description)
180
+ end
181
+ end
182
+
183
+ # Called when recipes have been loaded.
184
+ def recipe_load_complete; end
185
+
186
+ # Called before convergence starts
187
+ def converge_start(run_context); end
188
+
189
+ # Called when the converge phase is finished.
190
+ def converge_complete; end
191
+
192
+ # Called before action is executed on a resource.
193
+ def resource_action_start(resource, action, notification_type=nil, notifier=nil); end
194
+
195
+ # Called when a resource fails, but will retry.
196
+ def resource_failed_retriable(resource, action, retry_count, exception); end
197
+
198
+ # Called when a resource fails and will not be retried.
199
+ def resource_failed(resource, action, exception)
200
+ expecting_exception(exception) do
201
+ description = Chef::Formatters::ErrorMapper.resource_failed(resource, action, exception)
202
+ display_error(description)
203
+ end
204
+ end
205
+
206
+ # Called when a resource action has been skipped b/c of a conditional
207
+ def resource_skipped(resource, action, conditional); end
208
+
209
+ # Called when a resource action has been completed
210
+ def resource_completed(resource); end
211
+
212
+ # Called after #load_current_resource has run.
213
+ def resource_current_state_loaded(resource, action, current_resource); end
214
+
215
+ # Called when resource current state load is skipped due to the provider
216
+ # not supporting whyrun mode.
217
+ def resource_current_state_load_bypassed(resource, action, current_resource); end
218
+
219
+ # Called when evaluating a resource that does not support whyrun in whyrun mode
220
+ def resource_bypassed(resource, action, current_resource); end
221
+
222
+ # Called when a resource has no converge actions, e.g., it was already correct.
223
+ def resource_up_to_date(resource, action); end
224
+
225
+ # Called when a change has been made to a resource. May be called multiple
226
+ # times per resource, e.g., a file may have its content updated, and then
227
+ # its permissions updated.
228
+ def resource_update_applied(resource, action, update); end
229
+
230
+ # Called after a resource has been completely converged, but only if
231
+ # modifications were made.
232
+ def resource_updated(resource, action); end
233
+
234
+ # Called before handlers run
235
+ def handlers_start(handler_count); end
236
+
237
+ # Called after an individual handler has run
238
+ def handler_executed(handler); end
239
+
240
+ # Called after all handlers have executed
241
+ def handlers_completed; end
242
+
243
+ # Called when an assertion declared by a provider fails
244
+ def provider_requirement_failed(action, resource, exception, message); end
245
+
246
+ # Called when a provider makes an assumption after a failed assertion
247
+ # in whyrun mode, in order to allow execution to continue
248
+ def whyrun_assumption(action, resource, message); end
249
+
250
+ # An uncategorized message. This supports the case that a user needs to
251
+ # pass output that doesn't fit into one of the callbacks above. Note that
252
+ # there's no semantic information about the content or importance of the
253
+ # message. That means that if you're using this too often, you should add a
254
+ # callback for it.
255
+ def msg(message); end
256
+
257
+ private
258
+ def file_load_failed(path, exception)
259
+ expecting_exception(exception) do
260
+ description = Chef::Formatters::ErrorMapper.file_load_failed(path, exception)
261
+ display_error(description)
262
+ end
263
+ end
264
+
265
+ def expecting_exception(exception, &block)
266
+ yield unless ChefSpec::ExpectException.new(exception).expected?
267
+ end
268
+
269
+ end
270
+ end
@@ -0,0 +1,217 @@
1
+ module ChefSpec
2
+ module Macros
3
+ extend self
4
+
5
+ #
6
+ # The name of the currently running cookbook spec. Given the top-level
7
+ # +describe+ block is of the format:
8
+ #
9
+ # describe 'my_cookbook::my_recipe' do
10
+ # # ...
11
+ # end
12
+ #
13
+ # The value of +described_cookbook+ is "my_cookbook".
14
+ #
15
+ # @example Using +described_cookbook+ in a context block
16
+ # context "#{described_recipe} installs foo" do
17
+ # # ...
18
+ # end
19
+ #
20
+ #
21
+ # @return [String]
22
+ #
23
+ def described_cookbook
24
+ described_recipe.split('::').first
25
+ end
26
+
27
+ #
28
+ # The name of the currently running recipe spec. Given the top-level
29
+ # +describe+ block is of the format:
30
+ #
31
+ # describe 'my_cookbook::my_recipe' do
32
+ # # ...
33
+ # end
34
+ #
35
+ # The value of +described_recipe+ is "my_cookbook::my_recipe".
36
+ #
37
+ # @example Using +described_recipe+ in the +ChefSpec::Runner+
38
+ # let(:chef_run) { ChefSpec::Runner.new.converge(described_recipe) }
39
+ #
40
+ #
41
+ # @return [String]
42
+ #
43
+ def described_recipe
44
+ scope = self.is_a?(Class) ? self : self.class
45
+
46
+ metahash = scope.metadata
47
+ while metahash.has_key?(:example_group)
48
+ metahash = metahash[:example_group]
49
+ end
50
+
51
+ metahash[:description_args].first.to_s
52
+ end
53
+
54
+ #
55
+ # Stub a shell command to return a particular value without
56
+ # shelling out to the system.
57
+ #
58
+ # @example stubbing a command to return true
59
+ # stub_command('test -f /tmp/bacon').and_return(true)
60
+ #
61
+ # @example stubbing a block that is evaluated at runtime
62
+ # stub_command('test -f /tmp/bacon') { MyClass.check? }
63
+ #
64
+ # @example stubbing a command that matches a pattern
65
+ # stub_command(/test \-f/).and_return(true)
66
+ #
67
+ # @example stubbing a command that raises an exception
68
+ # stub_command('test -f /tmp/bacon').and_raise(SomeException)
69
+ #
70
+ #
71
+ # @param [String, Regexp] command
72
+ # the command to stub
73
+ #
74
+ # @return [ChefSpec::CommandStub]
75
+ #
76
+ def stub_command(command, &block)
77
+ Stubs::CommandRegistry.register(Stubs::CommandStub.new(command, &block))
78
+ end
79
+
80
+ #
81
+ # Stub a Chef call to load a data_bag.
82
+ #
83
+ # @example stubbing a data_bag to return an empty Array
84
+ # stub_data_bag('users').and_return([])
85
+ #
86
+ # @example stubbing a data_bag with a block that is evaluated at runtime
87
+ # stub_data_bag('users') { JSON.parse(File.read('fixtures/data_bag.json')) }
88
+ #
89
+ # @example stubbing a data_bag to return an Array of Hashes
90
+ # stub_data_bag('users').and_return([
91
+ # { id: 'bacon', comment: 'delicious' },
92
+ # { id: 'ham', comment: 'also good' }
93
+ # ])
94
+ #
95
+ # @example stubbing a data_bag to raise an exception
96
+ # stub_data_bag('users').and_raise(Chef::Exceptions::PrivateKeyMissing)
97
+ #
98
+ #
99
+ # @param [String, Symbol] bag
100
+ # the name of the data bag to stub
101
+ #
102
+ # @return [ChefSpec::DataBagStub]
103
+ #
104
+ def stub_data_bag(bag, &block)
105
+ Stubs::DataBagRegistry.register(Stubs::DataBagStub.new(bag, &block))
106
+ end
107
+
108
+ #
109
+ # Stub a Chef data_bag call.
110
+ #
111
+ # @example stubbing a data_bag_item to return a Hash of data
112
+ # stub_data_bag_item('users', 'svargo').and_return({
113
+ # id: 'svargo',
114
+ # name: 'Seth Vargo'
115
+ # })
116
+ #
117
+ # @example stubbing a data_bag_item with a block that is evaluated at runtime
118
+ # stub_data_bag_item('users', 'svargo') { JSON.parse(File.read('fixtures/data_bag_item.json')) }
119
+ #
120
+ # @example stubbing a data_bag_item to raise an exception
121
+ # stub_data_bag('users', 'svargo').and_raise(Chef::Exceptions::PrivateKeyMissing)
122
+ #
123
+ #
124
+ # @param [String, Symbol] bag
125
+ # the name of the data bag to find the item in
126
+ # @param [String] id
127
+ # the id of the data bag item to stub
128
+ #
129
+ # @return [ChefSpec::DataBagItemStub]
130
+ #
131
+ def stub_data_bag_item(bag, id, &block)
132
+ Stubs::DataBagItemRegistry.register(Stubs::DataBagItemStub.new(bag, id, &block))
133
+ end
134
+
135
+ #
136
+ # Creates a fake Chef::Node for use in testing.
137
+ #
138
+ # @example mocking a simple node
139
+ # stub_node('mynode.example')
140
+ #
141
+ # @example mocking a specific platform and version
142
+ # stub_node('mynode.example', platform: 'ubuntu', version: '12.04')
143
+ #
144
+ # @example overriding a specific ohai attribute
145
+ # stub_node('mynode.example', ohai: { ipaddress: '1.2.3.4' })
146
+ #
147
+ # @example stubbing a node based on a JSON fixture
148
+ # stub_node('mynode.example', path: File.join('fixtures', 'nodes', 'default.json'))
149
+ #
150
+ # @example setting specific attributes
151
+ # stub_node('mynode.example') do |node|
152
+ # node.default['attribute']['thing'] = 'value'
153
+ # end
154
+ #
155
+ #
156
+ # @param [String] name
157
+ # the name of the node
158
+ # @param [Hash] options
159
+ # the list of options for the node
160
+ #
161
+ # @option options [Symbol] :platform
162
+ # the platform to mock
163
+ # @option options [Symbol] :version
164
+ # the version of the platform to mock
165
+ # @option options [Symbol] :path
166
+ # filepath to a JSON file to pull a node from
167
+ # @option options [Hash] :ohai
168
+ # a Hash of Ohai attributes to mock on the node
169
+ #
170
+ def stub_node(name = 'node.example', options = {}, &block)
171
+ fauxhai = Fauxhai.mock(options).data
172
+ fauxhai = fauxhai.merge(options[:ohai] || {})
173
+ fauxhai = Mash.new(fauxhai)
174
+
175
+ node = Chef::Node.new
176
+ node.name(name)
177
+ node.automatic_attrs = fauxhai
178
+ node.instance_eval(&block) if block_given?
179
+ node
180
+ end
181
+
182
+ #
183
+ # Stub a Chef search to return pre-defined data. When providing a value,
184
+ # the value is automatically mashified (to the best of ChefSpec's abilities)
185
+ # to ease in use.
186
+ #
187
+ # @example stubbing a search to return nothing
188
+ # stub_search(:node)
189
+ #
190
+ # @example stubbing a search with a query
191
+ # stub_search(:node, 'name:*')
192
+ #
193
+ # @example stubbing a search with a query as a regex
194
+ # stub_search(:node, /name:(.+)/)
195
+ #
196
+ # @example stubbing a search with a block that is evaluated at runtime
197
+ # stub_search(:node) { JSON.parse(File.read('fixtures/nodes.json')) }
198
+ #
199
+ # @example stubbing a search to return a fixed value
200
+ # stub_search(:node).and_return([ { a: 'b' } ])
201
+ #
202
+ # @example stubbing a search to raise an exception
203
+ # stub_search(:node).and_raise(Chef::Exceptions::PrivateKeyMissing)
204
+ #
205
+ #
206
+ # @param [String, Symbol] type
207
+ # the type to search to stub
208
+ # @param [String, Symbol, nil] query
209
+ # the query to stub
210
+ #
211
+ # @return [ChefSpec::SearchStub]
212
+ #
213
+ def stub_search(type, query = '*:*', &block)
214
+ Stubs::SearchRegistry.register(Stubs::SearchStub.new(type, query, &block))
215
+ end
216
+ end
217
+ end