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,17 @@
1
+ RSpec.configure do |config|
2
+ config.include(ChefSpec::API)
3
+ config.include(ChefSpec::Macros)
4
+
5
+ config.after(:each) do
6
+ ChefSpec::Stubs::CommandRegistry.reset!
7
+ ChefSpec::Stubs::DataBagRegistry.reset!
8
+ ChefSpec::Stubs::DataBagItemRegistry.reset!
9
+ ChefSpec::Stubs::SearchRegistry.reset!
10
+ end
11
+
12
+ config.add_setting :cookbook_path
13
+ config.add_setting :log_level, default: :warn
14
+ config.add_setting :path
15
+ config.add_setting :platform
16
+ config.add_setting :version
17
+ end
@@ -0,0 +1,274 @@
1
+ require 'fauxhai'
2
+ require 'chef/client'
3
+ require 'chef/mash'
4
+ require 'chef/providers'
5
+ require 'chef/resources'
6
+
7
+ module ChefSpec
8
+ class Runner
9
+ #
10
+ # Defines a new runner method on the +ChefSpec::Runner+.
11
+ #
12
+ # @param [Symbol] resource_name
13
+ # the name of the resource to define a method
14
+ #
15
+ # @return [self]
16
+ #
17
+ def self.define_runner_method(resource_name)
18
+ define_method(resource_name) do |identity|
19
+ find_resource(resource_name, identity)
20
+ end
21
+
22
+ self
23
+ end
24
+
25
+ # @return [Hash]
26
+ attr_reader :options
27
+
28
+ # @return [Chef::RunContext]
29
+ attr_reader :run_context
30
+
31
+ #
32
+ # Instantiate a new Runner to run examples with.
33
+ #
34
+ # @example Instantiate a new Runner
35
+ # ChefSpec::Runner.new
36
+ #
37
+ # @example Specifying the platform and version
38
+ # ChefSpec::Runner.new(platform: 'ubuntu', version: '12.04')
39
+ #
40
+ # @example Specifying the cookbook path
41
+ # ChefSpec::Runner.new(cookbook_path: ['/cookbooks'])
42
+ #
43
+ # @example Specifying the log level
44
+ # ChefSpec::Runner.new(log_level: :info)
45
+ #
46
+ #
47
+ # @param [Hash] options
48
+ # The options for the new runner
49
+ #
50
+ # @option options [Symbol] :log_level
51
+ # The log level to use (default is :warn)
52
+ # @option options [String] :platform
53
+ # The platform to load Ohai attributes from (must be present in fauxhai)
54
+ # @option options [String] :version
55
+ # The version of the platform to load Ohai attributes from (must be present in fauxhai)
56
+ # @option options [String] :path
57
+ # Path of a json file that will be passed to fauxhai as :path option
58
+ # @option options [Array<String>] :step_into
59
+ # The list of LWRPs to evaluate
60
+ #
61
+ # @yield [node] Configuration block for Chef::Node
62
+ #
63
+ def initialize(options = {}, &block)
64
+ @options = options = {
65
+ cookbook_path: RSpec.configuration.cookbook_path || calling_cookbook_path(caller),
66
+ log_level: RSpec.configuration.log_level,
67
+ path: RSpec.configuration.path,
68
+ platform: RSpec.configuration.platform,
69
+ version: RSpec.configuration.version,
70
+ }.merge(options)
71
+
72
+ Chef::Log.level = options[:log_level]
73
+
74
+ Chef::Config.reset!
75
+ Chef::Config.formatters.clear
76
+ Chef::Config.add_formatter('chefspec')
77
+ Chef::Config[:cache_type] = 'Memory'
78
+ Chef::Config[:cookbook_path] = Array(options[:cookbook_path])
79
+ Chef::Config[:force_logger] = true
80
+ Chef::Config[:solo] = true
81
+
82
+ yield node if block_given?
83
+ end
84
+
85
+ #
86
+ # Execute the specified recipes on the node, without actually converging
87
+ # the node. This is the equivalent of `chef-apply`.
88
+ #
89
+ # @example Converging a single recipe
90
+ # chef_run.apply('example::default')
91
+ #
92
+ # @example Converging multiple recipes
93
+ # chef_run.apply('example::default', 'example::secondary')
94
+ #
95
+ #
96
+ # @param [Array] recipe_names
97
+ # The names of the recipe or recipes to apply
98
+ #
99
+ # @return [ChefSpec::Runner]
100
+ # A reference to the calling Runner (for chaining purposes)
101
+ #
102
+ def apply(*recipe_names)
103
+ recipe_names.each do |recipe_name|
104
+ cookbook, recipe = Chef::Recipe.parse_recipe_name(recipe_name)
105
+ recipe_path = File.join(Dir.pwd, 'recipes', "#{recipe}.rb")
106
+
107
+ recipe = Chef::Recipe.new(cookbook, recipe, run_context)
108
+ recipe.from_file(recipe_path)
109
+ end
110
+
111
+ @resources = {}
112
+ @run_context = Chef::RunContext.new(client.node, {}, client.events)
113
+
114
+ Chef::Runner.new(@run_context).converge
115
+ self
116
+ end
117
+
118
+ #
119
+ # Execute the given `run_list` on the node, without actually converging
120
+ # the node.
121
+ #
122
+ # @example Converging a single recipe
123
+ # chef_run.converge('example::default')
124
+ #
125
+ # @example Converging multiple recipes
126
+ # chef_run.converge('example::default', 'example::secondary')
127
+ #
128
+ #
129
+ # @param [Array] recipe_names
130
+ # The names of the recipe or recipes to converge
131
+ #
132
+ # @return [ChefSpec::Runner]
133
+ # A reference to the calling Runner (for chaining purposes)
134
+ #
135
+ def converge(*recipe_names)
136
+ node.run_list.reset!
137
+ recipe_names.each { |recipe_name| node.run_list.add(recipe_name) }
138
+
139
+ return self if dry_run?
140
+
141
+ # Reset the resource collection
142
+ @resources = {}
143
+
144
+ client.build_node
145
+ @run_context = client.setup_run_context
146
+
147
+ Chef::Runner.new(@run_context).converge
148
+ self
149
+ end
150
+
151
+ #
152
+ # The +Chef::Node+ corresponding to this Runner.
153
+ #
154
+ # @return [Chef::Node]
155
+ #
156
+ def node
157
+ return @node if @node
158
+
159
+ @node = client.node
160
+ @node.instance_variable_set(:@runner, self)
161
+ @node.class.send(:attr_reader, :runner)
162
+ @node
163
+ end
164
+
165
+ #
166
+ # The full collection of resources for this Runner.
167
+ #
168
+ # @return [Hash<String, Chef::Resource>]
169
+ #
170
+ def resources
171
+ @resources ||= {}
172
+ end
173
+
174
+ #
175
+ # Find the resource with the declared type and resource name.
176
+ #
177
+ # @example Find a template at `/etc/foo`
178
+ # chef_run.find_resource(:template, '/etc/foo') #=> #<Chef::Resource::Template>
179
+ #
180
+ #
181
+ # @param [Symbol] type
182
+ # The type of resource (sometimes called `resource_name`) such as `file`
183
+ # or `directory`.
184
+ # @param [String, Regexp] name
185
+ # The value of the name attribute or identity attribute for the resource.
186
+ #
187
+ # @return [Chef::Resource, nil]
188
+ # The matching resource, or nil if one is not found
189
+ #
190
+ def find_resource(type, name)
191
+ return resources["#{type}[#{name}]"] if resources["#{type}[#{name}]"]
192
+
193
+ resources.values.find do |resource|
194
+ resource.resource_name.to_sym == type && (name === resource.identity || name === resource.name)
195
+ end
196
+ end
197
+
198
+ #
199
+ # Find the resource with the declared type.
200
+ #
201
+ # @example Find all template resources
202
+ # chef_run.find_resources('template') #=> [#<Chef::Resource::Template>, #...]
203
+ #
204
+ #
205
+ # @param [Symbol] type
206
+ # The type of resource such as `:file` or `:directory`.
207
+ #
208
+ # @return [Array<Chef::Resource>]
209
+ # The matching resources
210
+ #
211
+ def find_resources(type)
212
+ resources.select do |_, resource|
213
+ resource.resource_name.to_s == type.to_s
214
+ end
215
+ end
216
+
217
+ #
218
+ # The list of LWRPs to step into and evaluate.
219
+ #
220
+ # @return [Array<String>]
221
+ #
222
+ def step_into
223
+ @step_into ||= Array(options[:step_into] || [])
224
+ end
225
+
226
+ #
227
+ # Boolean method to determine if this Runner is in `dry_run` mode.
228
+ #
229
+ # @return [Boolean]
230
+ #
231
+ def dry_run?
232
+ !!options[:dry_run]
233
+ end
234
+
235
+ #
236
+ # This runner as a string.
237
+ #
238
+ # @return [String] Currently includes the run_list. Format of the string may change between versions of this gem.
239
+ #
240
+ def to_s
241
+ return "chef_run: #{node.run_list.to_s}" unless node.run_list.empty?
242
+ 'chef_run'
243
+ end
244
+
245
+ #
246
+ # The runner as a String with helpful output.
247
+ #
248
+ # @return [String]
249
+ #
250
+ def inspect
251
+ "#<#{self.class} options: #{options.inspect}, run_list: '#{node.run_list.to_s}'>"
252
+ end
253
+
254
+ private
255
+ def calling_cookbook_path(kaller)
256
+ calling_spec = kaller.find { |line| line =~ /\/spec/ }
257
+ bits = calling_spec.split(':', 2).first.split(File::SEPARATOR)
258
+ spec_dir = bits.index('spec') || 0
259
+
260
+ File.expand_path(File.join(bits.slice(0, spec_dir), '..'))
261
+ end
262
+
263
+ #
264
+ def client
265
+ return @client if @client
266
+
267
+ @client = Chef::Client.new
268
+ @client.ohai.data = Mash.from_hash(Fauxhai.mock(options).data)
269
+ @client.load_node
270
+ @client.build_node
271
+ @client
272
+ end
273
+ end
274
+ end
@@ -0,0 +1,11 @@
1
+ require_relative 'registry'
2
+
3
+ module ChefSpec
4
+ module Stubs
5
+ class CommandRegistry < Registry
6
+ def stub_for(command)
7
+ @stubs.find { |stub| stub.command === command }
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,37 @@
1
+ require_relative 'stub'
2
+
3
+ module ChefSpec
4
+ module Stubs
5
+ class CommandStub < Stub
6
+ attr_reader :block
7
+ attr_reader :command
8
+ attr_reader :value
9
+
10
+ def initialize(command, &block)
11
+ @command = command
12
+ @block = block
13
+ end
14
+
15
+ def and_return(value)
16
+ @value = value
17
+ self
18
+ end
19
+
20
+ def result
21
+ if @block
22
+ @block.call
23
+ else
24
+ @value
25
+ end
26
+ end
27
+
28
+ def signature
29
+ if @block
30
+ "stub_command(#{@command.inspect}) { # Ruby code }"
31
+ else
32
+ "stub_command(#{@command.inspect}).and_return(#{@value})"
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,13 @@
1
+ require_relative 'registry'
2
+
3
+ module ChefSpec
4
+ module Stubs
5
+ class DataBagItemRegistry < Registry
6
+ def stub_for(bag, id)
7
+ @stubs.find do |stub|
8
+ stub.bag.to_s == bag.to_s && stub.id === id
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,25 @@
1
+ require_relative 'stub'
2
+
3
+ module ChefSpec
4
+ module Stubs
5
+ class DataBagItemStub < Stub
6
+ attr_reader :block
7
+ attr_reader :id
8
+ attr_reader :bag
9
+
10
+ def initialize(bag, id, &block)
11
+ @bag = bag.to_s
12
+ @id = id
13
+ @block = block
14
+ end
15
+
16
+ def signature
17
+ if @block
18
+ "stub_data_bag_item(#{@bag.inspect}, #{@id.inspect}) { # Ruby code }"
19
+ else
20
+ "stub_data_bag_item(#{@bag.inspect}, #{@id.inspect}).and_return(#{@value})"
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,13 @@
1
+ require_relative 'registry'
2
+
3
+ module ChefSpec
4
+ module Stubs
5
+ class DataBagRegistry < Registry
6
+ def stub_for(bag)
7
+ @stubs.find do |stub|
8
+ stub.bag.to_s == bag.to_s
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,23 @@
1
+ require_relative 'stub'
2
+
3
+ module ChefSpec
4
+ module Stubs
5
+ class DataBagStub < Stub
6
+ attr_reader :block
7
+ attr_reader :bag
8
+
9
+ def initialize(bag, &block)
10
+ @bag = bag.to_s
11
+ @block = block
12
+ end
13
+
14
+ def signature
15
+ if @block
16
+ "stub_data_bag(#{@bag.inspect}) { # Ruby code }"
17
+ else
18
+ "stub_data_bag(#{@bag.inspect}).and_return(#{@value})"
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,32 @@
1
+ module ChefSpec
2
+ module Stubs
3
+ class Registry
4
+ class << self
5
+ extend Forwardable
6
+ def_delegators :instance, :reset!, :register, :stubs, :stubs=, :stub_for
7
+ end
8
+
9
+ include Singleton
10
+
11
+ # @return [Hash<Symbol, Array<SearchStub>>]
12
+ attr_accessor :stubs
13
+
14
+ def initialize
15
+ reset!
16
+ end
17
+
18
+ def reset!
19
+ @stubs = []
20
+ end
21
+
22
+ def register(stub)
23
+ @stubs.insert(0, stub)
24
+ stub
25
+ end
26
+
27
+ def stub_for(*args)
28
+ raise ArgumentError, '#stub_for is an abstract function'
29
+ end
30
+ end
31
+ end
32
+ end