chefspec 2.0.1 → 3.0.0.beta.1

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