summaryrefslogtreecommitdiff
path: root/spec/support
diff options
context:
space:
mode:
authordanielsdeleo <dan@opscode.com>2013-06-24 17:30:27 -0700
committerdanielsdeleo <dan@opscode.com>2013-06-26 10:47:47 -0700
commit34dd4d4730656141889dc0cf9eee45e979b0a141 (patch)
tree6bcf1bc2e4efe24e2709aea01791f3d39632e91a /spec/support
parent283ab69016cb7e485ffaee0836ca486144d4de94 (diff)
downloadchef-34dd4d4730656141889dc0cf9eee45e979b0a141.tar.gz
Allow file resources to manage files via symlink
Fixes CHEF-4312 http://tickets.opscode.com/browse/CHEF-4312 Adds resource attribute `manage_symlink_source` to file resource and descendents. When true, file resources will manage the source file when a symlink exists at the destination path. When nil (default), the source file is managed, but a warning is emitted. When false, symlinks are not followed. In Chef 12, the default should be changed to false.
Diffstat (limited to 'spec/support')
-rw-r--r--spec/support/shared/functional/file_resource.rb190
1 files changed, 164 insertions, 26 deletions
diff --git a/spec/support/shared/functional/file_resource.rb b/spec/support/shared/functional/file_resource.rb
index ec0ddafb00..2b4330b539 100644
--- a/spec/support/shared/functional/file_resource.rb
+++ b/spec/support/shared/functional/file_resource.rb
@@ -369,45 +369,183 @@ shared_examples_for "a configured file resource" do
File.join(CHEF_SPEC_DATA, "file-test-target")
}
- before do
- FileUtils.touch(symlink_target)
- end
- after do
- FileUtils.rm_rf(symlink_target)
- end
+ describe "when configured not to manage symlink's target" do
+ before(:each) do
+ # configure not to manage symlink source
+ resource.manage_symlink_source(false)
- before(:each) do
- if windows?
- Chef::ReservedNames::Win32::File.symlink(symlink_target, path)
- else
- File.symlink(symlink_target, path)
+ # create symlinks for test context
+ FileUtils.touch(symlink_target)
+
+ if windows?
+ Chef::ReservedNames::Win32::File.symlink(symlink_target, path)
+ else
+ File.symlink(symlink_target, path)
+ end
end
- end
- after(:each) do
- FileUtils.rm_rf(path)
- end
+ after(:each) do
+ FileUtils.rm_rf(symlink_target)
+ FileUtils.rm_rf(path)
+ end
- describe "when symlink target has correct content" do
- before(:each) do
- File.open(symlink_target, "wb") { |f| f.print expected_content }
+ describe "when symlink target has correct content" do
+ before(:each) do
+ File.open(symlink_target, "wb") { |f| f.print expected_content }
+ end
+
+ it_behaves_like "file resource not pointing to a real file"
end
- it_behaves_like "file resource not pointing to a real file"
+ describe "when symlink target has the wrong content" do
+ before(:each) do
+ File.open(symlink_target, "wb") { |f| f.print "This is so wrong!!!" }
+ end
+
+ after(:each) do
+ # symlink should never be followed
+ binread(symlink_target).should == "This is so wrong!!!"
+ end
+
+ it_behaves_like "file resource not pointing to a real file"
+ end
end
- describe "when symlink target has the wrong content" do
- before(:each) do
- File.open(symlink_target, "wb") { |f| f.print "This is so wrong!!!" }
+ # Unix-only for now. Windows behavior may differ because of how ACL
+ # management handles symlinks. Since symlinks are rare on Windows and this
+ # feature primarily exists to support the case where a well-known file
+ # (e.g., resolv.conf) has been converted to a symlink, we're okay with the
+ # discrepancy.
+ context "when configured to manage the symlink source", :unix_only do
+
+ before do
+ resource.manage_symlink_source(true)
end
- after(:each) do
- # symlink should never be followed
- binread(symlink_target).should == "This is so wrong!!!"
+ context "but the symlink is part of a loop" do
+ let(:link1_path) { File.join(CHEF_SPEC_DATA, "points-to-link2") }
+ let(:link2_path) { File.join(CHEF_SPEC_DATA, "points-to-link1") }
+
+ before do
+ # point resource at link1:
+ resource.path(link1_path)
+ # create symlinks for test context
+ File.symlink(link1_path, link2_path)
+ File.symlink(link2_path, link1_path)
+ end
+
+ after(:each) do
+ FileUtils.rm_rf(link1_path)
+ FileUtils.rm_rf(link2_path)
+ end
+
+ it "raises an InvalidSymlink error" do
+ lambda { resource.run_action(:create) }.should raise_error(Chef::Exceptions::InvalidSymlink)
+ end
+
+ it "issues a warning/assumption in whyrun mode" do
+ begin
+ Chef::Config[:why_run] = true
+ resource.run_action(:create) # should not raise
+ ensure
+ Chef::Config[:why_run] = false
+ end
+ end
+ end
+
+ context "but the symlink points to a nonexistent file" do
+ let(:link_path) { File.join(CHEF_SPEC_DATA, "points-to-nothing") }
+ let(:not_existent_source) { File.join(CHEF_SPEC_DATA, "i-am-not-here") }
+
+ before do
+ resource.path(link_path)
+ # create symlinks for test context
+ File.symlink(not_existent_source, link_path)
+ FileUtils.rm_rf(not_existent_source)
+ end
+
+ after(:each) do
+ FileUtils.rm_rf(link_path)
+ end
+ it "raises an InvalidSymlink error" do
+ lambda { resource.run_action(:create) }.should raise_error(Chef::Exceptions::InvalidSymlink)
+ end
+
+ it "issues a warning/assumption in whyrun mode" do
+ begin
+ Chef::Config[:why_run] = true
+ resource.run_action(:create) # should not raise
+ ensure
+ Chef::Config[:why_run] = false
+ end
+ end
+ end
+
+ context "but the symlink is points to a non-file fs entry" do
+ let(:link_path) { File.join(CHEF_SPEC_DATA, "points-to-dir") }
+ let(:not_a_file_path) { File.join(CHEF_SPEC_DATA, "dir-at-end-of-symlink") }
+
+ before do
+ # point resource at link1:
+ resource.path(link_path)
+ # create symlinks for test context
+ File.symlink(not_a_file_path, link_path)
+ Dir.mkdir(not_a_file_path)
+ end
+
+ after(:each) do
+ FileUtils.rm_rf(link_path)
+ FileUtils.rm_rf(not_a_file_path)
+ end
+
+ it "raises an InvalidSymlink error" do
+ lambda { resource.run_action(:create) }.should raise_error(Chef::Exceptions::FileTypeMismatch)
+ end
+
+ it "issues a warning/assumption in whyrun mode" do
+ begin
+ Chef::Config[:why_run] = true
+ resource.run_action(:create) # should not raise
+ ensure
+ Chef::Config[:why_run] = false
+ end
+ end
+ end
+
+ context "when the symlink source is a real file" do
+
+ let(:wrong_content) { "this is the wrong content" }
+ let(:link_path) { File.join(CHEF_SPEC_DATA, "points-to-real-file") }
+
+ before do
+ # point resource at link:
+ resource.path(link_path)
+ # create symlinks for test context
+ File.symlink(path, link_path)
+
+ # Create source (real) file
+ File.open(path, "wb") { |f| f.write(wrong_content) }
+ end
+
+ include_context "setup broken permissions"
+
+ include_examples "a securable resource with existing target"
+
+ after(:each) do
+ # shared examples should not change our test setup of a file resource
+ # pointing at a symlink:
+ resource.path.should == link_path
+ FileUtils.rm_rf(link_path)
+ end
+
+ it "does not replace the symlink with a real file" do
+ resource.run_action(:create)
+ File.should be_symlink(link_path)
+ end
+
end
- it_behaves_like "file resource not pointing to a real file"
end
end