chefspec-bootstrap 0.0.2 → 0.0.3

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.
data/README.md CHANGED
@@ -23,10 +23,6 @@ require 'chefspec'
23
23
  describe 'cookbook::recipe' do
24
24
  let(:chef_run) { ChefSpec::Runner.new.converge(described_recipe) }
25
25
 
26
- it 'runs successfully' do
27
- expect{chef_run}.not_to raise_error
28
- end
29
-
30
26
  it "installs the apache2 package" do
31
27
  expect(chef_run).to install_package("apache2")
32
28
  end
@@ -3,11 +3,21 @@
3
3
  require 'chefspec-bootstrap'
4
4
  require 'trollop'
5
5
 
6
+ cookbook_path_help_text = "RSpec config for cookbook path. Defaults to RSpec.configure.cookbook_path from spec_helper.rb."
7
+
6
8
  opts = Trollop::options do
7
9
  opt :cookbooks_dir, "Your site cookbooks directory", :type => :string, :default => "site-cookbooks"
10
+ opt :cookbooks_path, cookbook_path_help_text, :type => :strings
11
+ opt :recursive, "Generate specs for included recipes."
8
12
  opt :spec_dir, "Your spec directory", :type => :string, :default => "spec"
9
13
  opt :template, "ERB template file used to generate specs", :type => :string
10
14
  end
11
15
 
12
- bootstrap = ChefSpec::Bootstrap.new(opts[:cookbooks_dir], opts[:spec_dir], opts[:template])
16
+ bootstrap = ChefSpec::Bootstrap.new(
17
+ opts[:cookbooks_dir],
18
+ opts[:cookbooks_path],
19
+ opts[:spec_dir],
20
+ opts[:template],
21
+ opts[:recursive]
22
+ )
13
23
  bootstrap.generate()
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'chefspec-bootstrap'
3
- s.version = '0.0.2'
3
+ s.version = '0.0.3'
4
4
  s.date = '2014-06-02'
5
5
  s.summary = "Bootstrap your ChefSpec tests."
6
6
  s.description = "Automatically generate ChefSpec tests based on your recipes."
data/lib/api_map.rb ADDED
@@ -0,0 +1,84 @@
1
+ module ChefSpec
2
+ class APIMap
3
+
4
+ IT_CREATE_IF_MISSING = "creates the %{adjective} %{noun} if it is missing"
5
+ IT_MODIFY = "modifies the %{adjective} %{noun}"
6
+ IT_TOUCH = "touches the %{adjective} %{noun}"
7
+ EXPECT_CREATE_IF_MISSING = "create_%{noun}_if_missing"
8
+
9
+ def map
10
+ {
11
+ :cookbook_file => {
12
+ :it => { :create_if_missing => IT_CREATE_IF_MISSING },
13
+ :expect => { :create_if_missing => EXPECT_CREATE_IF_MISSING }
14
+ },
15
+ :deploy => {
16
+ :it => { :force_deploy => "force deploys the %{adjective} %{noun}" }
17
+ },
18
+ :env => {
19
+ :it => { :modify => IT_MODIFY }
20
+ },
21
+ :execute => {
22
+ :it => { :run => "executes %{adjective}" }
23
+ },
24
+ :file => {
25
+ :it => {
26
+ :create_if_missing => IT_CREATE_IF_MISSING,
27
+ :touch => IT_TOUCH
28
+ },
29
+ :expect => { :create_if_missing => EXPECT_CREATE_IF_MISSING }
30
+ },
31
+ :git => {
32
+ :it => {
33
+ :default => "%{verb}s the %{adjective} git repository",
34
+ :checkout => "checks out the %{adjective} git repository"
35
+ }
36
+ },
37
+ :group => {
38
+ :it => { :modify => IT_MODIFY }
39
+ },
40
+ :http_request => {
41
+ :it => {
42
+ :default => "performs a %{verb} HTTP request to %{adjective}"
43
+ }
44
+ },
45
+ :ifconfig => {
46
+ :it => {
47
+ :default => "%{verb}s the %{adjective} network interface using %{noun}"
48
+ }
49
+ },
50
+ :registry_key => {
51
+ :it => {
52
+ :create_if_missing => IT_CREATE_IF_MISSING,
53
+ :delete => "%{verb}s the %{adjective} %{noun} value"
54
+ },
55
+ :expect => { :create_if_missing => EXPECT_CREATE_IF_MISSING }
56
+ },
57
+ :remote_directory => {
58
+ :it => { :create_if_missing => IT_CREATE_IF_MISSING },
59
+ :expect => { :create_if_missing => EXPECT_CREATE_IF_MISSING }
60
+ },
61
+ :remote_file => {
62
+ :it => {
63
+ :create_if_missing => IT_CREATE_IF_MISSING,
64
+ :touch => IT_TOUCH
65
+ },
66
+ :expect => { :create_if_missing => EXPECT_CREATE_IF_MISSING }
67
+ },
68
+ :subversion => {
69
+ :it => {
70
+ :default => "%{verb}s the %{adjective} svn repository",
71
+ :checkout => "checks out the %{adjective} svn repository"
72
+ }
73
+ },
74
+ :template => {
75
+ :it => {
76
+ :create_if_missing => IT_CREATE_IF_MISSING,
77
+ :touch => IT_TOUCH
78
+ },
79
+ :expect => { :create_if_missing => EXPECT_CREATE_IF_MISSING }
80
+ }
81
+ }
82
+ end
83
+ end
84
+ end
@@ -2,14 +2,17 @@ require 'erb'
2
2
  require 'fileutils'
3
3
  require 'ostruct'
4
4
  require 'chefspec'
5
+ require_relative 'api_map'
5
6
 
6
7
  module ChefSpec
7
8
  class Bootstrap
8
9
 
9
- def initialize(cookbooks_dir, spec_dir, template_file)
10
+ def initialize(cookbooks_dir, cookbooks_path, spec_dir, template_file, recursive)
10
11
  @cookbooks_dir = cookbooks_dir
12
+ @cookbooks_path = cookbooks_path
11
13
  @spec_dir = spec_dir
12
14
  @template_file = template_file
15
+ @recursive = recursive
13
16
  end
14
17
 
15
18
  def setup
@@ -24,6 +27,18 @@ module ChefSpec
24
27
  if not File.exist?(@template_file)
25
28
  abort "Unable to locate template file (#{@template_file})"
26
29
  end
30
+
31
+ @api_map = ChefSpec::APIMap.new.map
32
+
33
+ begin
34
+ require File.expand_path("#{@spec_dir}/spec_helper.rb")
35
+ @spec_helper = true
36
+ rescue LoadError
37
+ @spec_helper = false
38
+ ::RSpec.configure do |config|
39
+ config.cookbook_path = @cookbooks_path || [@cookbooks_dir, 'cookbooks']
40
+ end
41
+ end
27
42
  end
28
43
 
29
44
  def generate
@@ -31,14 +46,6 @@ module ChefSpec
31
46
 
32
47
  erb = ERB.new(File.read(@template_file))
33
48
 
34
- # begin
35
- # require "#{@spec_dir}/spec_helper.rb"
36
- # rescue LoadError
37
-
38
- # end
39
-
40
- ::RSpec.configure { |config| config.cookbook_path = [@cookbooks_dir, 'cookbooks'] }
41
-
42
49
  Dir.glob("#{@cookbooks_dir}/*/recipes/*").each do |path|
43
50
  path, recipe_file = File.split(path)
44
51
  recipe = recipe_file.split('.')[0]
@@ -62,7 +69,7 @@ module ChefSpec
62
69
  puts " execution failed. Creating empty spec file."
63
70
  end
64
71
 
65
- resources = get_resources(chef_run)
72
+ resources = get_resources(chef_run, cookbook, recipe)
66
73
  test_cases = generate_test_cases(resources)
67
74
 
68
75
  File.open(filename, "w") do |spec_file|
@@ -79,7 +86,7 @@ module ChefSpec
79
86
  def get_chef_run(cookbook, recipe)
80
87
  begin
81
88
  return ChefSpec::Runner.new.converge("#{cookbook}::#{recipe}")
82
- rescue
89
+ rescue Exception => e
83
90
  return nil
84
91
  end
85
92
  end
@@ -88,9 +95,20 @@ module ChefSpec
88
95
  return resource.name || resource.identity
89
96
  end
90
97
 
91
- def get_resources(chef_run)
98
+ def get_all_resources(chef_run)
99
+ return chef_run.resource_collection.all_resources
100
+ end
101
+
102
+ def get_resources(chef_run, cookbook, recipe)
92
103
  if chef_run
93
- return chef_run.resource_collection.all_resources
104
+ resources = get_all_resources(chef_run)
105
+ if @recursive
106
+ return resources
107
+ else
108
+ return resources.select do |resource|
109
+ resource.cookbook_name == cookbook.to_sym and resource.recipe_name == recipe
110
+ end
111
+ end
94
112
  else
95
113
  return []
96
114
  end
@@ -110,8 +128,8 @@ module ChefSpec
110
128
  verbs.each do |verb|
111
129
  if not verb == :nothing
112
130
  test_cases.push({
113
- :it => "#{verb}s the #{adjective} #{noun}",
114
- :action => "#{verb}_#{noun}",
131
+ :it => get_it_block(noun, verb, adjective),
132
+ :expect => get_expect_block(noun, verb),
115
133
  :name => adjective
116
134
  })
117
135
  end
@@ -119,5 +137,42 @@ module ChefSpec
119
137
  end
120
138
  return test_cases
121
139
  end
140
+
141
+ def get_it_block(noun, verb, adjective)
142
+ it = "%{verb}s the %{adjective} %{noun}"
143
+ noun_readable = noun.to_s.gsub("_", " ")
144
+ verb_readable = verb.to_s.gsub("_", " ")
145
+ string_variables = {:noun => noun_readable, :verb => verb_readable, :adjective => adjective}
146
+
147
+ if @api_map[noun] and @api_map[noun][:it]
148
+ if @api_map[noun][:it][verb]
149
+ it = @api_map[noun][:it][verb]
150
+ elsif @api_map[noun][:it][:default]
151
+ it = @api_map[noun][:it][:default]
152
+ end
153
+ end
154
+
155
+ return escape_string(it % string_variables)
156
+ end
157
+
158
+ def get_expect_block(noun, verb)
159
+ expect = "%{verb}_%{noun}"
160
+ string_variables = {:noun => noun, :verb => verb}
161
+
162
+ if @api_map[noun] and @api_map[noun][:expect]
163
+ if @api_map[noun][:expect][verb]
164
+ expect = @api_map[noun][:expect][verb]
165
+ elsif @api_map[noun][:expect][:default]
166
+ expect = @api_map[noun][:expect][:default]
167
+ end
168
+ end
169
+
170
+ return escape_string(expect % string_variables)
171
+ end
172
+
173
+ def escape_string(string)
174
+ return string.gsub("\\","\\\\").gsub("\"", "\\\"")
175
+ end
176
+
122
177
  end
123
178
  end
@@ -1,13 +1,12 @@
1
1
  require 'chefspec'
2
2
 
3
3
  describe '<%= cookbook %>::<%= recipe %>' do
4
- let(:chef_run) { ChefSpec::Runner.new.converge(described_recipe) }
4
+ let(:chef_run) { ChefSpec::Runner.new.converge(described_recipe) }<% if not test_cases.empty? %><% test_cases.each do |test_case| %>
5
5
 
6
+ it "<%= test_case[:it] %>" do
7
+ expect(chef_run).to <%= test_case[:expect] %>("<%= test_case[:name] %>")
8
+ end<% end %><% else %>
6
9
  it 'runs successfully' do
7
10
  expect{chef_run}.not_to raise_error
8
- end<% if test_cases %><% test_cases.each do |test_case| %>
9
-
10
- it "<%= test_case[:it] %>" do
11
- expect(chef_run).to <%= test_case[:action] %>("<%= test_case[:name] %>")
12
- end<% end %><% end %>
11
+ end<% end %>
13
12
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chefspec-bootstrap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -55,6 +55,7 @@ files:
55
55
  - README.md
56
56
  - bin/chefspec-bootstrap
57
57
  - chefspec-bootstrap.gemspec
58
+ - lib/api_map.rb
58
59
  - lib/chefspec-bootstrap.rb
59
60
  - templates/default.erb
60
61
  homepage: http://rubygems.org/gems/chefspec-bootstrap