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
@@ -1,107 +0,0 @@
1
- require 'chefspec'
2
-
3
- if Chef.const_defined? :Knife
4
- module ChefSpec
5
- module Knife
6
-
7
- # Knife plugin to create placeholder specs.
8
- #
9
- # $ knife cookbook create -o . my_new_cookbook
10
- # $ knife cookbook create_specs -o . my_new_cookbook
11
- # $ rspec my_new_cookbook
12
- #
13
- # http://help.opscode.com/kb/knife/manage-cookbooks-with-knife
14
- class CookbookCreateSpecs < Chef::Knife
15
-
16
- # Implemented as a separate knife command rather than extending the knife built-in create_cookbook_command.
17
- # Extension may arguably have been better from the end user perspective but would be much more brittle.
18
-
19
- banner "knife cookbook create_specs COOKBOOK (options)"
20
-
21
- option :cookbook_path,
22
- :short => "-o PATH",
23
- :long => "--cookbook-path PATH",
24
- :description => "The directory where the cookbook specs will be created"
25
-
26
- # Invoke this command and create the new specs
27
- def run
28
- self.config = Chef::Config.merge!(config)
29
- if @name_args.empty?
30
- show_usage
31
- ui.fatal("You must specify a cookbook name")
32
- exit 1
33
- end
34
-
35
- if default_cookbook_path_empty? && parameter_empty?(config[:cookbook_path])
36
- raise ArgumentError, "Default cookbook_path is not specified in the knife.rb config file, and a value to -o is not provided. Nowhere to write the new cookbook to."
37
- end
38
-
39
- create_specs(Array(config[:cookbook_path]).first, @name_args.first)
40
- end
41
-
42
- private
43
-
44
- # Has a default cookbook path been set?
45
- #
46
- # @return [Boolean] True if cookbook path has been set in the Chef config.
47
- def default_cookbook_path_empty?
48
- Chef::Config[:cookbook_path].nil? || Chef::Config[:cookbook_path].empty?
49
- end
50
-
51
- # Create placeholder specs for the cookbook.
52
- #
53
- # @param [String] dir The directory to create the specs in
54
- # @param [String] cookbook The name of the cookbook
55
- # @param [String] recipe The name of the recipe to create a spec for
56
- def create_specs(dir, cookbook)
57
- spec_dir = "#{File.join(dir, cookbook, 'spec')}"
58
- FileUtils.mkdir_p spec_dir
59
- msg("** Creating specs for cookbook: #{cookbook}")
60
- existing_recipes(dir, cookbook).each do |recipe|
61
- create_spec(spec_dir, cookbook, recipe)
62
- end
63
- end
64
-
65
- # The list of recipes for a cookbook
66
- #
67
- # @param [String] dir The directory
68
- # @param [String] cookbook The name of the cookbook
69
- # @return [Array] The list of recipes for the cookbook
70
- def existing_recipes(dir, cookbook)
71
- Dir[File.join(dir, cookbook, 'recipes/*.rb')].map{|recipe| File.basename recipe, '.rb'}
72
- end
73
-
74
- # Create a placeholder spec for the cookbook.
75
- #
76
- # @param [String] spec_dir The directory to create the specs in
77
- # @param [String] cookbook The name of the cookbook
78
- # @param [String] recipe The name of the recipe to create a spec for
79
- def create_spec(spec_dir, cookbook, recipe)
80
- unless File.exists?(File.join(spec_dir, "#{recipe}_spec.rb"))
81
- open(File.join(spec_dir, "#{recipe}_spec.rb"), "w") do |file|
82
- file.puts spec_file_content(cookbook, recipe)
83
- end
84
- end
85
- end
86
-
87
- # Generate the content for the placeholder spec file.
88
- #
89
- # @param [String] cookbook The name of the cookbook
90
- # @param [String] recipe The name of the recipe
91
- def spec_file_content(cookbook, recipe)
92
- return <<-EOH
93
- require 'chefspec'
94
-
95
- describe '#{cookbook}::#{recipe}' do
96
- let (:chef_run) { ChefSpec::ChefRunner.new.converge '#{cookbook}::#{recipe}' }
97
- it 'should do something' do
98
- pending 'Your recipe examples go here.'
99
- end
100
- end
101
- EOH
102
- end
103
-
104
- end
105
- end
106
- end
107
- end
@@ -1,275 +0,0 @@
1
- require 'chef'
2
- require 'chef/client'
3
- require 'chef/cookbook_loader'
4
- require 'fauxhai'
5
-
6
- require 'chefspec/matchers/shared'
7
-
8
- begin
9
- require 'berkshelf'
10
- rescue LoadError; end
11
-
12
- # ChefSpec allows you to write rspec examples for Chef recipes to gain faster feedback without the need to converge a
13
- # node.
14
- module ChefSpec
15
-
16
- # The main entry point for running recipes within RSpec.
17
- class ChefRunner
18
-
19
- @resources = []
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
-
35
- attr_accessor :resources
36
- attr_reader :step_into
37
- attr_reader :run_context
38
- attr_reader :node
39
- attr_reader :stubbed_commands
40
-
41
- # Instantiate a new runner to run examples with.
42
- #
43
- # @param [Hash] options The options for the new runner
44
- # @option options [String] :cookbook_path The path to the chef cookbook(s) to be tested.
45
- # @option options [Symbol] :log_level The log level to use (default is :warn)
46
- # @option options [String] :platform The platform to load Ohai attributes from (must be present in fauxhai)
47
- # @option options [String] :version The version of the platform to load Ohai attributes from (must be present in fauxhai)
48
- # @option options [String] :ohai_data_path Path of a json file that will be passed to fauxhai as :path option
49
- # @yield [node] Configuration block for Chef::Node
50
- def initialize(options={})
51
- # Because we evaluate the "caller" in this method, we need to call
52
- # it first so that the path is correctly calculated.
53
- @default_cookbook_path = default_cookbook_path
54
-
55
- defaults = {
56
- :cookbook_path => cookbook_paths,
57
- :log_level => :warn,
58
- :dry_run => false,
59
- :step_into => [],
60
- :evaluate_guards => false
61
- }
62
- options = {:cookbook_path => options} unless options.respond_to?(:to_hash) # backwards-compatibility
63
- @options = defaults.merge(options)
64
-
65
- the_runner = self
66
- @resources = []
67
- @step_into = @options[:step_into]
68
- @do_dry_run = @options[:dry_run]
69
- @evaluate_guards = @options[:evaluate_guards]
70
- @actually_run_shell_guards = @options[:actually_run_shell_guards]
71
- @stubbed_commands = []
72
-
73
- Chef::Resource::Conditional.class_eval do
74
- if self.class.methods.include?(:class_variable_set)
75
- self.class_variable_set :@@runner, the_runner
76
- else
77
- @@runner = the_runner
78
- end
79
- def runner
80
- if self.class.methods.include?(:class_variable_get)
81
- self.class.send(:class_variable_get, :@@runner)
82
- else
83
- @@runner
84
- end
85
- end
86
- end
87
-
88
- Chef::Resource.class_eval do
89
- alias :old_run_action :run_action unless method_defined?(:old_run_action)
90
-
91
- if self.class.methods.include?(:class_variable_set)
92
- self.class_variable_set :@@runner, the_runner
93
- else
94
- @@runner = the_runner
95
- end
96
-
97
- def run_action(*args)
98
- action = args.first
99
- runner = if self.class.methods.include?(:class_variable_get)
100
- self.class.class_variable_get(:@@runner)
101
- else
102
- @@runner
103
- end
104
-
105
- if runner.evaluate_guards?
106
- if self.respond_to?(:should_skip?) # Chef >= 0.10
107
- if self.method(:should_skip?).arity == 1
108
- return if self.should_skip?(action)
109
- else
110
- return if self.should_skip?
111
- end
112
- end
113
- end
114
-
115
- if runner.step_into.include?(self.resource_name.to_s)
116
- # Ignore not_if / only_if guards
117
- if self.only_if.is_a?(Array) # 0.10.x
118
- self.instance_eval { @not_if = []; @only_if = [] }
119
- else # 0.9.x
120
- self.only_if { true }
121
- self.not_if { false }
122
- end
123
- self.old_run_action(action)
124
- end
125
-
126
- Chef::Log.info("Processing #{self} action #{action} (#{defined_at})") if self.respond_to? :defined_at
127
- runner.resources << self
128
- end
129
- end
130
-
131
- Chef::Config[:solo] = true
132
- Chef::Config[:cache_type] = "Memory"
133
- Chef::Config[:cache_options] = { :path => File.join(File.expand_path('~'), '.chef', 'checksums') }
134
- Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest) }
135
- Chef::Config[:cookbook_path] = Array(@options[:cookbook_path])
136
- Chef::Config[:client_key] = nil
137
-
138
- # it should be saved to an instance variable to prevent automatic
139
- # unlinking during garbage collection
140
- @dummy_config = Tempfile.new 'chef-config'
141
- Chef::Config[:config_file] = @dummy_config.path
142
-
143
- self.class.register_formatter
144
-
145
- Chef::Log.verbose = true if Chef::Log.respond_to?(:verbose)
146
- Chef::Log.level(@options[:log_level])
147
- @client = Chef::Client.new
148
- fake_ohai(@client.ohai)
149
- @client.load_node if @client.respond_to?(:load_node) # chef >= 10.14.0
150
- @node = @client.build_node
151
- if block_given?
152
- yield @node
153
- end
154
- end
155
-
156
- def stub_command(command, result)
157
- # We want to preserve insertion order so that stubs are applied in a
158
- # known order. Ruby 1.9 hashes behave like this but we are still
159
- # supporting 1.8.
160
- @stubbed_commands.reject!{|existing_cmd, _| existing_cmd == command}
161
- @stubbed_commands << [command, result]
162
- self
163
- end
164
-
165
- # Run the specified recipes, but without actually converging the node.
166
- #
167
- # @param [array] recipe_names The names of the recipes to execute
168
- # @return ChefSpec::ChefRunner The runner itself
169
- def converge(*recipe_names)
170
- @node.run_list.reset!
171
- recipe_names.each do |recipe_name|
172
- @node.run_list << recipe_name
173
- end
174
- return self if @do_dry_run
175
-
176
- @client.instance_eval do
177
- if defined?(@expanded_run_list_with_versions) # 0.10.x
178
- @run_list_expansion = @node.expand!('disk')
179
- @expanded_run_list_with_versions = @run_list_expansion.recipes.with_version_constraints_strings
180
- end
181
- end
182
-
183
- @resources = []
184
- if @client.respond_to?(:setup_run_context) # 0.10.x
185
- @run_context = @client.setup_run_context
186
- else
187
- @run_context = Chef::RunContext.new(@client.node, Chef::CookbookCollection.new(Chef::CookbookLoader.new)) # 0.9.x
188
- end
189
- runner = Chef::Runner.new(@run_context)
190
- runner.converge
191
- self
192
- end
193
-
194
- def evaluate_guards?
195
- !! @evaluate_guards
196
- end
197
-
198
- def actually_run_shell_guards?
199
- !! @actually_run_shell_guards
200
- end
201
-
202
- FILE_RESOURCES = %w(directory cookbook_file file template link remote_directory remote_file)
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)
204
- SCRIPT_RESOURCES = %w(script powershell bash csh perl python ruby)
205
- MISC_RESOURCES = %w(cron env user execute service log route ruby_block git subversion group mount ohai ifconfig deploy http_request)
206
-
207
- (FILE_RESOURCES + PACKAGE_RESOURCES + SCRIPT_RESOURCES + MISC_RESOURCES).sort.uniq.each do |type|
208
- define_method(type) do |name|
209
- find_resource(type, name)
210
- end
211
- end
212
-
213
- # This runner as a string.
214
- #
215
- # @return [String] Currently includes the run_list. Format of the string may change between versions of this gem.
216
- def to_s
217
- return "chef_run: #{@node.run_list.to_s}" unless @node.run_list.empty?
218
- 'chef_run'
219
- end
220
-
221
- # Find the resource with the declared type and name
222
- #
223
- # @param [String] type The type of resource - e.g. 'file' or 'directory'
224
- # @param [String] name The resource name
225
- # @return [Chef::Resource] The matching resource, or Nil
226
- def find_resource(type, name)
227
- resources.find{|resource| resource_type(resource) == type and resource.name == name}
228
- end
229
-
230
- private
231
-
232
- # Populate basic OHAI attributes required to get recipes working. This is a minimal set - if your recipe example
233
- # does conditional execution based on these values or additional attributes you can set these via
234
- # node.automatic_attrs.
235
- #
236
- # This method now relies on fauxhai to set node attributes.
237
- #
238
- # @param [Ohai::System] ohai The ohai instance to set fake attributes on
239
- def fake_ohai(ohai)
240
- data = if @options.has_key?(:ohai_data_path)
241
- Fauxhai::Mocker.new(:path => @options[:ohai_data_path]).data
242
- else
243
- Fauxhai::Mocker.new(:platform => @options[:platform], :version => @options[:version]).data
244
- end
245
- data.each_pair do |attribute, value|
246
- ohai[attribute] = value
247
- end
248
- end
249
-
250
- # Infer the default cookbook path from the location of the calling spec.
251
- #
252
- # @return [String] The path to the cookbooks directory
253
- def default_cookbook_path
254
- Pathname.new(File.join(caller(2).first.split(':').slice(0..-3).join(':'), '..', '..', '..')).cleanpath.to_s
255
- end
256
-
257
- # The cookbook path, appended with some "common" directories to search
258
- # as well (such as vendor/cookbooks)
259
- #
260
- # @return [Array<String>] The cookbook_paths
261
- def cookbook_paths
262
- vendor_path = File.expand_path(File.join('vendor', 'cookbooks'))
263
- test_path = File.expand_path(File.join('test', 'cookbooks'))
264
- spec_path = File.expand_path(File.join('spec', 'cookbooks'))
265
-
266
- Array(@default_cookbook_path).
267
- push(vendor_path).
268
- push(test_path).
269
- push(spec_path).
270
- select { |path| File.exists?(path) }
271
- end
272
-
273
- end
274
-
275
- end
@@ -1,17 +0,0 @@
1
- module ChefSpec
2
- module Helpers
3
- module Describe
4
- def described_recipe
5
- metahash = self.class.metadata
6
- while metahash.has_key? :example_group
7
- metahash = metahash[:example_group]
8
- end
9
- metahash[:description_args].first
10
- end
11
-
12
- def described_cookbook
13
- described_recipe.split('::').first
14
- end
15
- end
16
- end
17
- end
@@ -1,7 +0,0 @@
1
- require 'chefspec/matchers/shared'
2
-
3
- module ChefSpec
4
- module Matchers
5
- define_resource_matchers([:create, :delete], [:cron], :name)
6
- end
7
- end
@@ -1,8 +0,0 @@
1
-
2
- require 'chefspec/matchers/shared'
3
-
4
- module ChefSpec
5
- module Matchers
6
- define_resource_matchers([:create, :delete,:modify], [:env], :key_name)
7
- end
8
- end
@@ -1,33 +0,0 @@
1
- require 'chefspec/matchers/shared'
2
-
3
- module ChefSpec
4
- module Matchers
5
- RSpec::Matchers.define :execute_command do |command|
6
- match do |chef_run|
7
- if @attributes
8
- chef_run.resources.any? do |resource|
9
- expected_resource?(resource,command) &&
10
- expected_attributes?(resource)
11
- end
12
- else
13
- chef_run.resources.any? do |resource|
14
- expected_resource?(resource,command)
15
- end
16
- end
17
- end
18
-
19
- chain :with do |attributes|
20
- @attributes = attributes
21
- end
22
-
23
- def expected_resource?(resource,command)
24
- resource_type(resource) == 'execute' &&
25
- command === resource.command
26
- end
27
-
28
- def expected_attributes?(resource)
29
- @attributes.all? { |k,v| resource.send(k) == v }
30
- end
31
- end
32
- end
33
- end