diff options
author | Ho-Sheng Hsiao <hosh@opscode.com> | 2013-02-12 17:18:09 -0800 |
---|---|---|
committer | John Keiser <jkeiser@opscode.com> | 2013-06-07 13:12:26 -0700 |
commit | c9d895a63226044729e801b097548c3ae1d3da65 (patch) | |
tree | 016cf4cde19213722490c74882d2dd28868c6bff /spec/unit | |
parent | 2f137309be467c3e0a676144ba14caee8eb8c50c (diff) | |
download | chef-c9d895a63226044729e801b097548c3ae1d3da65.tar.gz |
[SPEC] Separated cookbooks_dir and cookbook_dir spec. Added versioned_cookbooks test
Diffstat (limited to 'spec/unit')
-rw-r--r-- | spec/unit/chef_fs/file_system/cookbook_dir_spec.rb | 547 | ||||
-rw-r--r-- | spec/unit/chef_fs/file_system/cookbooks_dir_spec.rb | 523 |
2 files changed, 591 insertions, 479 deletions
diff --git a/spec/unit/chef_fs/file_system/cookbook_dir_spec.rb b/spec/unit/chef_fs/file_system/cookbook_dir_spec.rb new file mode 100644 index 0000000000..a23b60b610 --- /dev/null +++ b/spec/unit/chef_fs/file_system/cookbook_dir_spec.rb @@ -0,0 +1,547 @@ +# +# Author:: John Keiser (<jkeiser@opscode.com>) +# Copyright:: Copyright (c) 2012 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'spec_helper' +require 'chef/chef_fs/file_system/chef_server_root_dir' +require 'chef/chef_fs/file_system' + +describe Chef::ChefFS::FileSystem::CookbookDir do + let(:root_dir) { + Chef::ChefFS::FileSystem::ChefServerRootDir.new('remote', + { + :chef_server_url => 'url', + :node_name => 'username', + :client_key => 'key' + }, + 'everything') + } + + let(:cookbook_response) do + { + "achild" => { + "url" => "http://example.com/cookbooks/achild", + 'versions' => [ + { "version" => '2.0.0', 'url' => 'http://example.com/cookbooks/achild/2.0.0' }, + { "version" => '1.0.0', 'url' => 'http://example.com/cookbooks/achild/2.0.0' }, ] }, + "bchild" => { + "url" => "http://example.com/cookbokks/bchild", + 'versions' => [ { "version" => '1.0.0', 'url' => 'http://example.com/cookbooks/achild/2.0.0' }, ] }, + + } + end + + let(:cookbooks_dir) { root_dir.child('cookbooks') } + let(:should_list_cookbooks) { rest.should_receive(:get_rest).with('cookbooks').once.and_return(cookbook_response) } + + let(:rest) { double 'rest' } + before(:each) { Chef::REST.stub(:new).with('url','username','key') { rest } } + + # Cookbook dir (/cookbooks/<blah>) + shared_examples_for 'a segment directory' do + it 'has cookbook as parent' do + segment_dir.parent.should == cookbook_dir + end + it 'exists' do + segment_dir.exists?.should be_true + end + it 'is a directory' do + segment_dir.dir?.should be_true + end + it 'name is correct' do + segment_dir.name.should == segment_dir_name + end + it 'path is correct' do + segment_dir.path.should == "/cookbooks/#{cookbook_dir_name}/#{segment_dir_name}" + end + it 'path_for_printing is correct' do + segment_dir.path_for_printing.should == "remote/cookbooks/#{cookbook_dir_name}/#{segment_dir_name}" + end + it 'has the right children' do + segment_dir.children =~ %w(a.rb b.txt subdir) + end + it 'children are identical to child()' do + segment_dir.child('a.rb').should == segment_dir.children.select { |child| child.name == 'a.rb' }.first + segment_dir.child('b.txt').should == segment_dir.children.select { |child| child.name == 'b.txt' }.first + segment_dir.child('subdir').should == segment_dir.children.select { |child| child.name == 'subdir' }.first + end + context 'subdirectory' do + it 'has segment as a parent' do + segment_dir.child('subdir').parent.should == segment_dir + end + it 'exists' do + segment_dir.child('subdir').exists?.should be_true + end + it 'is a directory' do + segment_dir.child('subdir').dir?.should be_true + end + it 'name is subdir' do + segment_dir.child('subdir').name.should == 'subdir' + end + it 'path is correct' do + segment_dir.child('subdir').path.should == "/cookbooks/#{cookbook_dir_name}/#{segment_dir_name}/subdir" + end + it 'path_for_printing is correct' do + segment_dir.child('subdir').path_for_printing.should == "remote/cookbooks/#{cookbook_dir_name}/#{segment_dir_name}/subdir" + end + it 'has the right children' do + segment_dir.child('subdir').children =~ %w(a.rb b.txt) + end + it 'children are identical to child()' do + segment_dir.child('subdir').child('a.rb').should == segment_dir.child('subdir').children.select { |child| child.name == 'a.rb' }.first + segment_dir.child('subdir').child('b.txt').should == segment_dir.child('subdir').children.select { |child| child.name == 'b.txt' }.first + end + end + end + + shared_examples_for 'a cookbook' do + it 'has cookbooks as parent' do + cookbook_dir.parent == cookbooks_dir + end + it 'is a directory' do + should_list_cookbooks + cookbook_dir.dir?.should be_true + end + it 'exists' do + should_list_cookbooks + cookbook_dir.exists?.should be_true + end + it 'has name <cookbook name>' do + cookbook_dir.name.should == cookbook_dir_name + end + it 'has path /cookbooks/<cookbook name>' do + cookbook_dir.path.should == "/cookbooks/#{cookbook_dir_name}" + end + it 'has path_for_printing remote/cookbooks/<cookbook name>' do + cookbook_dir.path_for_printing.should == "remote/cookbooks/#{cookbook_dir_name}" + end + it 'can have segment directories as children' do + cookbook_dir.can_have_child?('attributes', true).should be_true + cookbook_dir.can_have_child?('definitions', true).should be_true + cookbook_dir.can_have_child?('recipes', true).should be_true + cookbook_dir.can_have_child?('libraries', true).should be_true + cookbook_dir.can_have_child?('templates', true).should be_true + cookbook_dir.can_have_child?('files', true).should be_true + cookbook_dir.can_have_child?('resources', true).should be_true + cookbook_dir.can_have_child?('providers', true).should be_true + end + it 'cannot have arbitrary directories as children' do + cookbook_dir.can_have_child?('blah', true).should be_false + cookbook_dir.can_have_child?('root_files', true).should be_false + end + it 'can have files as children' do + cookbook_dir.can_have_child?('blah', false).should be_true + cookbook_dir.can_have_child?('root_files', false).should be_true + cookbook_dir.can_have_child?('attributes', false).should be_true + cookbook_dir.can_have_child?('definitions', false).should be_true + cookbook_dir.can_have_child?('recipes', false).should be_true + cookbook_dir.can_have_child?('libraries', false).should be_true + cookbook_dir.can_have_child?('templates', false).should be_true + cookbook_dir.can_have_child?('files', false).should be_true + cookbook_dir.can_have_child?('resources', false).should be_true + cookbook_dir.can_have_child?('providers', false).should be_true + end + # TODO test empty parts, cross-contamination (root_files named templates/x.txt, libraries named recipes/blah.txt) + context 'with a full directory structure' do + + let(:manifest) do + { + :attributes => json_files('attributes'), + :definitions => json_files('definitions'), + :files => json_files('files'), + :libraries => json_files('libraries'), + :providers => json_files('providers'), + :recipes => json_files('recipes'), + :resources => json_files('resources'), + :templates => json_files('templates'), + :root_files => root_files.map { |f| json_file(f, file_checksums[f]) } + } + end + + def json_file(path, checksum) + { + :name => basename(path), + :url => "cookbook_file:#{path}", + :checksum => checksum, + :path => path, + :specificity => "default" + } + end + + def json_files(segment) + files. + select { |f| /^#{segment}\//.match(f) }. + map { |f| json_file(f, file_checksums[f]) } + end + + def basename(path) + Chef::ChefFS::PathUtils.split(path)[-1] + end + + let(:segments) { %w(attributes definitions files libraries providers recipes resources templates) } + let(:some_filenames) { %w(a.rb b.txt subdir/a.rb subdir/b.txt) } + let(:root_files) { ['root_files'] + some_filenames } + + # Generate a sample cookbook + let(:files) { [root_files, segment_files].flatten } + let(:segment_files) { segments.map { |s| some_filenames.map { |f| "#{s}/#{f}" } } } + + # Make a hash where { filename => checksum } + let(:file_checksums) { Hash[*(files.each_with_index.map(&filename_with_checksum).flatten)] } + let(:filename_with_checksum) { lambda { |f, i| [f, i.to_s(16)] } } + + let(:cookbook) { double('cookbook').tap { |c| c.should_receive(:manifest).and_return(manifest) } } + let(:api_url) do + if Chef::Config[:versioned_cookbooks] + "cookbooks/?num_versions=all" + else + "cookbooks/#{cookbook_dir_name}/_latest" + end + end + + let(:should_get_cookbook) do + rest.should_receive(:get_rest).with(api_url).once.and_return(cookbook) + end + + it 'has correct children' do + should_get_cookbook + cookbook_dir.children.map { |child| child.name }.should =~ %w(attributes definitions files libraries providers recipes resources templates a.rb b.txt subdir root_files) + end + it 'children and child() yield the exact same objects' do + should_get_cookbook + cookbook_dir.children.each { |child| child.should == cookbook_dir.child(child.name) } + end + it 'all files exist (recursive) and have correct parent, path, path_for_printing, checksum and type' do + should_get_cookbook + file_checksums.each do |path, checksum| + file = Chef::ChefFS::FileSystem.resolve_path(cookbook_dir, path) + file_parts = path.split('/') + if file_parts.length == 3 + file.parent.parent.parent.should == cookbook_dir + elsif file_parts.length == 2 + file.parent.parent.should == cookbook_dir + else + file.parent.should == cookbook_dir + end + file.exists?.should be_true + file.dir?.should be_false + file.name.should == file_parts[-1] + file.path.should == "/cookbooks/#{cookbook_dir_name}/#{path}" + file.path_for_printing.should == "remote/cookbooks/#{cookbook_dir_name}/#{path}" + file.checksum.should == checksum + end + end + it 'all files can be read' do + should_get_cookbook + files.each do |path| + cookbook_file = double(path) + cookbook_file.should_receive(:open).with(no_args()).once + cookbook_file.should_receive(:read).with(no_args()).once.and_return("This is #{path}'s content") + cookbook_file.should_receive(:close!).with(no_args()).once + rest.should_receive(:get_rest).with("cookbook_file:#{path}", true).once.and_return(cookbook_file) + rest.should_receive(:sign_on_redirect).with(no_args()).once.and_return(true) + rest.should_receive(:sign_on_redirect=).with(false).once + rest.should_receive(:sign_on_redirect=).with(true).once + file = Chef::ChefFS::FileSystem.resolve_path(cookbook_dir, path) + file.read.should == "This is #{path}'s content" + end + end + + context 'the attributes segment' do + let(:segment_dir) { cookbook_dir.child('attributes') } + let(:segment_dir_name) { 'attributes' } + it_behaves_like 'a segment directory' + + before(:each) do + should_get_cookbook + end + + it 'can have ruby files' do + should_get_cookbook + segment_dir.can_have_child?('blah.rb', false).should be_true + segment_dir.can_have_child?('.blah.rb', false).should be_true + end + it 'cannot have non-ruby files' do + should_get_cookbook + segment_dir.can_have_child?('blah.txt', false).should be_false + segment_dir.can_have_child?('.blah.txt', false).should be_false + end + it 'cannot have subdirectories' do + should_get_cookbook + segment_dir.can_have_child?('blah', true).should be_false + end + end + + context 'the definitions segment' do + let(:segment_dir) { cookbook_dir.child('definitions') } + let(:segment_dir_name) { 'definitions' } + it_behaves_like 'a segment directory' + + before(:each) do + should_get_cookbook + end + + it 'can have ruby files' do + segment_dir.can_have_child?('blah.rb', false).should be_true + segment_dir.can_have_child?('.blah.rb', false).should be_true + end + it 'cannot have non-ruby files' do + segment_dir.can_have_child?('blah.txt', false).should be_false + segment_dir.can_have_child?('.blah.txt', false).should be_false + end + it 'cannot have subdirectories' do + segment_dir.can_have_child?('blah', true).should be_false + end + end + + context 'the files segment' do + let(:segment_dir) { cookbook_dir.child('files') } + let(:segment_dir_name) { 'files' } + it_behaves_like 'a segment directory' + + before(:each) do + should_get_cookbook + end + + it 'can have ruby files' do + segment_dir.can_have_child?('blah.rb', false).should be_true + segment_dir.can_have_child?('.blah.rb', false).should be_true + end + it 'can have non-ruby files' do + segment_dir.can_have_child?('blah.txt', false).should be_true + segment_dir.can_have_child?('.blah.txt', false).should be_true + end + it 'can have subdirectories' do + segment_dir.can_have_child?('blah', true).should be_true + end + it 'subdirectories can have ruby files' do + segment_dir.child('subdir').can_have_child?('blah.rb', false).should be_true + segment_dir.child('subdir').can_have_child?('.blah.rb', false).should be_true + end + it 'subdirectories can have non-ruby files' do + segment_dir.child('subdir').can_have_child?('blah.txt', false).should be_true + segment_dir.child('subdir').can_have_child?('.blah.txt', false).should be_true + end + it 'subdirectories can have subdirectories' do + segment_dir.child('subdir').can_have_child?('blah', true).should be_true + end + end + + context 'the libraries segment' do + let(:segment_dir) { cookbook_dir.child('libraries') } + let(:segment_dir_name) { 'libraries' } + it_behaves_like 'a segment directory' + + before(:each) do + should_get_cookbook + end + + it 'can have ruby files' do + segment_dir.can_have_child?('blah.rb', false).should be_true + segment_dir.can_have_child?('.blah.rb', false).should be_true + end + it 'cannot have non-ruby files' do + segment_dir.can_have_child?('blah.txt', false).should be_false + segment_dir.can_have_child?('.blah.txt', false).should be_false + end + it 'cannot have subdirectories' do + segment_dir.can_have_child?('blah', true).should be_false + end + end + + context 'the providers segment' do + let(:segment_dir) { cookbook_dir.child('providers') } + let(:segment_dir_name) { 'providers' } + it_behaves_like 'a segment directory' + + before(:each) do + should_get_cookbook + end + + it 'can have ruby files' do + segment_dir.can_have_child?('blah.rb', false).should be_true + segment_dir.can_have_child?('.blah.rb', false).should be_true + end + it 'cannot have non-ruby files' do + segment_dir.can_have_child?('blah.txt', false).should be_false + segment_dir.can_have_child?('.blah.txt', false).should be_false + end + it 'can have subdirectories' do + segment_dir.can_have_child?('blah', true).should be_true + end + it 'subdirectories can have ruby files' do + segment_dir.child('subdir').can_have_child?('blah.rb', false).should be_true + segment_dir.child('subdir').can_have_child?('.blah.rb', false).should be_true + end + it 'subdirectories cannot have non-ruby files' do + segment_dir.child('subdir').can_have_child?('blah.txt', false).should be_false + segment_dir.child('subdir').can_have_child?('.blah.txt', false).should be_false + end + it 'subdirectories can have subdirectories' do + segment_dir.child('subdir').can_have_child?('blah', true).should be_true + end + end + + context 'the recipes segment' do + let(:segment_dir) { cookbook_dir.child('recipes') } + let(:segment_dir_name) { 'recipes' } + it_behaves_like 'a segment directory' + + before(:each) do + should_get_cookbook + end + + it 'can have ruby files' do + segment_dir.can_have_child?('blah.rb', false).should be_true + segment_dir.can_have_child?('.blah.rb', false).should be_true + end + it 'cannot have non-ruby files' do + segment_dir.can_have_child?('blah.txt', false).should be_false + segment_dir.can_have_child?('.blah.txt', false).should be_false + end + it 'cannot have subdirectories' do + segment_dir.can_have_child?('blah', true).should be_false + end + end + + context 'the resources segment' do + let(:segment_dir) { cookbook_dir.child('resources') } + let(:segment_dir_name) { 'resources' } + it_behaves_like 'a segment directory' + + before(:each) do + should_get_cookbook + end + + it 'can have ruby files' do + segment_dir.can_have_child?('blah.rb', false).should be_true + segment_dir.can_have_child?('.blah.rb', false).should be_true + end + it 'cannot have non-ruby files' do + segment_dir.can_have_child?('blah.txt', false).should be_false + segment_dir.can_have_child?('.blah.txt', false).should be_false + end + it 'can have subdirectories' do + segment_dir.can_have_child?('blah', true).should be_true + end + it 'subdirectories can have ruby files' do + segment_dir.child('subdir').can_have_child?('blah.rb', false).should be_true + segment_dir.child('subdir').can_have_child?('.blah.rb', false).should be_true + end + it 'subdirectories cannot have non-ruby files' do + segment_dir.child('subdir').can_have_child?('blah.txt', false).should be_false + segment_dir.child('subdir').can_have_child?('.blah.txt', false).should be_false + end + it 'subdirectories can have subdirectories' do + segment_dir.child('subdir').can_have_child?('blah', true).should be_true + end + end + + context 'the templates segment' do + let(:segment_dir) { cookbook_dir.child('templates') } + let(:segment_dir_name) { 'templates' } + it_behaves_like 'a segment directory' + + before(:each) do + should_get_cookbook + end + + it 'can have ruby files' do + segment_dir.can_have_child?('blah.rb', false).should be_true + segment_dir.can_have_child?('.blah.rb', false).should be_true + end + it 'can have non-ruby files' do + segment_dir.can_have_child?('blah.txt', false).should be_true + segment_dir.can_have_child?('.blah.txt', false).should be_true + end + it 'can have subdirectories' do + segment_dir.can_have_child?('blah', true).should be_true + end + it 'subdirectories can have ruby files' do + segment_dir.child('subdir').can_have_child?('blah.rb', false).should be_true + segment_dir.child('subdir').can_have_child?('.blah.rb', false).should be_true + end + it 'subdirectories can have non-ruby files' do + segment_dir.child('subdir').can_have_child?('blah.txt', false).should be_true + segment_dir.child('subdir').can_have_child?('.blah.txt', false).should be_true + end + it 'subdirectories can have subdirectories' do + segment_dir.child('subdir').can_have_child?('blah', true).should be_true + end + end + + context 'root subdirectories' do + let(:root_subdir) { cookbook_dir.child('subdir') } + + before(:each) do + should_get_cookbook + end + + # Really, since these shouldn't exist in the first place, + # it doesn't matter; but these REALLY shouldn't be able to + # have any files in them at all. + it 'can have ruby files' do + root_subdir.can_have_child?('blah.rb', false).should be_true + root_subdir.can_have_child?('.blah.rb', false).should be_true + end + it 'can have non-ruby files' do + root_subdir.can_have_child?('blah.txt', false).should be_true + root_subdir.can_have_child?('.blah.txt', false).should be_true + end + it 'cannot have subdirectories' do + root_subdir.can_have_child?('blah', true).should be_false + end + end + end + end + + context 'achild from cookbooks_dir.children' do + let(:cookbook_dir_name) { 'achild' } + let(:cookbook_dir) do + should_list_cookbooks + cookbooks_dir.children.select { |child| child.name == 'achild' }.first + end + it_behaves_like 'a cookbook' + end + + context 'cookbooks_dir.child(achild)' do + let(:cookbook_dir_name) { 'achild' } + let(:cookbook_dir) { cookbooks_dir.child('achild') } + it_behaves_like 'a cookbook' + end + context 'nonexistent cookbooks_dir.child()' do + let(:nonexistent_child) { cookbooks_dir.child('blah') } + it 'has correct parent, name, path and path_for_printing' do + nonexistent_child.parent.should == cookbooks_dir + nonexistent_child.name.should == "blah" + nonexistent_child.path.should == "/cookbooks/blah" + nonexistent_child.path_for_printing.should == "remote/cookbooks/blah" + end + it 'does not exist' do + should_list_cookbooks + nonexistent_child.exists?.should be_false + end + it 'is a directory' do + should_list_cookbooks + nonexistent_child.dir?.should be_false + end + it 'read returns NotFoundError' do + should_list_cookbooks + expect { nonexistent_child.read }.to raise_error(Chef::ChefFS::FileSystem::NotFoundError) + end + end +end diff --git a/spec/unit/chef_fs/file_system/cookbooks_dir_spec.rb b/spec/unit/chef_fs/file_system/cookbooks_dir_spec.rb index 7779b177c8..c689cd6983 100644 --- a/spec/unit/chef_fs/file_system/cookbooks_dir_spec.rb +++ b/spec/unit/chef_fs/file_system/cookbooks_dir_spec.rb @@ -46,528 +46,93 @@ describe Chef::ChefFS::FileSystem::CookbooksDir do end let(:cookbooks_dir) { root_dir.child('cookbooks') } - let(:should_list_cookbooks) { @rest.should_receive(:get_rest).with('cookbooks').once.and_return(cookbook_response) } + let(:api_url) { 'cookbooks' } + let(:should_list_cookbooks) { rest.should_receive(:get_rest).with(api_url).once.and_return(cookbook_response) } - before(:each) do - @rest = double("rest") - Chef::REST.stub(:new).with('url','username','key') { @rest } - end + let(:rest) { double 'rest' } + before(:each) { Chef::REST.stub(:new).with('url','username','key') { rest } } it 'has / as parent' do cookbooks_dir.parent.should == root_dir end + it 'is a directory' do cookbooks_dir.dir?.should be_true end + it 'exists' do cookbooks_dir.exists?.should be_true end + it 'has name cookbooks' do cookbooks_dir.name.should == 'cookbooks' end + it 'has path /cookbooks' do cookbooks_dir.path.should == '/cookbooks' end + it 'has path_for_printing remote/cookbooks' do cookbooks_dir.path_for_printing.should == 'remote/cookbooks' end + it 'has correct children' do should_list_cookbooks cookbooks_dir.children.map { |child| child.name }.should =~ %w(achild bchild) end - it 'can have directories as children' do - cookbooks_dir.can_have_child?('blah', true).should be_true - end - it 'cannot have files as children' do - cookbooks_dir.can_have_child?('blah', false).should be_false - end - # - # Cookbook dir (/cookbooks/<blah>) - # - shared_examples_for 'a segment directory' do - it 'has cookbook as parent' do - segment_dir.parent.should == cookbook_dir - end - it 'exists' do - segment_dir.exists?.should be_true - end - it 'is a directory' do - segment_dir.dir?.should be_true + describe '#can_have_child?' do + it 'can have directories as children' do + cookbooks_dir.can_have_child?('blah', true).should be_true end - it 'name is correct' do - segment_dir.name.should == segment_dir_name - end - it 'path is correct' do - segment_dir.path.should == "/cookbooks/#{cookbook_dir_name}/#{segment_dir_name}" - end - it 'path_for_printing is correct' do - segment_dir.path_for_printing.should == "remote/cookbooks/#{cookbook_dir_name}/#{segment_dir_name}" - end - it 'has the right children' do - segment_dir.children =~ %w(a.rb b.txt subdir) - end - it 'children are identical to child()' do - segment_dir.child('a.rb').should == segment_dir.children.select { |child| child.name == 'a.rb' }.first - segment_dir.child('b.txt').should == segment_dir.children.select { |child| child.name == 'b.txt' }.first - segment_dir.child('subdir').should == segment_dir.children.select { |child| child.name == 'subdir' }.first - end - context 'subdirectory' do - it 'has segment as a parent' do - segment_dir.child('subdir').parent.should == segment_dir - end - it 'exists' do - segment_dir.child('subdir').exists?.should be_true - end - it 'is a directory' do - segment_dir.child('subdir').dir?.should be_true - end - it 'name is subdir' do - segment_dir.child('subdir').name.should == 'subdir' - end - it 'path is correct' do - segment_dir.child('subdir').path.should == "/cookbooks/#{cookbook_dir_name}/#{segment_dir_name}/subdir" - end - it 'path_for_printing is correct' do - segment_dir.child('subdir').path_for_printing.should == "remote/cookbooks/#{cookbook_dir_name}/#{segment_dir_name}/subdir" - end - it 'has the right children' do - segment_dir.child('subdir').children =~ %w(a.rb b.txt) - end - it 'children are identical to child()' do - segment_dir.child('subdir').child('a.rb').should == segment_dir.child('subdir').children.select { |child| child.name == 'a.rb' }.first - segment_dir.child('subdir').child('b.txt').should == segment_dir.child('subdir').children.select { |child| child.name == 'b.txt' }.first - end + it 'cannot have files as children' do + cookbooks_dir.can_have_child?('blah', false).should be_false end end - shared_examples_for 'a cookbook' do - it 'has cookbooks as parent' do - cookbook_dir.parent == cookbooks_dir - end - it 'is a directory' do - should_list_cookbooks - cookbook_dir.dir?.should be_true - end - it 'exists' do - should_list_cookbooks - cookbook_dir.exists?.should be_true - end - it 'has name <cookbook name>' do - cookbook_dir.name.should == cookbook_dir_name - end - it 'has path /cookbooks/<cookbook name>' do - cookbook_dir.path.should == "/cookbooks/#{cookbook_dir_name}" - end - it 'has path_for_printing remote/cookbooks/<cookbook name>' do - cookbook_dir.path_for_printing.should == "remote/cookbooks/#{cookbook_dir_name}" - end - it 'can have segment directories as children' do - cookbook_dir.can_have_child?('attributes', true).should be_true - cookbook_dir.can_have_child?('definitions', true).should be_true - cookbook_dir.can_have_child?('recipes', true).should be_true - cookbook_dir.can_have_child?('libraries', true).should be_true - cookbook_dir.can_have_child?('templates', true).should be_true - cookbook_dir.can_have_child?('files', true).should be_true - cookbook_dir.can_have_child?('resources', true).should be_true - cookbook_dir.can_have_child?('providers', true).should be_true - end - it 'cannot have arbitrary directories as children' do - cookbook_dir.can_have_child?('blah', true).should be_false - cookbook_dir.can_have_child?('root_files', true).should be_false - end - it 'can have files as children' do - cookbook_dir.can_have_child?('blah', false).should be_true - cookbook_dir.can_have_child?('root_files', false).should be_true - cookbook_dir.can_have_child?('attributes', false).should be_true - cookbook_dir.can_have_child?('definitions', false).should be_true - cookbook_dir.can_have_child?('recipes', false).should be_true - cookbook_dir.can_have_child?('libraries', false).should be_true - cookbook_dir.can_have_child?('templates', false).should be_true - cookbook_dir.can_have_child?('files', false).should be_true - cookbook_dir.can_have_child?('resources', false).should be_true - cookbook_dir.can_have_child?('providers', false).should be_true - end - # TODO test empty parts, cross-contamination (root_files named templates/x.txt, libraries named recipes/blah.txt) - context 'with a full directory structure' do - - let(:manifest) do - { - :attributes => json_files('attributes'), - :definitions => json_files('definitions'), - :files => json_files('files'), - :libraries => json_files('libraries'), - :providers => json_files('providers'), - :recipes => json_files('recipes'), - :resources => json_files('resources'), - :templates => json_files('templates'), - :root_files => root_files.map { |f| json_file(f, file_checksums[f]) } - } - end - - def json_file(path, checksum) - { - :name => basename(path), - :url => "cookbook_file:#{path}", - :checksum => checksum, - :path => path, - :specificity => "default" - } - end - - def json_files(segment) - files. - select { |f| /^#{segment}\//.match(f) }. - map { |f| json_file(f, file_checksums[f]) } - end - - def basename(path) - Chef::ChefFS::PathUtils.split(path)[-1] - end - - let(:segments) { %w(attributes definitions files libraries providers recipes resources templates) } - let(:some_filenames) { %w(a.rb b.txt subdir/a.rb subdir/b.txt) } - let(:root_files) { ['root_files'] + some_filenames } + describe '#children' do + subject { cookbooks_dir.children } + before(:each) { should_list_cookbooks } - # Generate a sample cookbook - let(:files) { [root_files, segment_files].flatten } - let(:segment_files) { segments.map { |s| some_filenames.map { |f| "#{s}/#{f}" } } } + let(:entity_names) { subject.map(&:name) } + let(:cookbook_names) { subject.map(&:cookbook_name) } + let(:versions) { subject.map(&:version) } - # Make a hash where { filename => checksum } - let(:file_checksums) { Hash[*(files.each_with_index.map(&filename_with_checksum).flatten)] } - let(:filename_with_checksum) { lambda { |f, i| [f, i.to_s(16)] } } + context 'with versioned cookbooks' do + before(:each) { Chef::Config[:versioned_cookbooks] = true } + after(:each) { Chef::Config[:versioned_cookbooks] = false } - let(:should_get_cookbook) do - cookbook = double('cookbook') - cookbook.should_receive(:manifest).and_return(manifest) - @rest.should_receive(:get_rest).with("cookbooks/#{cookbook_dir_name}/_latest").once.and_return(cookbook) - end - - it 'has correct children' do - should_get_cookbook - cookbook_dir.children.map { |child| child.name }.should =~ %w(attributes definitions files libraries providers recipes resources templates a.rb b.txt subdir root_files) - end - it 'children and child() yield the exact same objects' do - should_get_cookbook - cookbook_dir.children.each { |child| child.should == cookbook_dir.child(child.name) } - end - it 'all files exist (recursive) and have correct parent, path, path_for_printing, checksum and type' do - should_get_cookbook - file_checksums.each do |path, checksum| - file = Chef::ChefFS::FileSystem.resolve_path(cookbook_dir, path) - file_parts = path.split('/') - if file_parts.length == 3 - file.parent.parent.parent.should == cookbook_dir - elsif file_parts.length == 2 - file.parent.parent.should == cookbook_dir - else - file.parent.should == cookbook_dir - end - file.exists?.should be_true - file.dir?.should be_false - file.name.should == file_parts[-1] - file.path.should == "/cookbooks/#{cookbook_dir_name}/#{path}" - file.path_for_printing.should == "remote/cookbooks/#{cookbook_dir_name}/#{path}" - file.checksum.should == checksum - end - end - it 'all files can be read' do - should_get_cookbook - files.each do |path| - cookbook_file = double(path) - cookbook_file.should_receive(:open).with(no_args()).once - cookbook_file.should_receive(:read).with(no_args()).once.and_return("This is #{path}'s content") - cookbook_file.should_receive(:close!).with(no_args()).once - @rest.should_receive(:get_rest).with("cookbook_file:#{path}", true).once.and_return(cookbook_file) - @rest.should_receive(:sign_on_redirect).with(no_args()).once.and_return(true) - @rest.should_receive(:sign_on_redirect=).with(false).once - @rest.should_receive(:sign_on_redirect=).with(true).once - file = Chef::ChefFS::FileSystem.resolve_path(cookbook_dir, path) - file.read.should == "This is #{path}'s content" - end - end - - context 'the attributes segment' do - let(:segment_dir) { cookbook_dir.child('attributes') } - let(:segment_dir_name) { 'attributes' } - it_behaves_like 'a segment directory' - - before(:each) do - should_get_cookbook - end - - it 'can have ruby files' do - should_get_cookbook - segment_dir.can_have_child?('blah.rb', false).should be_true - segment_dir.can_have_child?('.blah.rb', false).should be_true - end - it 'cannot have non-ruby files' do - should_get_cookbook - segment_dir.can_have_child?('blah.txt', false).should be_false - segment_dir.can_have_child?('.blah.txt', false).should be_false - end - it 'cannot have subdirectories' do - should_get_cookbook - segment_dir.can_have_child?('blah', true).should be_false - end - end - - context 'the definitions segment' do - let(:segment_dir) { cookbook_dir.child('definitions') } - let(:segment_dir_name) { 'definitions' } - it_behaves_like 'a segment directory' - - before(:each) do - should_get_cookbook - end - - it 'can have ruby files' do - segment_dir.can_have_child?('blah.rb', false).should be_true - segment_dir.can_have_child?('.blah.rb', false).should be_true - end - it 'cannot have non-ruby files' do - segment_dir.can_have_child?('blah.txt', false).should be_false - segment_dir.can_have_child?('.blah.txt', false).should be_false - end - it 'cannot have subdirectories' do - segment_dir.can_have_child?('blah', true).should be_false - end - end - - context 'the files segment' do - let(:segment_dir) { cookbook_dir.child('files') } - let(:segment_dir_name) { 'files' } - it_behaves_like 'a segment directory' - - before(:each) do - should_get_cookbook - end - - it 'can have ruby files' do - segment_dir.can_have_child?('blah.rb', false).should be_true - segment_dir.can_have_child?('.blah.rb', false).should be_true - end - it 'can have non-ruby files' do - segment_dir.can_have_child?('blah.txt', false).should be_true - segment_dir.can_have_child?('.blah.txt', false).should be_true - end - it 'can have subdirectories' do - segment_dir.can_have_child?('blah', true).should be_true - end - it 'subdirectories can have ruby files' do - segment_dir.child('subdir').can_have_child?('blah.rb', false).should be_true - segment_dir.child('subdir').can_have_child?('.blah.rb', false).should be_true - end - it 'subdirectories can have non-ruby files' do - segment_dir.child('subdir').can_have_child?('blah.txt', false).should be_true - segment_dir.child('subdir').can_have_child?('.blah.txt', false).should be_true - end - it 'subdirectories can have subdirectories' do - segment_dir.child('subdir').can_have_child?('blah', true).should be_true - end - end - - context 'the libraries segment' do - let(:segment_dir) { cookbook_dir.child('libraries') } - let(:segment_dir_name) { 'libraries' } - it_behaves_like 'a segment directory' - - before(:each) do - should_get_cookbook - end - - it 'can have ruby files' do - segment_dir.can_have_child?('blah.rb', false).should be_true - segment_dir.can_have_child?('.blah.rb', false).should be_true - end - it 'cannot have non-ruby files' do - segment_dir.can_have_child?('blah.txt', false).should be_false - segment_dir.can_have_child?('.blah.txt', false).should be_false - end - it 'cannot have subdirectories' do - segment_dir.can_have_child?('blah', true).should be_false - end - end - - context 'the providers segment' do - let(:segment_dir) { cookbook_dir.child('providers') } - let(:segment_dir_name) { 'providers' } - it_behaves_like 'a segment directory' - - before(:each) do - should_get_cookbook - end + let(:api_url) { 'cookbooks/?num_versions=all' } - it 'can have ruby files' do - segment_dir.can_have_child?('blah.rb', false).should be_true - segment_dir.can_have_child?('.blah.rb', false).should be_true - end - it 'cannot have non-ruby files' do - segment_dir.can_have_child?('blah.txt', false).should be_false - segment_dir.can_have_child?('.blah.txt', false).should be_false - end - it 'can have subdirectories' do - segment_dir.can_have_child?('blah', true).should be_true - end - it 'subdirectories can have ruby files' do - segment_dir.child('subdir').can_have_child?('blah.rb', false).should be_true - segment_dir.child('subdir').can_have_child?('.blah.rb', false).should be_true - end - it 'subdirectories cannot have non-ruby files' do - segment_dir.child('subdir').can_have_child?('blah.txt', false).should be_false - segment_dir.child('subdir').can_have_child?('.blah.txt', false).should be_false - end - it 'subdirectories can have subdirectories' do - segment_dir.child('subdir').can_have_child?('blah', true).should be_true - end + it 'should return all versions of cookbooks in <cookbook_name>-<version> format' do + entity_names.should include('achild-2.0.0') + entity_names.should include('achild-1.0.0') + entity_names.should include('bchild-1.0.0') end - context 'the recipes segment' do - let(:segment_dir) { cookbook_dir.child('recipes') } - let(:segment_dir_name) { 'recipes' } - it_behaves_like 'a segment directory' - - before(:each) do - should_get_cookbook - end - - it 'can have ruby files' do - segment_dir.can_have_child?('blah.rb', false).should be_true - segment_dir.can_have_child?('.blah.rb', false).should be_true - end - it 'cannot have non-ruby files' do - segment_dir.can_have_child?('blah.txt', false).should be_false - segment_dir.can_have_child?('.blah.txt', false).should be_false - end - it 'cannot have subdirectories' do - segment_dir.can_have_child?('blah', true).should be_false - end + it 'should return cookbooks with server canonical cookbook name' do + cookbook_names.should include('achild') + cookbook_names.should include('bchild') end - context 'the resources segment' do - let(:segment_dir) { cookbook_dir.child('resources') } - let(:segment_dir_name) { 'resources' } - it_behaves_like 'a segment directory' - - before(:each) do - should_get_cookbook - end - - it 'can have ruby files' do - segment_dir.can_have_child?('blah.rb', false).should be_true - segment_dir.can_have_child?('.blah.rb', false).should be_true - end - it 'cannot have non-ruby files' do - segment_dir.can_have_child?('blah.txt', false).should be_false - segment_dir.can_have_child?('.blah.txt', false).should be_false - end - it 'can have subdirectories' do - segment_dir.can_have_child?('blah', true).should be_true - end - it 'subdirectories can have ruby files' do - segment_dir.child('subdir').can_have_child?('blah.rb', false).should be_true - segment_dir.child('subdir').can_have_child?('.blah.rb', false).should be_true - end - it 'subdirectories cannot have non-ruby files' do - segment_dir.child('subdir').can_have_child?('blah.txt', false).should be_false - segment_dir.child('subdir').can_have_child?('.blah.txt', false).should be_false - end - it 'subdirectories can have subdirectories' do - segment_dir.child('subdir').can_have_child?('blah', true).should be_true - end + it 'should return cookbooks with version numbers' do + versions.should include('2.0.0') + versions.should include('1.0.0') + versions.uniq.size.should eql 2 end + end - context 'the templates segment' do - let(:segment_dir) { cookbook_dir.child('templates') } - let(:segment_dir_name) { 'templates' } - it_behaves_like 'a segment directory' - - before(:each) do - should_get_cookbook - end - - it 'can have ruby files' do - segment_dir.can_have_child?('blah.rb', false).should be_true - segment_dir.can_have_child?('.blah.rb', false).should be_true - end - it 'can have non-ruby files' do - segment_dir.can_have_child?('blah.txt', false).should be_true - segment_dir.can_have_child?('.blah.txt', false).should be_true - end - it 'can have subdirectories' do - segment_dir.can_have_child?('blah', true).should be_true - end - it 'subdirectories can have ruby files' do - segment_dir.child('subdir').can_have_child?('blah.rb', false).should be_true - segment_dir.child('subdir').can_have_child?('.blah.rb', false).should be_true - end - it 'subdirectories can have non-ruby files' do - segment_dir.child('subdir').can_have_child?('blah.txt', false).should be_true - segment_dir.child('subdir').can_have_child?('.blah.txt', false).should be_true - end - it 'subdirectories can have subdirectories' do - segment_dir.child('subdir').can_have_child?('blah', true).should be_true - end + context 'without versioned cookbooks' do + it 'should return a single version for each cookbook' do + entity_names.should include('achild') + entity_names.should include('bchild') end - context 'root subdirectories' do - let(:root_subdir) { cookbook_dir.child('subdir') } - - before(:each) do - should_get_cookbook - end - - # Really, since these shouldn't exist in the first place, - # it doesn't matter; but these REALLY shouldn't be able to - # have any files in them at all. - it 'can have ruby files' do - root_subdir.can_have_child?('blah.rb', false).should be_true - root_subdir.can_have_child?('.blah.rb', false).should be_true - end - it 'can have non-ruby files' do - root_subdir.can_have_child?('blah.txt', false).should be_true - root_subdir.can_have_child?('.blah.txt', false).should be_true - end - it 'cannot have subdirectories' do - root_subdir.can_have_child?('blah', true).should be_false - end + it "should return cookbooks '_latest' for version numbers" do + versions.should include('_latest') + versions.uniq.size.should eql 1 end end end - context 'achild from cookbooks_dir.children' do - let(:cookbook_dir_name) { 'achild' } - let(:cookbook_dir) do - should_list_cookbooks - cookbooks_dir.children.select { |child| child.name == 'achild' }.first - end - it_behaves_like 'a cookbook' - end - context 'cookbooks_dir.child(achild)' do - let(:cookbook_dir_name) { 'achild' } - let(:cookbook_dir) { cookbooks_dir.child('achild') } - it_behaves_like 'a cookbook' - end - context 'nonexistent cookbooks_dir.child()' do - let(:nonexistent_child) { cookbooks_dir.child('blah') } - it 'has correct parent, name, path and path_for_printing' do - nonexistent_child.parent.should == cookbooks_dir - nonexistent_child.name.should == "blah" - nonexistent_child.path.should == "/cookbooks/blah" - nonexistent_child.path_for_printing.should == "remote/cookbooks/blah" - end - it 'does not exist' do - should_list_cookbooks - nonexistent_child.exists?.should be_false - end - it 'is a directory' do - should_list_cookbooks - nonexistent_child.dir?.should be_false - end - it 'read returns NotFoundError' do - should_list_cookbooks - expect { nonexistent_child.read }.to raise_error(Chef::ChefFS::FileSystem::NotFoundError) - end - end - end |