diff options
author | Thom May <thom@may.lt> | 2016-04-14 11:23:29 +0100 |
---|---|---|
committer | Thom May <thom@may.lt> | 2016-04-14 11:23:29 +0100 |
commit | 88063538fad12deabc92cfaea2ead957c664bd41 (patch) | |
tree | f6f739c0684a8ae2d362ee68ecfa567fdca426dd | |
parent | 1a129ed91b46b4e92b74d2f22453060f785ee57f (diff) | |
parent | d4a7d82ae1042a601f768edca3bdb94f81a3a387 (diff) | |
download | chef-88063538fad12deabc92cfaea2ead957c664bd41.tar.gz |
Merge pull request #4826 from chef/tm/flow_252
Refactor ChefFS directories to be directories
14 files changed, 572 insertions, 36 deletions
diff --git a/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_acls_dir.rb b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_acls_dir.rb index c347e808f9..cb4c495156 100644 --- a/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_acls_dir.rb +++ b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_acls_dir.rb @@ -17,6 +17,7 @@ # require "chef/chef_fs/file_system/repository/chef_repository_file_system_entry" +require "chef/chef_fs/file_system/repository/directory" require "chef/chef_fs/file_system/chef_server/acls_dir" require "chef/chef_fs/data_handler/acl_data_handler" @@ -24,14 +25,17 @@ class Chef module ChefFS module FileSystem module Repository - class ChefRepositoryFileSystemAclsDir < ChefRepositoryFileSystemEntry - def initialize(name, parent, path = nil) - super(name, parent, path, Chef::ChefFS::DataHandler::AclDataHandler.new) - end + class ChefRepositoryFileSystemAclsDir < Repository::Directory def can_have_child?(name, is_dir) is_dir ? Chef::ChefFS::FileSystem::ChefServer::AclsDir::ENTITY_TYPES.include?(name) : name == "organization.json" end + + protected + + def make_child_entry(child_name) + ChefRepositoryFileSystemEntry.new(child_name, self, nil, Chef::ChefFS::DataHandler::AclDataHandler.new) + end end end end diff --git a/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_client_keys_dir.rb b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_client_keys_dir.rb index 237d1035ad..544f089096 100644 --- a/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_client_keys_dir.rb +++ b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_client_keys_dir.rb @@ -18,19 +18,23 @@ require "chef/chef_fs/file_system/repository/chef_repository_file_system_entry" require "chef/chef_fs/data_handler/client_key_data_handler" +require "chef/chef_fs/file_system/repository/directory" class Chef module ChefFS module FileSystem module Repository class ChefRepositoryFileSystemClientKeysDir < ChefRepositoryFileSystemEntry - def initialize(name, parent, path = nil) - super(name, parent, path, Chef::ChefFS::DataHandler::ClientKeyDataHandler.new) - end def can_have_child?(name, is_dir) is_dir && !name.start_with?(".") end + + protected + + def make_child_entry(child_name) + ChefRepositoryFileSystemEntry.new(child_name, self, nil, Chef::ChefFS::DataHandler::ClientKeyDataHandler.new) + end end end end diff --git a/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_entry.rb b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_entry.rb index b9d681c116..e490daa584 100644 --- a/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_entry.rb +++ b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_entry.rb @@ -57,12 +57,22 @@ class Chef !is_dir && name[-5..-1] == ".json" end + def name_valid? + !name.start_with?(".") + end + + # basic implementation to support Repository::Directory API + def fs_entry_valid? + name_valid? && File.exist?(file_path) + end + def write(file_contents) if file_contents && write_pretty_json && name[-5..-1] == ".json" file_contents = minimize(file_contents, self) end super(file_contents) end + alias :create :write def minimize(file_contents, entry) object = Chef::JSONCompat.parse(file_contents) diff --git a/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_root_dir.rb b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_root_dir.rb index c7209ba634..4457910317 100644 --- a/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_root_dir.rb +++ b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_root_dir.rb @@ -18,9 +18,17 @@ require "chef/chef_fs/file_system/base_fs_dir" require "chef/chef_fs/file_system/repository/chef_repository_file_system_acls_dir" +require "chef/chef_fs/file_system/repository/clients_dir" require "chef/chef_fs/file_system/repository/cookbooks_dir" require "chef/chef_fs/file_system/repository/cookbook_artifacts_dir" +require "chef/chef_fs/file_system/repository/containers_dir" require "chef/chef_fs/file_system/repository/data_bags_dir" +require "chef/chef_fs/file_system/repository/environments_dir" +require "chef/chef_fs/file_system/repository/groups_dir" +require "chef/chef_fs/file_system/repository/nodes_dir" +require "chef/chef_fs/file_system/repository/policy_groups_dir" +require "chef/chef_fs/file_system/repository/roles_dir" +require "chef/chef_fs/file_system/repository/users_dir" require "chef/chef_fs/file_system/repository/chef_repository_file_system_client_keys_dir" require "chef/chef_fs/file_system/repository/chef_repository_file_system_entry" require "chef/chef_fs/file_system/repository/chef_repository_file_system_policies_dir" @@ -166,6 +174,14 @@ class Chef return NonexistentFSObject.new(name, self) end case name + when "acls" + dirs = paths.map { |path| ChefRepositoryFileSystemAclsDir.new(name, self, path) } + when "client_keys" + dirs = paths.map { |path| ChefRepositoryFileSystemClientKeysDir.new(name, self, path) } + when "clients" + dirs = paths.map { |path| ClientsDir.new(name, self, path) } + when "containers" + dirs = paths.map { |path| ContainersDir.new(name, self, path) } when "cookbooks" if versioned_cookbooks dirs = paths.map { |path| VersionedCookbooksDir.new(name, self, path) } @@ -174,36 +190,24 @@ class Chef end when "cookbook_artifacts" dirs = paths.map { |path| CookbookArtifactsDir.new(name, self, path) } - when "policies" - dirs = paths.map { |path| ChefRepositoryFileSystemPoliciesDir.new(name, self, path) } when "data_bags" dirs = paths.map { |path| DataBagsDir.new(name, self, path) } - when "acls" - dirs = paths.map { |path| ChefRepositoryFileSystemAclsDir.new(name, self, path) } - when "client_keys" - dirs = paths.map { |path| ChefRepositoryFileSystemClientKeysDir.new(name, self, path) } + when "environments" + dirs = paths.map { |path| EnvironmentsDir.new(name, self, path) } + when "groups" + dirs = paths.map { |path| GroupsDir.new(name, self, path) } + when "nodes" + dirs = paths.map { |path| NodesDir.new(name, self, path) } + when "policy_groups" + dirs = paths.map { |path| PolicyGroupsDir.new(name, self, path) } + when "policies" + dirs = paths.map { |path| ChefRepositoryFileSystemPoliciesDir.new(name, self, path) } + when "roles" + dirs = paths.map { |path| RolesDir.new(name, self, path) } + when "users" + dirs = paths.map { |path| UsersDir.new(name, self, path) } else - data_handler = case name - when "clients" - Chef::ChefFS::DataHandler::ClientDataHandler.new - when "environments" - Chef::ChefFS::DataHandler::EnvironmentDataHandler.new - when "nodes" - Chef::ChefFS::DataHandler::NodeDataHandler.new - when "policy_groups" - Chef::ChefFS::DataHandler::PolicyGroupDataHandler.new - when "roles" - Chef::ChefFS::DataHandler::RoleDataHandler.new - when "users" - Chef::ChefFS::DataHandler::UserDataHandler.new - when "groups" - Chef::ChefFS::DataHandler::GroupDataHandler.new - when "containers" - Chef::ChefFS::DataHandler::ContainerDataHandler.new - else - raise "Unknown top level path #{name}" - end - dirs = paths.map { |path| ChefRepositoryFileSystemEntry.new(name, self, path, data_handler) } + raise "Unknown top level path #{name}" end MultiplexedDir.new(dirs) end diff --git a/lib/chef/chef_fs/file_system/repository/clients_dir.rb b/lib/chef/chef_fs/file_system/repository/clients_dir.rb new file mode 100644 index 0000000000..6e23a6b8be --- /dev/null +++ b/lib/chef/chef_fs/file_system/repository/clients_dir.rb @@ -0,0 +1,40 @@ +# +# Author:: John Keiser (<jkeiser@chef.io>) +# Author:: Ho-Sheng Hsiao (<hosh@chef.io>) +# Copyright:: Copyright 2012-2016, Chef Software 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 "chef/chef_fs/file_system/repository/chef_repository_file_system_entry" +require "chef/chef_fs/file_system/repository/directory" +require "chef/chef_fs/file_system/exceptions" + +class Chef + module ChefFS + module FileSystem + module Repository + class ClientsDir < Repository::Directory + def can_have_child?(name, is_dir) + !is_dir && File.extname(name) == ".json" + end + + def make_child_entry(child_name) + ChefRepositoryFileSystemEntry.new(child_name, self, nil, Chef::ChefFS::DataHandler::ClientDataHandler.new) + end + end + end + end + end +end diff --git a/lib/chef/chef_fs/file_system/repository/containers_dir.rb b/lib/chef/chef_fs/file_system/repository/containers_dir.rb new file mode 100644 index 0000000000..b5ff84be7b --- /dev/null +++ b/lib/chef/chef_fs/file_system/repository/containers_dir.rb @@ -0,0 +1,41 @@ +# +# Author:: John Keiser (<jkeiser@chef.io>) +# Author:: Ho-Sheng Hsiao (<hosh@chef.io>) +# Copyright:: Copyright 2012-2016, Chef Software 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 "chef/chef_fs/file_system/repository/chef_repository_file_system_entry" +require "chef/chef_fs/file_system/repository/directory" +require "chef/chef_fs/file_system/exceptions" + +class Chef + module ChefFS + module FileSystem + module Repository + class ContainersDir < Repository::Directory + + def can_have_child?(name, is_dir) + !is_dir && File.extname(name) == ".json" + end + + def make_child_entry(child_name) + ChefRepositoryFileSystemEntry.new(child_name, self, nil, Chef::ChefFS::DataHandler::ContainerDataHandler.new) + end + end + end + end + end +end diff --git a/lib/chef/chef_fs/file_system/repository/directory.rb b/lib/chef/chef_fs/file_system/repository/directory.rb index 782a134a58..20f6f82108 100644 --- a/lib/chef/chef_fs/file_system/repository/directory.rb +++ b/lib/chef/chef_fs/file_system/repository/directory.rb @@ -66,13 +66,26 @@ class Chef def children dir_ls.sort. map { |child_name| make_child_entry(child_name) }. - select { |maybe_child| maybe_child.fs_entry_valid? } + select { |new_child| new_child.fs_entry_valid? && can_have_child?(new_child.name, new_child.dir?) } rescue Errno::ENOENT => e raise Chef::ChefFS::FileSystem::NotFoundError.new(self, e) end def create_child(child_name, file_contents = nil) - make_child_entry(child_name).tap { |c| c.create(file_contents) } + child = make_child_entry(child_name) + if child.exists? + raise Chef::ChefFS::FileSystem::AlreadyExistsError.new(:create_child, child) + end + if file_contents + child.write(file_contents) + else + begin + Dir.mkdir(child.file_path) + rescue Errno::EEXIST + raise Chef::ChefFS::FileSystem::AlreadyExistsError.new(:create_child, child) + end + end + child end # An empty children array is an empty dir diff --git a/lib/chef/chef_fs/file_system/repository/environments_dir.rb b/lib/chef/chef_fs/file_system/repository/environments_dir.rb new file mode 100644 index 0000000000..50b6dbefca --- /dev/null +++ b/lib/chef/chef_fs/file_system/repository/environments_dir.rb @@ -0,0 +1,41 @@ +# +# Author:: John Keiser (<jkeiser@chef.io>) +# Author:: Ho-Sheng Hsiao (<hosh@chef.io>) +# Copyright:: Copyright 2012-2016, Chef Software 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 "chef/chef_fs/file_system/repository/chef_repository_file_system_entry" +require "chef/chef_fs/data_handler/environment_data_handler" +require "chef/chef_fs/file_system/repository/directory" + +class Chef + module ChefFS + module FileSystem + module Repository + class EnvironmentsDir < Repository::Directory + + def can_have_child?(name, is_dir) + !is_dir && File.extname(name) == ".json" + end + + def make_child_entry(child_name) + ChefRepositoryFileSystemEntry.new(child_name, self, nil, Chef::ChefFS::DataHandler::EnvironmentDataHandler.new) + end + end + end + end + end +end diff --git a/lib/chef/chef_fs/file_system/repository/groups_dir.rb b/lib/chef/chef_fs/file_system/repository/groups_dir.rb new file mode 100644 index 0000000000..f9ca4956b0 --- /dev/null +++ b/lib/chef/chef_fs/file_system/repository/groups_dir.rb @@ -0,0 +1,41 @@ +# +# Author:: John Keiser (<jkeiser@chef.io>) +# Author:: Ho-Sheng Hsiao (<hosh@chef.io>) +# Copyright:: Copyright 2012-2016, Chef Software 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 "chef/chef_fs/file_system/repository/chef_repository_file_system_entry" +require "chef/chef_fs/file_system/repository/directory" +require "chef/chef_fs/file_system/exceptions" + +class Chef + module ChefFS + module FileSystem + module Repository + class GroupsDir < Repository::Directory + + def can_have_child?(name, is_dir) + !is_dir && File.extname(name) == ".json" + end + + def make_child_entry(child_name) + ChefRepositoryFileSystemEntry.new(child_name, self, nil, Chef::ChefFS::DataHandler::GroupDataHandler.new) + end + end + end + end + end +end diff --git a/lib/chef/chef_fs/file_system/repository/nodes_dir.rb b/lib/chef/chef_fs/file_system/repository/nodes_dir.rb new file mode 100644 index 0000000000..7263dc3132 --- /dev/null +++ b/lib/chef/chef_fs/file_system/repository/nodes_dir.rb @@ -0,0 +1,41 @@ +# +# Author:: John Keiser (<jkeiser@chef.io>) +# Author:: Ho-Sheng Hsiao (<hosh@chef.io>) +# Copyright:: Copyright 2012-2016, Chef Software 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 "chef/chef_fs/file_system/repository/chef_repository_file_system_entry" +require "chef/chef_fs/file_system/repository/directory" +require "chef/chef_fs/file_system/exceptions" + +class Chef + module ChefFS + module FileSystem + module Repository + class NodesDir < Repository::Directory + + def can_have_child?(name, is_dir) + !is_dir && File.extname(name) == ".json" + end + + def make_child_entry(child_name) + ChefRepositoryFileSystemEntry.new(child_name, self, nil, Chef::ChefFS::DataHandler::NodeDataHandler.new) + end + end + end + end + end +end diff --git a/lib/chef/chef_fs/file_system/repository/policy_groups_dir.rb b/lib/chef/chef_fs/file_system/repository/policy_groups_dir.rb new file mode 100644 index 0000000000..314c375879 --- /dev/null +++ b/lib/chef/chef_fs/file_system/repository/policy_groups_dir.rb @@ -0,0 +1,41 @@ +# +# Author:: John Keiser (<jkeiser@chef.io>) +# Author:: Ho-Sheng Hsiao (<hosh@chef.io>) +# Copyright:: Copyright 2012-2016, Chef Software 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 "chef/chef_fs/file_system/repository/chef_repository_file_system_entry" +require "chef/chef_fs/file_system/repository/directory" +require "chef/chef_fs/file_system/exceptions" + +class Chef + module ChefFS + module FileSystem + module Repository + class PolicyGroupsDir < Repository::Directory + + def can_have_child?(name, is_dir) + !is_dir && File.extname(name) == ".json" + end + + def make_child_entry(child_name) + ChefRepositoryFileSystemEntry.new(child_name, self, nil, Chef::ChefFS::DataHandler::PolicyGroupDataHandler.new) + end + end + end + end + end +end diff --git a/lib/chef/chef_fs/file_system/repository/roles_dir.rb b/lib/chef/chef_fs/file_system/repository/roles_dir.rb new file mode 100644 index 0000000000..e3acd3a730 --- /dev/null +++ b/lib/chef/chef_fs/file_system/repository/roles_dir.rb @@ -0,0 +1,41 @@ +# +# Author:: John Keiser (<jkeiser@chef.io>) +# Author:: Ho-Sheng Hsiao (<hosh@chef.io>) +# Copyright:: Copyright 2012-2016, Chef Software 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 "chef/chef_fs/file_system/repository/chef_repository_file_system_entry" +require "chef/chef_fs/file_system/repository/directory" +require "chef/chef_fs/file_system/exceptions" + +class Chef + module ChefFS + module FileSystem + module Repository + class RolesDir < Repository::Directory + + def can_have_child?(name, is_dir) + !is_dir && File.extname(name) == ".json" + end + + def make_child_entry(child_name) + ChefRepositoryFileSystemEntry.new(child_name, self, nil, Chef::ChefFS::DataHandler::RoleDataHandler.new) + end + end + end + end + end +end diff --git a/lib/chef/chef_fs/file_system/repository/users_dir.rb b/lib/chef/chef_fs/file_system/repository/users_dir.rb new file mode 100644 index 0000000000..928bb2d699 --- /dev/null +++ b/lib/chef/chef_fs/file_system/repository/users_dir.rb @@ -0,0 +1,41 @@ +# +# Author:: John Keiser (<jkeiser@chef.io>) +# Author:: Ho-Sheng Hsiao (<hosh@chef.io>) +# Copyright:: Copyright 2012-2016, Chef Software 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 "chef/chef_fs/file_system/repository/chef_repository_file_system_entry" +require "chef/chef_fs/file_system/repository/directory" +require "chef/chef_fs/file_system/exceptions" + +class Chef + module ChefFS + module FileSystem + module Repository + class UsersDir < Repository::Directory + + def can_have_child?(name, is_dir) + !is_dir && File.extname(name) == ".json" + end + + def make_child_entry(child_name) + ChefRepositoryFileSystemEntry.new(child_name, self, nil, Chef::ChefFS::DataHandler::UserDataHandler.new) + end + end + end + end + end +end diff --git a/spec/unit/chef_fs/file_system/repository/directory_spec.rb b/spec/unit/chef_fs/file_system/repository/directory_spec.rb new file mode 100644 index 0000000000..e050181be9 --- /dev/null +++ b/spec/unit/chef_fs/file_system/repository/directory_spec.rb @@ -0,0 +1,174 @@ +# +# Author:: Thom May (<thom@chef.io>) +# Copyright:: Copyright 2012-2016, Chef Software 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/repository/directory" +require "chef/chef_fs/file_system/base_fs_object" +require "chef/chef_fs/file_system/exceptions" +require "chef/chef_fs/file_system/nonexistent_fs_object" + +CHILD_FILES = %w{ test1.json test2.json skip test3.json skip2 test4 } + +class TestDirectory < Chef::ChefFS::FileSystem::Repository::Directory + def make_child_entry(name) + TestFile.new(name, self) + end + + def can_have_child?(name, is_dir) + !is_dir && File.extname(name) == ".json" + end + + def dir_ls + CHILD_FILES + end +end + +class TestFile < Chef::ChefFS::FileSystem::BaseFSObject + def fs_entry_valid? + name.start_with? "test" + end + + def name_valid? + true + end +end + +describe Chef::ChefFS::FileSystem::Repository::Directory do + let(:root) do + Chef::ChefFS::FileSystem::BaseFSDir.new("", nil) + end + + let(:tmp_dir) { Dir.mktmpdir } + + let(:directory) do + described_class.new("test", root, tmp_dir) + end + + let(:test_directory) do + TestDirectory.new("test", root, tmp_dir) + end + + let(:file_double) do + double(TestFile, create: true, exists?: false) + end + + context "#make_child_entry" do + it "raises if not implemented" do + expect { directory.send(:make_child_entry, "test") }.to raise_error("Not Implemented") + end + end + + context "#create_child" do + it "creates a new TestFile" do + expect(TestFile).to receive(:new).with("test_child", test_directory).and_return(file_double) + expect(file_double).to receive(:write).with("test") + test_directory.create_child("test_child", "test") + end + end + + context "#child" do + it "returns a child if it's valid" do + expect(test_directory.child("test")).to be_an_instance_of(TestFile) + end + + it "returns a non existent object otherwise" do + file_double = instance_double(TestFile, :name_valid? => false) + expect(TestFile).to receive(:new).with("test_child", test_directory).and_return(file_double) + expect(test_directory.child("test_child")).to be_an_instance_of(Chef::ChefFS::FileSystem::NonexistentFSObject) + end + end + + context "#children" do + before do + CHILD_FILES.sort.each do |child| + expect(TestFile).to receive(:new).with(child, test_directory).and_call_original + end + end + + it "creates a child for each name" do + test_directory.children + end + + it "filters invalid names" do + expect(test_directory.children.map { |c| c.name }).to eql %w{ test1.json test2.json test3.json } + end + end + + context "#empty?" do + it "is true if there are no children" do + expect(test_directory).to receive(:children).and_return([]) + expect(test_directory.empty?).to be_truthy + end + + it "is false if there are children" do + expect(test_directory.empty?).to be_falsey + end + end + + describe "checks entry validity" do + it "rejects dotfiles" do + dir = described_class.new(".test", root, tmp_dir) + expect(dir.name_valid?).to be_falsey + end + + it "rejects files" do + Tempfile.open("test") do |file| + dir = described_class.new("test", root, file.path) + expect(dir.name_valid?).to be_truthy + expect(dir.fs_entry_valid?).to be_falsey + end + end + + it "accepts directories" do + expect(directory.name_valid?).to be_truthy + end + end + + describe "creates directories" do + it "doesn't create an existing directory" do + expect { directory.create }.to raise_error(Chef::ChefFS::FileSystem::AlreadyExistsError) + end + + it "creates a new directory" do + FileUtils.rmdir(tmp_dir) + expect(Dir).to receive(:mkdir).with(tmp_dir) + expect { directory.create }.to_not raise_error + end + + after do + FileUtils.rmdir(tmp_dir) + end + end + + describe "deletes directories" do + it "won't delete a non-existant directory" do + FileUtils.rmdir(tmp_dir) + expect { directory.delete(true) }.to raise_error(Chef::ChefFS::FileSystem::NotFoundError) + end + + it "must delete recursively" do + expect { directory.delete(false) }.to raise_error(Chef::ChefFS::FileSystem::MustDeleteRecursivelyError) + end + + it "deletes a directory" do + expect(FileUtils).to receive(:rm_r).with(tmp_dir) + expect { directory.delete(true) }.to_not raise_error + end + end + +end |