chefspec-bootstrap 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +0 -4
- data/bin/chefspec-bootstrap +11 -1
- data/chefspec-bootstrap.gemspec +1 -1
- data/lib/api_map.rb +84 -0
- data/lib/chefspec-bootstrap.rb +70 -15
- data/templates/default.erb +5 -6
- metadata +2 -1
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
|
data/bin/chefspec-bootstrap
CHANGED
@@ -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(
|
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()
|
data/chefspec-bootstrap.gemspec
CHANGED
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
|
data/lib/chefspec-bootstrap.rb
CHANGED
@@ -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
|
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
|
-
|
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 =>
|
114
|
-
:
|
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
|
data/templates/default.erb
CHANGED
@@ -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<%
|
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.
|
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
|