berkshelf 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. data/.gitignore +20 -0
  2. data/.rbenv-version +1 -0
  3. data/Gemfile +3 -0
  4. data/Guardfile +23 -0
  5. data/LICENSE +22 -0
  6. data/README.rdoc +102 -0
  7. data/Thorfile +47 -0
  8. data/berkshelf.gemspec +39 -0
  9. data/features/config.sample.yml +3 -0
  10. data/features/init_command.feature +40 -0
  11. data/features/install.feature +55 -0
  12. data/features/lockfile.feature +22 -0
  13. data/features/step_definitions/chef_server_steps.rb +13 -0
  14. data/features/step_definitions/cli_steps.rb +56 -0
  15. data/features/step_definitions/filesystem_steps.rb +79 -0
  16. data/features/support/env.rb +55 -0
  17. data/features/update.feature +23 -0
  18. data/features/upload_command.feature +43 -0
  19. data/features/without.feature +25 -0
  20. data/lib/berkshelf.rb +90 -0
  21. data/lib/berkshelf/berksfile.rb +170 -0
  22. data/lib/berkshelf/cached_cookbook.rb +253 -0
  23. data/lib/berkshelf/cookbook_source.rb +139 -0
  24. data/lib/berkshelf/cookbook_source/git_location.rb +54 -0
  25. data/lib/berkshelf/cookbook_source/path_location.rb +27 -0
  26. data/lib/berkshelf/cookbook_source/site_location.rb +206 -0
  27. data/lib/berkshelf/cookbook_store.rb +77 -0
  28. data/lib/berkshelf/core_ext.rb +3 -0
  29. data/lib/berkshelf/core_ext/file.rb +14 -0
  30. data/lib/berkshelf/core_ext/kernel.rb +33 -0
  31. data/lib/berkshelf/core_ext/pathname.rb +24 -0
  32. data/lib/berkshelf/downloader.rb +92 -0
  33. data/lib/berkshelf/dsl.rb +39 -0
  34. data/lib/berkshelf/errors.rb +20 -0
  35. data/lib/berkshelf/generator_files/Berksfile.erb +3 -0
  36. data/lib/berkshelf/generator_files/chefignore +44 -0
  37. data/lib/berkshelf/git.rb +70 -0
  38. data/lib/berkshelf/init_generator.rb +38 -0
  39. data/lib/berkshelf/lockfile.rb +42 -0
  40. data/lib/berkshelf/resolver.rb +176 -0
  41. data/lib/berkshelf/tx_result.rb +12 -0
  42. data/lib/berkshelf/tx_result_set.rb +37 -0
  43. data/lib/berkshelf/uploader.rb +153 -0
  44. data/lib/berkshelf/version.rb +3 -0
  45. data/lib/chef/knife/berks_init.rb +29 -0
  46. data/lib/chef/knife/berks_install.rb +27 -0
  47. data/lib/chef/knife/berks_update.rb +23 -0
  48. data/lib/chef/knife/berks_upload.rb +39 -0
  49. data/spec/fixtures/Berksfile +3 -0
  50. data/spec/fixtures/cookbooks/example_cookbook-0.5.0/README.md +12 -0
  51. data/spec/fixtures/cookbooks/example_cookbook-0.5.0/metadata.rb +6 -0
  52. data/spec/fixtures/cookbooks/example_cookbook-0.5.0/recipes/default.rb +8 -0
  53. data/spec/fixtures/cookbooks/example_cookbook/README.md +12 -0
  54. data/spec/fixtures/cookbooks/example_cookbook/metadata.rb +6 -0
  55. data/spec/fixtures/cookbooks/example_cookbook/recipes/default.rb +8 -0
  56. data/spec/fixtures/cookbooks/invalid_ruby_files-1.0.0/recipes/default.rb +1 -0
  57. data/spec/fixtures/cookbooks/invalid_template_files-1.0.0/templates/default/broken.erb +1 -0
  58. data/spec/fixtures/cookbooks/nginx-0.100.5/README.md +77 -0
  59. data/spec/fixtures/cookbooks/nginx-0.100.5/attributes/default.rb +65 -0
  60. data/spec/fixtures/cookbooks/nginx-0.100.5/definitions/nginx_site.rb +35 -0
  61. data/spec/fixtures/cookbooks/nginx-0.100.5/files/default/mime.types +73 -0
  62. data/spec/fixtures/cookbooks/nginx-0.100.5/files/ubuntu/mime.types +73 -0
  63. data/spec/fixtures/cookbooks/nginx-0.100.5/libraries/nginxlib.rb +1 -0
  64. data/spec/fixtures/cookbooks/nginx-0.100.5/metadata.rb +91 -0
  65. data/spec/fixtures/cookbooks/nginx-0.100.5/providers/defprovider.rb +1 -0
  66. data/spec/fixtures/cookbooks/nginx-0.100.5/recipes/default.rb +59 -0
  67. data/spec/fixtures/cookbooks/nginx-0.100.5/resources/defresource.rb +1 -0
  68. data/spec/fixtures/cookbooks/nginx-0.100.5/templates/default/nginx.pill.erb +15 -0
  69. data/spec/fixtures/cookbooks/nginx-0.100.5/templates/default/plugins/nginx.rb.erb +66 -0
  70. data/spec/fixtures/lockfile_spec/with_lock/Berksfile +1 -0
  71. data/spec/fixtures/lockfile_spec/without_lock/Berksfile.lock +5 -0
  72. data/spec/spec_helper.rb +92 -0
  73. data/spec/support/chef_api.rb +27 -0
  74. data/spec/support/matchers/file_system_matchers.rb +115 -0
  75. data/spec/support/matchers/filepath_matchers.rb +19 -0
  76. data/spec/unit/berkshelf/cached_cookbook_spec.rb +420 -0
  77. data/spec/unit/berkshelf/cookbook_source/git_location_spec.rb +59 -0
  78. data/spec/unit/berkshelf/cookbook_source/path_location_spec.rb +34 -0
  79. data/spec/unit/berkshelf/cookbook_source/site_location_spec.rb +166 -0
  80. data/spec/unit/berkshelf/cookbook_source_spec.rb +194 -0
  81. data/spec/unit/berkshelf/cookbook_store_spec.rb +71 -0
  82. data/spec/unit/berkshelf/cookbookfile_spec.rb +160 -0
  83. data/spec/unit/berkshelf/downloader_spec.rb +82 -0
  84. data/spec/unit/berkshelf/dsl_spec.rb +42 -0
  85. data/spec/unit/berkshelf/git_spec.rb +63 -0
  86. data/spec/unit/berkshelf/init_generator_spec.rb +52 -0
  87. data/spec/unit/berkshelf/lockfile_spec.rb +25 -0
  88. data/spec/unit/berkshelf/resolver_spec.rb +126 -0
  89. data/spec/unit/berkshelf/tx_result_set_spec.rb +77 -0
  90. data/spec/unit/berkshelf/tx_result_spec.rb +21 -0
  91. data/spec/unit/berkshelf/uploader_spec.rb +71 -0
  92. data/spec/unit/berkshelf_spec.rb +29 -0
  93. metadata +411 -0
@@ -0,0 +1 @@
1
+ cookbook 'nginx', '= 0.101.0'
@@ -0,0 +1,5 @@
1
+ cookbook 'nginx', :locked_version => '0.101.0'
2
+ cookbook 'build-essential', :locked_version => '1.0.2'
3
+ cookbook 'runit', :locked_version => '0.15.0'
4
+ cookbook 'bluepill', :locked_version => '1.0.4'
5
+ cookbook 'ohai', :locked_version => '1.0.2'
@@ -0,0 +1,92 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ require 'spork'
4
+ require 'vcr'
5
+
6
+ Spork.prefork do
7
+ require 'rspec'
8
+ require 'simplecov'
9
+ require 'pp'
10
+ require 'json_spec'
11
+ require 'webmock/rspec'
12
+
13
+ APP_ROOT = File.expand_path('../../', __FILE__)
14
+
15
+ Dir[File.join(APP_ROOT, "spec/support/**/*.rb")].each {|f| require f}
16
+
17
+ VCR.configure do |c|
18
+ c.cassette_library_dir = File.join(File.dirname(__FILE__), 'fixtures', 'vcr_cassettes')
19
+ c.hook_into :webmock
20
+ end
21
+
22
+ RSpec.configure do |config|
23
+ config.include Berkshelf::RSpec::FileSystemMatchers
24
+ config.include JsonSpec::Helpers
25
+
26
+ config.mock_with :rspec
27
+ config.treat_symbols_as_metadata_keys_with_true_values = true
28
+ config.filter_run :focus => true
29
+ config.run_all_when_everything_filtered = true
30
+
31
+ config.around do |example|
32
+ # Dynamically create cassettes based on the name of the example
33
+ # being run. This creates a new cassette for every test.
34
+ cur = example.metadata
35
+ identifiers = [example.metadata[:description_args]]
36
+ while cur = cur[:example_group] do
37
+ identifiers << cur[:description_args]
38
+ end
39
+
40
+ VCR.use_cassette(identifiers.reverse.join(' ')) do
41
+ example.run
42
+ end
43
+ end
44
+
45
+ config.before(:each) do
46
+ clean_tmp_path
47
+ Berkshelf.cookbook_store = Berkshelf::CookbookStore.new(tmp_path.join("downloader_tmp"))
48
+ end
49
+ end
50
+
51
+ SimpleCov.start do
52
+ add_filter 'spec/'
53
+ end
54
+
55
+ def capture(stream)
56
+ begin
57
+ stream = stream.to_s
58
+ eval "$#{stream} = StringIO.new"
59
+ yield
60
+ result = eval("$#{stream}").string
61
+ ensure
62
+ eval("$#{stream} = #{stream.upcase}")
63
+ end
64
+
65
+ result
66
+ end
67
+
68
+ def example_cookbook_from_path
69
+ @example_cookbook_from_path ||= Berkshelf::Cookbook.new('example_cookbook', path: File.join(File.dirname(__FILE__), 'fixtures', 'cookbooks'))
70
+ end
71
+
72
+ def app_root_path
73
+ Pathname.new(APP_ROOT)
74
+ end
75
+
76
+ def tmp_path
77
+ app_root_path.join('spec/tmp')
78
+ end
79
+
80
+ def fixtures_path
81
+ app_root_path.join('spec/fixtures')
82
+ end
83
+
84
+ def clean_tmp_path
85
+ FileUtils.rm_rf(tmp_path)
86
+ FileUtils.mkdir_p(tmp_path)
87
+ end
88
+ end
89
+
90
+ Spork.each_run do
91
+ require 'berkshelf'
92
+ end
@@ -0,0 +1,27 @@
1
+ require 'chef/rest'
2
+ require 'chef/cookbook_version'
3
+
4
+ module Berkshelf
5
+ module RSpec
6
+ module ChefAPI
7
+ def purge_cookbook(name, version)
8
+ rest.delete_rest("cookbooks/#{name}/#{version}?purge=true")
9
+ rescue Net::HTTPServerException => e
10
+ raise unless e.to_s =~ /^404/
11
+ end
12
+
13
+ def server_has_cookbook?(name, version)
14
+ rest.get_rest("cookbooks/#{name}/#{version}")
15
+ true
16
+ rescue Net::HTTPServerException => e
17
+ false
18
+ end
19
+
20
+ private
21
+
22
+ def rest
23
+ quietly { Chef::REST.new(Chef::Config[:chef_server_url]) }
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,115 @@
1
+ # Taken from (https://github.com/carlhuda/beard)
2
+ # Permission granted by Yehuda Katz (Jan 4th, 2012)
3
+ module Berkshelf
4
+ module RSpec
5
+ module FileSystemMatchers
6
+ class File
7
+ def initialize(name, &block)
8
+ @contents = []
9
+ @name = name
10
+
11
+ if block_given?
12
+ instance_eval(&block)
13
+ end
14
+ end
15
+
16
+ def contains(text)
17
+ @contents << text
18
+ end
19
+
20
+ def matches?(root)
21
+ unless root.join(@name).exist?
22
+ throw :failure, root.join(@name)
23
+ end
24
+
25
+ contents = ::File.read(root.join(@name))
26
+
27
+ @contents.each do |string|
28
+ unless contents.include?(string)
29
+ throw :failure, [root.join(@name), string, contents]
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ class Directory
36
+ attr_reader :tree
37
+
38
+ def initialize(root = nil, &block)
39
+ @tree = {}
40
+ @negative_tree = []
41
+ @root = root
42
+ instance_eval(&block) if block_given?
43
+ end
44
+
45
+ def directory(name, &block)
46
+ @tree[name] = block_given? && Directory.new(location(name), &block)
47
+ end
48
+
49
+ def file(name, &block)
50
+ @tree[name] = File.new(location(name), &block)
51
+ end
52
+
53
+ def no_file(name)
54
+ @negative_tree << name
55
+ end
56
+
57
+ def location(name)
58
+ [@root, name].compact.join("/")
59
+ end
60
+
61
+ def matches?(root)
62
+ @tree.each do |file, value|
63
+ unless value
64
+ unless root.join(location(file)).exist?
65
+ throw :failure, "#{root}/#{location(file)}"
66
+ end
67
+ else
68
+ value.matches?(root)
69
+ end
70
+ end
71
+
72
+ @negative_tree.each do |file|
73
+ if root.join(location(file)).exist?
74
+ throw :failure, [:not, "unexpected #{root}/#{location(file)}"]
75
+ end
76
+ end
77
+
78
+ nil
79
+ end
80
+ end
81
+
82
+ class Root < Directory
83
+ def failure_message
84
+ if @failure.is_a?(Array) && @failure[0] == :not
85
+ "Structure should not have had #{@failure[1]}, but it did"
86
+ elsif @failure.is_a?(Array)
87
+ "Structure should have #{@failure[0]} with #{@failure[1]}. It had:\n#{@failure[2]}"
88
+ else
89
+ "Structure should have #{@failure}, but it didn't"
90
+ end
91
+ end
92
+
93
+ def negative_failure_message
94
+ if @failure.is_a?(Array) && @failure[0] == :not
95
+ "Structure had #{@failure}, but it shouldn't have"
96
+ else
97
+ "Structure had #{@failure}, but it shouldn't have"
98
+ end
99
+ end
100
+
101
+ def matches?(root)
102
+ @failure = catch :failure do
103
+ super
104
+ end
105
+
106
+ !@failure
107
+ end
108
+ end
109
+
110
+ def have_structure(&block)
111
+ Root.new(&block)
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,19 @@
1
+ require 'pathname'
2
+
3
+ RSpec::Matchers.define :be_relative_path do
4
+ match do |given|
5
+ if given.nil?
6
+ false
7
+ else
8
+ Pathname.new(given).relative?
9
+ end
10
+ end
11
+
12
+ failure_message_for_should do |given|
13
+ "Expected '#{given}' to be a relative path but got an absolute path."
14
+ end
15
+
16
+ failure_message_for_should_not do |given|
17
+ "Expected '#{given}' to not be a relative path but got an absolute path."
18
+ end
19
+ end
@@ -0,0 +1,420 @@
1
+ require 'spec_helper'
2
+
3
+ module Berkshelf
4
+ describe CachedCookbook do
5
+ describe "ClassMethods" do
6
+ subject { CachedCookbook }
7
+
8
+ describe "#from_path" do
9
+ before(:each) do
10
+ @cached_cb = subject.from_path(fixtures_path.join("cookbooks", "example_cookbook-0.5.0"))
11
+ end
12
+
13
+ it "returns an instance of CachedCookbook" do
14
+ @cached_cb.should be_a(CachedCookbook)
15
+ end
16
+
17
+ it "sets a version number" do
18
+ @cached_cb.version.should eql("0.5.0")
19
+ end
20
+
21
+ context "given a path that does not contain a cookbook" do
22
+ it "returns nil" do
23
+ subject.from_path(tmp_path).should be_nil
24
+ end
25
+ end
26
+
27
+ context "given a path that does not match the CachedCookbook dirname format" do
28
+ it "returns nil" do
29
+ subject.from_path(fixtures_path.join("cookbooks", "example_cookbook")).should be_nil
30
+ end
31
+ end
32
+ end
33
+
34
+ describe "#checksum" do
35
+ it "returns a checksum of the given filepath" do
36
+ subject.checksum(fixtures_path.join("cookbooks", "example_cookbook-0.5.0", "README.md")).should eql("6e21094b7a920e374e7261f50e9c4eef")
37
+ end
38
+
39
+ context "given path does not exist" do
40
+ it "raises an Errno::ENOENT error" do
41
+ lambda {
42
+ subject.checksum(fixtures_path.join("notexisting.file"))
43
+ }.should raise_error(Errno::ENOENT)
44
+ end
45
+ end
46
+ end
47
+ end
48
+
49
+ let(:cb_path) { fixtures_path.join("cookbooks", "nginx-0.100.5") }
50
+ subject { CachedCookbook.from_path(cb_path) }
51
+
52
+ describe "#checksums" do
53
+ it "returns a Hash containing an entry for all matching cookbook files on disk" do
54
+ subject.checksums.should have(11).items
55
+ end
56
+
57
+ it "has a checksum for each key" do
58
+ subject.checksums.should have_key("fb1f925dcd5fc4ebf682c4442a21c619")
59
+ end
60
+
61
+ it "has a filepath for each value" do
62
+ subject.checksums.should have_value(cb_path.join("recipes/default.rb").to_s)
63
+ end
64
+ end
65
+
66
+ describe "#manifest" do
67
+ it "returns a Mash with a key for each cookbook file category" do
68
+ [
69
+ :recipes,
70
+ :definitions,
71
+ :libraries,
72
+ :attributes,
73
+ :files,
74
+ :templates,
75
+ :resources,
76
+ :providers,
77
+ :root_files
78
+ ].each do |category|
79
+ subject.manifest.should have_key(category)
80
+ end
81
+ end
82
+ end
83
+
84
+ describe "#validate!" do
85
+ it "returns true if the cookbook of the given name and version is valid" do
86
+ @cb = CachedCookbook.from_path(fixtures_path.join("cookbooks", "example_cookbook-0.5.0"))
87
+
88
+ @cb.validate!.should be_true
89
+ end
90
+
91
+ it "raises CookbookSyntaxError if the cookbook contains invalid ruby files" do
92
+ @cb = CachedCookbook.from_path(fixtures_path.join("cookbooks", "invalid_ruby_files-1.0.0"))
93
+
94
+ lambda {
95
+ @cb.validate!
96
+ }.should raise_error(CookbookSyntaxError)
97
+ end
98
+
99
+ it "raises CookbookSyntaxError if the cookbook contains invalid template files" do
100
+ @cb = CachedCookbook.from_path(fixtures_path.join("cookbooks", "invalid_template_files-1.0.0"))
101
+
102
+ lambda {
103
+ @cb.validate!
104
+ }.should raise_error(CookbookSyntaxError)
105
+ end
106
+ end
107
+
108
+ describe "#file_metadata" do
109
+ let(:file) { subject.path.join("files", "default", "mime.types") }
110
+
111
+ before(:each) { @metadata = subject.file_metadata(:file, file) }
112
+
113
+ it "has a 'path' key whose value is a relative path from the CachedCookbook's path" do
114
+ @metadata.should have_key(:path)
115
+ @metadata[:path].should be_relative_path
116
+ @metadata[:path].should eql("files/default/mime.types")
117
+ end
118
+
119
+ it "has a 'name' key whose value is the basename of the target file" do
120
+ @metadata.should have_key(:name)
121
+ @metadata[:name].should eql("mime.types")
122
+ end
123
+
124
+ it "has a 'checksum' key whose value is the checksum of the target file" do
125
+ @metadata.should have_key(:checksum)
126
+ @metadata[:checksum].should eql("06e7eca1d6cb608e2e74fd1f8e059f34")
127
+ end
128
+
129
+ it "has a 'specificity' key" do
130
+ @metadata.should have_key(:specificity)
131
+ end
132
+
133
+ context "given a 'template' or 'file' berksfile type" do
134
+ let(:file) { subject.path.join("files", "ubuntu", "mime.types") }
135
+ before(:each) { @metadata = subject.file_metadata(:files, file) }
136
+
137
+ it "has a 'specificity' key whose value represents the specificity found in filepath" do
138
+ @metadata[:specificity].should eql("ubuntu")
139
+ end
140
+ end
141
+
142
+ context "given any berksfile type that is not a 'template' or 'file'" do
143
+ let(:file) { subject.path.join("README.md") }
144
+ before(:each) { @metadata = subject.file_metadata(:root, file) }
145
+
146
+ it "has a 'specificity' key whose value is 'default'" do
147
+ @metadata[:specificity].should eql("default")
148
+ end
149
+ end
150
+ end
151
+
152
+ describe "#to_hash" do
153
+ before(:each) do
154
+ @hash = subject.to_hash
155
+ end
156
+
157
+ let(:cookbook_name) { subject.cookbook_name }
158
+ let(:cookbook_version) { subject.version }
159
+
160
+ it "has a 'recipes' key with a value of an Array Hashes" do
161
+ @hash.should have_key('recipes')
162
+ @hash['recipes'].should be_a(Array)
163
+ @hash['recipes'].each do |item|
164
+ item.should be_a(Hash)
165
+ end
166
+ end
167
+
168
+ it "has a 'name' key value pair in a Hash of the 'recipes' Array of Hashes" do
169
+ @hash['recipes'].first.should have_key('name')
170
+ end
171
+
172
+ it "has a 'path' key value pair in a Hash of the 'recipes' Array of Hashes" do
173
+ @hash['recipes'].first.should have_key('path')
174
+ end
175
+
176
+ it "has a 'checksum' key value pair in a Hash of the 'recipes' Array of Hashes" do
177
+ @hash['recipes'].first.should have_key('checksum')
178
+ end
179
+
180
+ it "has a 'specificity' key value pair in a Hash of the 'recipes' Array of Hashes" do
181
+ @hash['recipes'].first.should have_key('specificity')
182
+ end
183
+
184
+ it "has a 'definitions' key with a value of an Array Hashes" do
185
+ @hash.should have_key('definitions')
186
+ @hash['definitions'].should be_a(Array)
187
+ @hash['definitions'].each do |item|
188
+ item.should be_a(Hash)
189
+ end
190
+ end
191
+
192
+ it "has a 'name' key value pair in a Hash of the 'definitions' Array of Hashes" do
193
+ @hash['definitions'].first.should have_key('name')
194
+ end
195
+
196
+ it "has a 'path' key value pair in a Hash of the 'definitions' Array of Hashes" do
197
+ @hash['definitions'].first.should have_key('path')
198
+ end
199
+
200
+ it "has a 'checksum' key value pair in a Hash of the 'definitions' Array of Hashes" do
201
+ @hash['definitions'].first.should have_key('checksum')
202
+ end
203
+
204
+ it "has a 'specificity' key value pair in a Hash of the 'definitions' Array of Hashes" do
205
+ @hash['definitions'].first.should have_key('specificity')
206
+ end
207
+
208
+ it "has a 'libraries' key with a value of an Array Hashes" do
209
+ @hash.should have_key('libraries')
210
+ @hash['libraries'].should be_a(Array)
211
+ @hash['libraries'].each do |item|
212
+ item.should be_a(Hash)
213
+ end
214
+ end
215
+
216
+ it "has a 'name' key value pair in a Hash of the 'libraries' Array of Hashes" do
217
+ @hash['libraries'].first.should have_key('name')
218
+ end
219
+
220
+ it "has a 'path' key value pair in a Hash of the 'libraries' Array of Hashes" do
221
+ @hash['libraries'].first.should have_key('path')
222
+ end
223
+
224
+ it "has a 'checksum' key value pair in a Hash of the 'libraries' Array of Hashes" do
225
+ @hash['libraries'].first.should have_key('checksum')
226
+ end
227
+
228
+ it "has a 'specificity' key value pair in a Hash of the 'libraries' Array of Hashes" do
229
+ @hash['libraries'].first.should have_key('specificity')
230
+ end
231
+
232
+ it "has a 'attributes' key with a value of an Array Hashes" do
233
+ @hash.should have_key('attributes')
234
+ @hash['attributes'].should be_a(Array)
235
+ @hash['attributes'].each do |item|
236
+ item.should be_a(Hash)
237
+ end
238
+ end
239
+
240
+ it "has a 'name' key value pair in a Hash of the 'attributes' Array of Hashes" do
241
+ @hash['attributes'].first.should have_key('name')
242
+ end
243
+
244
+ it "has a 'path' key value pair in a Hash of the 'attributes' Array of Hashes" do
245
+ @hash['attributes'].first.should have_key('path')
246
+ end
247
+
248
+ it "has a 'checksum' key value pair in a Hash of the 'attributes' Array of Hashes" do
249
+ @hash['attributes'].first.should have_key('checksum')
250
+ end
251
+
252
+ it "has a 'specificity' key value pair in a Hash of the 'attributes' Array of Hashes" do
253
+ @hash['attributes'].first.should have_key('specificity')
254
+ end
255
+
256
+ it "has a 'files' key with a value of an Array Hashes" do
257
+ @hash.should have_key('files')
258
+ @hash['files'].should be_a(Array)
259
+ @hash['files'].each do |item|
260
+ item.should be_a(Hash)
261
+ end
262
+ end
263
+
264
+ it "has a 'name' key value pair in a Hash of the 'files' Array of Hashes" do
265
+ @hash['files'].first.should have_key('name')
266
+ end
267
+
268
+ it "has a 'path' key value pair in a Hash of the 'files' Array of Hashes" do
269
+ @hash['files'].first.should have_key('path')
270
+ end
271
+
272
+ it "has a 'checksum' key value pair in a Hash of the 'files' Array of Hashes" do
273
+ @hash['files'].first.should have_key('checksum')
274
+ end
275
+
276
+ it "has a 'specificity' key value pair in a Hash of the 'files' Array of Hashes" do
277
+ @hash['files'].first.should have_key('specificity')
278
+ end
279
+
280
+ it "has a 'templates' key with a value of an Array Hashes" do
281
+ @hash.should have_key('templates')
282
+ @hash['templates'].should be_a(Array)
283
+ @hash['templates'].each do |item|
284
+ item.should be_a(Hash)
285
+ end
286
+ end
287
+
288
+ it "has a 'name' key value pair in a Hash of the 'templates' Array of Hashes" do
289
+ @hash['templates'].first.should have_key('name')
290
+ end
291
+
292
+ it "has a 'path' key value pair in a Hash of the 'templates' Array of Hashes" do
293
+ @hash['templates'].first.should have_key('path')
294
+ end
295
+
296
+ it "has a 'checksum' key value pair in a Hash of the 'templates' Array of Hashes" do
297
+ @hash['templates'].first.should have_key('checksum')
298
+ end
299
+
300
+ it "has a 'specificity' key value pair in a Hash of the 'templates' Array of Hashes" do
301
+ @hash['templates'].first.should have_key('specificity')
302
+ end
303
+
304
+ it "has a 'resources' key with a value of an Array Hashes" do
305
+ @hash.should have_key('resources')
306
+ @hash['resources'].should be_a(Array)
307
+ @hash['resources'].each do |item|
308
+ item.should be_a(Hash)
309
+ end
310
+ end
311
+
312
+ it "has a 'name' key value pair in a Hash of the 'resources' Array of Hashes" do
313
+ @hash['resources'].first.should have_key('name')
314
+ end
315
+
316
+ it "has a 'path' key value pair in a Hash of the 'resources' Array of Hashes" do
317
+ @hash['resources'].first.should have_key('path')
318
+ end
319
+
320
+ it "has a 'checksum' key value pair in a Hash of the 'resources' Array of Hashes" do
321
+ @hash['resources'].first.should have_key('checksum')
322
+ end
323
+
324
+ it "has a 'specificity' key value pair in a Hash of the 'resources' Array of Hashes" do
325
+ @hash['resources'].first.should have_key('specificity')
326
+ end
327
+
328
+ it "has a 'providers' key with a value of an Array Hashes" do
329
+ @hash.should have_key('providers')
330
+ @hash['providers'].should be_a(Array)
331
+ @hash['providers'].each do |item|
332
+ item.should be_a(Hash)
333
+ end
334
+ end
335
+
336
+ it "has a 'name' key value pair in a Hash of the 'providers' Array of Hashes" do
337
+ @hash['providers'].first.should have_key('name')
338
+ end
339
+
340
+ it "has a 'path' key value pair in a Hash of the 'providers' Array of Hashes" do
341
+ @hash['providers'].first.should have_key('path')
342
+ end
343
+
344
+ it "has a 'checksum' key value pair in a Hash of the 'providers' Array of Hashes" do
345
+ @hash['providers'].first.should have_key('checksum')
346
+ end
347
+
348
+ it "has a 'specificity' key value pair in a Hash of the 'providers' Array of Hashes" do
349
+ @hash['providers'].first.should have_key('specificity')
350
+ end
351
+
352
+ it "has a 'root_files' key with a value of an Array Hashes" do
353
+ @hash.should have_key('root_files')
354
+ @hash['root_files'].should be_a(Array)
355
+ @hash['root_files'].each do |item|
356
+ item.should be_a(Hash)
357
+ end
358
+ end
359
+
360
+ it "has a 'name' key value pair in a Hash of the 'root_files' Array of Hashes" do
361
+ @hash['root_files'].first.should have_key('name')
362
+ end
363
+
364
+ it "has a 'path' key value pair in a Hash of the 'root_files' Array of Hashes" do
365
+ @hash['root_files'].first.should have_key('path')
366
+ end
367
+
368
+ it "has a 'checksum' key value pair in a Hash of the 'root_files' Array of Hashes" do
369
+ @hash['root_files'].first.should have_key('checksum')
370
+ end
371
+
372
+ it "has a 'specificity' key value pair in a Hash of the 'root_files' Array of Hashes" do
373
+ @hash['root_files'].first.should have_key('specificity')
374
+ end
375
+
376
+ it "has a 'cookbook_name' key with a String value" do
377
+ @hash.should have_key('cookbook_name')
378
+ @hash['cookbook_name'].should be_a(String)
379
+ end
380
+
381
+ it "has a 'metadata' key with a Cookbook::Metadata value" do
382
+ @hash.should have_key('metadata')
383
+ @hash['metadata'].should be_a(Chef::Cookbook::Metadata)
384
+ end
385
+
386
+ it "has a 'version' key with a String value" do
387
+ @hash.should have_key('version')
388
+ @hash['version'].should be_a(String)
389
+ end
390
+
391
+ it "has a 'name' key with a String value" do
392
+ @hash.should have_key('name')
393
+ @hash['name'].should be_a(String)
394
+ end
395
+
396
+ it "has a value containing the cookbook name and version separated by a dash for 'name'" do
397
+ name, version = @hash['name'].split('-')
398
+
399
+ name.should eql(cookbook_name)
400
+ version.should eql(cookbook_version)
401
+ end
402
+
403
+ it "has a 'chef_type' key with 'cookbook_version' as the value" do
404
+ @hash.should have_key('chef_type')
405
+ @hash['chef_type'].should eql("cookbook_version")
406
+ end
407
+ end
408
+
409
+ describe "#to_json" do
410
+ before(:each) do
411
+ @json = subject.to_json
412
+ end
413
+
414
+ it "has a 'json_class' key with 'Chef::CookbookVersion' as the value" do
415
+ @json.should have_json_path('json_class')
416
+ parse_json(@json)['json_class'].should eql("Chef::CookbookVersion")
417
+ end
418
+ end
419
+ end
420
+ end