chefspec 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,107 @@
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
data/lib/chefspec.rb CHANGED
@@ -8,5 +8,6 @@ require 'chefspec/matchers/log'
8
8
  require 'chefspec/matchers/package'
9
9
  require 'chefspec/matchers/service'
10
10
  require 'chefspec/matchers/shared'
11
+ require 'chefspec/matchers/file_content'
11
12
  require 'chefspec/monkey_patches/hash'
12
13
  require 'chefspec/monkey_patches/provider'
@@ -0,0 +1,27 @@
1
+ require 'chefspec/matchers/shared'
2
+
3
+ module ChefSpec
4
+ module Matchers
5
+ RSpec::Matchers.define :create_file_with_content do |path, content|
6
+ match do |chef_run|
7
+ chef_run.resources.any? do |resource|
8
+ if resource.name == path
9
+ if resource.action.include?(:create) || resource.action.include?(:create_if_missing)
10
+ case resource_type(resource)
11
+ when 'template'
12
+ @actual_content = render(resource, chef_run.node)
13
+ content == @actual_content
14
+ when 'file'
15
+ @actual_content = resource.content
16
+ content == @actual_content
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ failure_message_for_should do |actual|
23
+ "File content:\n#{@actual_content} does not match expected:\n#{content}"
24
+ end
25
+ end
26
+ end
27
+ end
@@ -1,6 +1,7 @@
1
1
  require 'chefspec/matchers/shared'
2
2
 
3
3
  module ChefSpec
4
+ # RSpec Matchers
4
5
  module Matchers
5
6
  RSpec::Matchers.define :log do |message|
6
7
  match do |chef_run|
@@ -30,4 +30,24 @@ def define_resource_matchers(actions, resource_types, name_attribute)
30
30
  end
31
31
  end
32
32
  end
33
- end
33
+ end
34
+
35
+ # Render a template.
36
+ #
37
+ # @param [Chef::Resource::Template] template The template to render
38
+ # @param [Chef::Node] node The node which may be required to render the template
39
+ # @return [String] The result result of rendering the template
40
+ def render(template, node)
41
+ # Duplicates functionality in the Chef Template provider
42
+ context = {}; context.merge!(template.variables)
43
+ context[:node] = node
44
+ Erubis::Eruby.new(IO.read(template_path(template))).evaluate(context)
45
+ end
46
+
47
+ # Given a template, return the path on disk.
48
+ #
49
+ # @param [Chef::Resource::Template] template The template
50
+ # @return [String] The path on disk
51
+ def template_path(template)
52
+ File.join("cookbooks/#{template.cookbook || template.cookbook_name}/templates/default", template.source)
53
+ end
@@ -1,9 +1,16 @@
1
1
  # Override Chef LWRP creation to remove existing class to avoid redefinition warnings.
2
2
  class Chef
3
+ # Chef provider for a resource
3
4
  class Provider
4
5
  class << self
5
- alias :old_build_from_file :build_from_file
6
+ alias_method :old_build_from_file, :build_from_file
6
7
 
8
+ # Override Opscode provider to remove any existing LWRP
9
+ #
10
+ # @param [String] cookbook_name The name of the cookbook
11
+ # @param [String] filename File to load as a LWRP
12
+ # @param [Chef::RunContext] run_context Context of a Chef Run
13
+ # @return [Chef::Provider] the created provider
7
14
  def build_from_file(cookbook_name, filename, run_context)
8
15
  remove_existing_lwrp(convert_to_class_name(filename_to_qualified_string(cookbook_name, filename)))
9
16
  old_build_from_file(cookbook_name, filename, run_context)
@@ -1,3 +1,4 @@
1
1
  module ChefSpec
2
- VERSION = '0.2.1'
3
- end
2
+ # The gem version
3
+ VERSION = '0.3.0'
4
+ end
metadata CHANGED
@@ -1,73 +1,63 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: chefspec
3
- version: !ruby/object:Gem::Version
4
- hash: 21
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
5
  prerelease:
6
- segments:
7
- - 0
8
- - 2
9
- - 1
10
- version: 0.2.1
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Andrew Crump
14
9
  autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
-
18
- date: 2011-09-21 00:00:00 Z
19
- dependencies:
20
- - !ruby/object:Gem::Dependency
21
- version_requirements: &id001 !ruby/object:Gem::Requirement
12
+ date: 2011-10-02 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: chef
16
+ requirement: &2151873320 !ruby/object:Gem::Requirement
22
17
  none: false
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- hash: 35
27
- segments:
28
- - 0
29
- - 9
30
- - 12
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
31
21
  version: 0.9.12
32
22
  - - ~>
33
- - !ruby/object:Gem::Version
34
- hash: 31
35
- segments:
36
- - 0
37
- - 10
38
- version: "0.10"
39
- name: chef
23
+ - !ruby/object:Gem::Version
24
+ version: '0.10'
40
25
  type: :runtime
41
26
  prerelease: false
42
- requirement: *id001
43
- - !ruby/object:Gem::Dependency
44
- version_requirements: &id002 !ruby/object:Gem::Requirement
27
+ version_requirements: *2151873320
28
+ - !ruby/object:Gem::Dependency
29
+ name: erubis
30
+ requirement: &2151885360 !ruby/object:Gem::Requirement
45
31
  none: false
46
- requirements:
47
- - - ">="
48
- - !ruby/object:Gem::Version
49
- hash: 23
50
- segments:
51
- - 2
52
- - 6
53
- - 0
54
- version: 2.6.0
32
+ requirements:
33
+ - - ! '>='
34
+ - !ruby/object:Gem::Version
35
+ version: '0'
36
+ type: :runtime
37
+ prerelease: false
38
+ version_requirements: *2151885360
39
+ - !ruby/object:Gem::Dependency
55
40
  name: rspec
41
+ requirement: &2151891840 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: 2.6.0
56
47
  type: :runtime
57
48
  prerelease: false
58
- requirement: *id002
49
+ version_requirements: *2151891840
59
50
  description: Write RSpec examples for Opscode Chef recipes
60
51
  email:
61
52
  executables: []
62
-
63
53
  extensions: []
64
-
65
54
  extra_rdoc_files: []
66
-
67
- files:
55
+ files:
56
+ - lib/chef/knife/cookbook_create_specs.rb
68
57
  - lib/chefspec/chef_runner.rb
69
58
  - lib/chefspec/matchers/execute.rb
70
59
  - lib/chefspec/matchers/file.rb
60
+ - lib/chefspec/matchers/file_content.rb
71
61
  - lib/chefspec/matchers/log.rb
72
62
  - lib/chefspec/matchers/package.rb
73
63
  - lib/chefspec/matchers/service.rb
@@ -77,37 +67,34 @@ files:
77
67
  - lib/chefspec/version.rb
78
68
  - lib/chefspec.rb
79
69
  homepage: http://acrmp.github.com/chefspec
80
- licenses:
70
+ licenses:
81
71
  - MIT
82
72
  post_install_message:
83
73
  rdoc_options: []
84
-
85
- require_paths:
74
+ require_paths:
86
75
  - lib
87
- required_ruby_version: !ruby/object:Gem::Requirement
76
+ required_ruby_version: !ruby/object:Gem::Requirement
88
77
  none: false
89
- requirements:
90
- - - ">="
91
- - !ruby/object:Gem::Version
92
- hash: 3
93
- segments:
78
+ requirements:
79
+ - - ! '>='
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ segments:
94
83
  - 0
95
- version: "0"
96
- required_rubygems_version: !ruby/object:Gem::Requirement
84
+ hash: 4357686734109657142
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
97
86
  none: false
98
- requirements:
99
- - - ">="
100
- - !ruby/object:Gem::Version
101
- hash: 3
102
- segments:
87
+ requirements:
88
+ - - ! '>='
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ segments:
103
92
  - 0
104
- version: "0"
93
+ hash: 4357686734109657142
105
94
  requirements: []
106
-
107
95
  rubyforge_project:
108
96
  rubygems_version: 1.8.6
109
97
  signing_key:
110
98
  specification_version: 3
111
- summary: chefspec-0.2.1
99
+ summary: chefspec-0.3.0
112
100
  test_files: []
113
-