berkshelf 0.1.1

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