diff options
Diffstat (limited to 'spec/unit/chef_fs/file_system/cookbooks_dir_spec.rb')
-rw-r--r-- | spec/unit/chef_fs/file_system/cookbooks_dir_spec.rb | 568 |
1 files changed, 568 insertions, 0 deletions
diff --git a/spec/unit/chef_fs/file_system/cookbooks_dir_spec.rb b/spec/unit/chef_fs/file_system/cookbooks_dir_spec.rb new file mode 100644 index 0000000000..35a777a9e4 --- /dev/null +++ b/spec/unit/chef_fs/file_system/cookbooks_dir_spec.rb @@ -0,0 +1,568 @@ +# +# 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::CookbooksDir do + let(:root_dir) { + Chef::ChefFS::FileSystem::ChefServerRootDir.new('remote', + { + :chef_server_url => 'url', + :node_name => 'username', + :client_key => 'key' + }, + 'everything') + } + let(:cookbooks_dir) { root_dir.child('cookbooks') } + let(:should_list_cookbooks) do + @rest.should_receive(:get_rest).with('cookbooks').once.and_return( + { + "achild" => "http://opscode.com/achild", + "bchild" => "http://opscode.com/bchild" + }) + end + before(:each) do + @rest = double("rest") + Chef::REST.stub(:new).with('url','username','key') { @rest } + end + + 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 + 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 + def json_file(path, checksum) + filename = Chef::ChefFS::PathUtils.split(path)[-1] + { + :name => filename, + :url => "cookbook_file:#{path}", + :checksum => checksum, + :path => path, + :specificity => "default" + } + end + def json_files(cookbook_dir) + result = [] + files.each do |filename| + if filename =~ /^#{cookbook_dir}\// + result << json_file(filename, file_checksums[filename]) + end + end + result + end + let(:files) { + result = [] + %w(attributes definitions files libraries providers recipes resources templates).each do |segment| + result << "#{segment}/a.rb" + result << "#{segment}/b.txt" + result << "#{segment}/subdir/a.rb" + result << "#{segment}/subdir/b.txt" + end + result << 'a.rb' + result << 'b.txt' + result << 'subdir/a.rb' + result << 'subdir/b.txt' + result << 'root_files' + result + } + let(:file_checksums) { + result = {} + files.each_with_index do |file, i| + result[file] = i.to_s(16) + end + result + } + let(:should_get_cookbook) do + cookbook = double('cookbook') + cookbook.should_receive(:manifest).and_return({ + :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 => [ + json_file('a.rb', file_checksums['a.rb']), + json_file('b.txt', file_checksums['b.txt']), + json_file('subdir/a.rb', file_checksums['subdir/a.rb']), + json_file('subdir/b.txt', file_checksums['subdir/b.txt']), + json_file('root_files', file_checksums['root_files']) + ] + }) + @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| + @rest.should_receive(:get_rest).with("cookbook_file:#{path}").once.and_return("This is #{path}'s content") + @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 + expect { nonexistent_child.read }.to raise_error(Chef::ChefFS::FileSystem::NotFoundError) + end + end + +end |