diff options
Diffstat (limited to 'spec/functional/resource/link_spec.rb')
-rw-r--r-- | spec/functional/resource/link_spec.rb | 132 |
1 files changed, 109 insertions, 23 deletions
diff --git a/spec/functional/resource/link_spec.rb b/spec/functional/resource/link_spec.rb index 6dd6ad8422..2b8b509730 100644 --- a/spec/functional/resource/link_spec.rb +++ b/spec/functional/resource/link_spec.rb @@ -1,6 +1,6 @@ # # Author:: John Keiser (<jkeiser@chef.io>) -# Copyright:: Copyright 2011-2016, Chef Software Inc. +# Copyright:: Copyright 2011-2017, Chef Software Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,12 +20,14 @@ require "spec_helper" if windows? require "chef/win32/file" #probably need this in spec_helper + require "chef/win32/security" end describe Chef::Resource::Link do let(:file_base) { "file_spec" } let(:expect_updated?) { true } + let(:logger) { double("Mixlib::Log::Child").as_null_object } # We create the files in a different directory than tmp to exercise # different file deployment strategies more completely. @@ -62,6 +64,18 @@ describe Chef::Resource::Link do end end + def node + node = Chef::Node.new + node.consume_external_attrs(ohai.data, {}) + node + end + + def user(user) + usr = Chef::Resource.resource_for_node(:user, node).new(user, run_context) + usr.password("ComplexPass11!") if windows? + usr + end + def cleanup_link(path) if windows? && File.directory?(path) # If the link target is a directory rm_rf doesn't work all the @@ -108,12 +122,49 @@ describe Chef::Resource::Link do end end + let(:test_user) { windows? ? nil : ENV["USER"] } + + def expected_owner + if windows? + get_sid(test_user) + else + test_user + end + end + + def get_sid(value) + if value.kind_of?(String) + Chef::ReservedNames::Win32::Security::SID.from_account(value) + elsif value.kind_of?(Chef::ReservedNames::Win32::Security::SID) + value + else + raise "Must specify username or SID: #{value}" + end + end + + def chown(file, user) + if windows? + Chef::ReservedNames::Win32::Security::SecurableObject.new(file).owner = get_sid(user) + else + File.lchown(Etc.getpwnam(user).uid, Etc.getpwnam(user).gid, file) + end + end + + def owner(file) + if windows? + Chef::ReservedNames::Win32::Security::SecurableObject.new(file).security_descriptor.owner + else + Etc.getpwuid(File.lstat(file).uid).name + end + end + def create_resource node = Chef::Node.new events = Chef::EventDispatch::Dispatcher.new cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks")) cookbook_collection = Chef::CookbookCollection.new(Chef::CookbookLoader.new(cookbook_repo)) run_context = Chef::RunContext.new(node, cookbook_collection, events) + allow(run_context).to receive(:logger).and_return(logger) resource = Chef::Resource::Link.new(target_file, run_context) resource.to(to) resource @@ -123,7 +174,7 @@ describe Chef::Resource::Link do create_resource end - describe "when supported on platform", :not_supported_on_win2k3 do + describe "when supported on platform" do shared_examples_for "delete errors out" do it "delete errors out" do expect { resource.run_action(:delete) }.to raise_error(Chef::Exceptions::Link) @@ -135,7 +186,7 @@ describe Chef::Resource::Link do describe "the :delete action" do before(:each) do @info = [] - allow(Chef::Log).to receive(:info) { |msg| @info << msg } + allow(logger).to receive(:info) { |msg| @info << msg } resource.run_action(:delete) end @@ -156,7 +207,7 @@ describe Chef::Resource::Link do describe "the :delete action" do before(:each) do @info = [] - allow(Chef::Log).to receive(:info) { |msg| @info << msg } + allow(logger).to receive(:info) { |msg| @info << msg } resource.run_action(:delete) end @@ -177,13 +228,14 @@ describe Chef::Resource::Link do describe "the :create action" do before(:each) do @info = [] - allow(Chef::Log).to receive(:info) { |msg| @info << msg } + allow(logger).to receive(:info) { |msg| @info << msg } resource.run_action(:create) end it "links to the target file" do expect(symlink?(target_file)).to be_truthy expect(readlink(target_file)).to eq(canonicalize(to)) + expect(owner(target_file)).to eq(expected_owner) unless test_user.nil? end it "marks the resource updated" do expect(resource).to be_updated @@ -198,13 +250,14 @@ describe Chef::Resource::Link do describe "the :create action" do before(:each) do @info = [] - allow(Chef::Log).to receive(:info) { |msg| @info << msg } + allow(logger).to receive(:info) { |msg| @info << msg } resource.run_action(:create) end it "leaves the file linked" do expect(symlink?(target_file)).to be_truthy expect(readlink(target_file)).to eq(canonicalize(to)) + expect(owner(target_file)).to eq(expected_owner) unless test_user.nil? end it "does not mark the resource updated" do expect(resource).not_to be_updated @@ -219,7 +272,7 @@ describe Chef::Resource::Link do describe "the :create action" do before(:each) do @info = [] - allow(Chef::Log).to receive(:info) { |msg| @info << msg } + allow(logger).to receive(:info) { |msg| @info << msg } resource.run_action(:create) end it "preserves the hard link" do @@ -244,7 +297,7 @@ describe Chef::Resource::Link do describe "the :create action" do before(:each) do @info = [] - allow(Chef::Log).to receive(:info) { |msg| @info << msg } + allow(logger).to receive(:info) { |msg| @info << msg } resource.run_action(:create) end it "links to the target file" do @@ -291,13 +344,23 @@ describe Chef::Resource::Link do expect(File.exists?(to)).to be_truthy end end - context "pointing somewhere else" do + context "pointing somewhere else", :requires_root_or_running_windows do + let(:test_user) { "test-link-user" } + before do + user(test_user).run_action(:create) + end + after do + user(test_user).run_action(:remove) + end before(:each) do + resource.owner(test_user) @other_target = File.join(test_file_dir, make_tmpname("other_spec")) File.open(@other_target, "w") { |file| file.write("eek") } symlink(@other_target, target_file) + chown(target_file, test_user) expect(symlink?(target_file)).to be_truthy expect(readlink(target_file)).to eq(canonicalize(@other_target)) + expect(owner(target_file)).to eq(expected_owner) end after(:each) do File.delete(@other_target) @@ -388,6 +451,14 @@ describe Chef::Resource::Link do symlink(other_dir, target_file) end include_context "create symbolic link succeeds" + include_context "delete succeeds" + end + context "and the link already exists and points at the target" do + before do + symlink(to, target_file) + end + include_context "create symbolic link is noop" + include_context "delete succeeds" end end context "when the link destination is a symbolic link" do @@ -406,6 +477,19 @@ describe Chef::Resource::Link do include_context "create symbolic link succeeds" include_context "delete is noop" end + context "and the destination itself has another symbolic link" do + context "to a link that exist" do + before do + symlink(to, target_file) + end + include_context "create symbolic link is noop" + include_context "delete succeeds" + end + context "to a link that does not exist" do + include_context "create symbolic link succeeds" + include_context "delete is noop" + end + end end context "to a file that does not exist" do before(:each) do @@ -418,6 +502,19 @@ describe Chef::Resource::Link do include_context "create symbolic link succeeds" include_context "delete is noop" end + context "and the destination itself has another symbolic link" do + context "to a link that exist" do + before do + symlink(to, target_file) + end + include_context "create symbolic link is noop" + include_context "delete succeeds" + end + context "to a link that does not exist" do + include_context "create symbolic link succeeds" + include_context "delete is noop" + end + end end end context "when the link destination does not exist" do @@ -559,7 +656,7 @@ describe Chef::Resource::Link do end context "and the link does not yet exist" do it "links to the target file" do - skip("OS X/FreeBSD/AIX symlink? and readlink working on hard links to symlinks") if os_x? || freebsd? || aix? + skip("OS X/FreeBSD/AIX/Solaris symlink? and readlink working on hard links to symlinks") if os_x? || freebsd? || aix? || solaris? resource.run_action(:create) expect(File.exists?(target_file)).to be_truthy # OS X gets angry about this sort of link. Bug in OS X, IMO. @@ -578,14 +675,9 @@ describe Chef::Resource::Link do end context "and the link does not yet exist" do it "links to the target file" do - skip("OS X/FreeBSD/AIX fails to create hardlinks to broken symlinks") if os_x? || freebsd? || aix? + skip("OS X/FreeBSD/AIX/Solaris fails to create hardlinks to broken symlinks") if os_x? || freebsd? || aix? || solaris? resource.run_action(:create) - # Windows and Unix have different definitions of exists? here, and that's OK. - if windows? - expect(File.exists?(target_file)).to be_truthy - else - expect(File.exists?(target_file)).to be_falsey - end + expect(File.exists?(target_file) || File.symlink?(target_file)).to be_truthy expect(symlink?(target_file)).to be_truthy expect(readlink(target_file)).to eq(canonicalize(@other_target)) end @@ -604,10 +696,4 @@ describe Chef::Resource::Link do end end end - - describe "when not supported on platform", :win2k3_only do - it "raises error" do - expect { resource }.to raise_error(Chef::Exceptions::Win32APIFunctionNotImplemented) - end - end end |