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
@@ -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