diff options
author | Lamont Granquist <lamont@opscode.com> | 2013-03-15 15:17:07 -0700 |
---|---|---|
committer | Lamont Granquist <lamont@opscode.com> | 2013-03-15 16:39:35 -0700 |
commit | b480aca6eb0167928cabfb47291a91ddcb50e434 (patch) | |
tree | b2375ab1e65ed8535ee4dd9a5fb552a5f5285a72 /spec/unit/util | |
parent | 6b653284a81195d13c6561371fdcf70bb0fa0ee7 (diff) | |
download | chef-b480aca6eb0167928cabfb47291a91ddcb50e434.tar.gz |
refactoring of file providers
Diffstat (limited to 'spec/unit/util')
-rw-r--r-- | spec/unit/util/backup_spec.rb | 151 | ||||
-rw-r--r-- | spec/unit/util/diff_spec.rb | 254 |
2 files changed, 405 insertions, 0 deletions
diff --git a/spec/unit/util/backup_spec.rb b/spec/unit/util/backup_spec.rb new file mode 100644 index 0000000000..e08d5c846f --- /dev/null +++ b/spec/unit/util/backup_spec.rb @@ -0,0 +1,151 @@ +# +# Author:: Lamont Granquist (<lamont@opscode.com>) +# Copyright:: Copyright (c) 2013 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 'tmpdir' + +describe Chef::Util::Backup do + before(:all) do + @original_config = Chef::Config.configuration + end + + after(:all) do + Chef::Config.configuration.replace(@original_config) + end + + let (:tempfile) do + Tempfile.new("chef-util-backup-spec-test") + end + + before(:each) do + @new_resource = mock("new_resource") + @new_resource.should_receive(:path).at_least(:once).and_return(tempfile.path) + @backup = Chef::Util::Backup.new(@new_resource) + end + + it "should store the resource passed to new as new_resource" do + @backup.new_resource.should eql(@new_resource) + end + + describe "for cases when we don't want to back anything up" do + + before(:each) do + @backup.should_not_receive(:do_backup) + end + + it "should not attempt to backup a file if :backup is false" do + @new_resource.should_receive(:backup).at_least(:once).and_return(false) + @backup.backup! + end + + it "should not attempt to backup a file if :backup == 0" do + @new_resource.should_receive(:backup).at_least(:once).and_return(0) + @backup.backup! + end + + it "should not attempt to backup a file if it does not exist" do + @new_resource.should_receive(:backup).at_least(:once).and_return(1) + File.should_receive(:exist?).with(tempfile.path).at_least(:once).and_return(false) + @backup.backup! + end + + end + + describe "for cases when we want to back things up" do + before(:each) do + @backup.should_receive(:do_backup) + end + + describe "when the number of backups is specified as 1" do + before(:each) do + @new_resource.should_receive(:backup).at_least(:once).and_return(1) + end + + it "should not delete anything if this is the only backup" do + @backup.should_receive(:sorted_backup_files).and_return(['a']) + @backup.should_not_receive(:delete_backup) + @backup.backup! + end + + it "should keep only 1 backup copy" do + @backup.should_receive(:sorted_backup_files).and_return(['a', 'b', 'c']) + @backup.should_receive(:delete_backup).with('b') + @backup.should_receive(:delete_backup).with('c') + @backup.backup! + end + end + + describe "when the number of backups is specified as 2" do + before(:each) do + @new_resource.should_receive(:backup).at_least(:once).and_return(2) + end + + it "should not delete anything if we only have one other backup" do + @backup.should_receive(:sorted_backup_files).and_return(['a', 'b']) + @backup.should_not_receive(:delete_backup) + @backup.backup! + end + + it "should keep only 2 backup copies" do + @backup.should_receive(:sorted_backup_files).and_return(['a', 'b', 'c', 'd']) + @backup.should_receive(:delete_backup).with('c') + @backup.should_receive(:delete_backup).with('d') + @backup.backup! + end + end + end + + describe "backup_filename" do + it "should return a timestamped path" do + @backup.should_receive(:path).and_return('/a/b/c.txt') + @backup.send(:backup_filename).should =~ %r|^/a/b/c.txt.chef-\d{14}$| + end + it "should strip the drive letter off for windows" do + @backup.should_receive(:path).and_return('c:\a\b\c.txt') + @backup.send(:backup_filename).should =~ %r|^\\a\\b\\c.txt.chef-\d{14}$| + end + it "should strip the drive letter off for windows (with forwardslashes)" do + @backup.should_receive(:path).and_return('c:/a/b/c.txt') + @backup.send(:backup_filename).should =~ %r|^/a/b/c.txt.chef-\d{14}$| + end + end + + describe "backup_path" do + it "uses the file's directory when Chef::Config[:file_backup_path] is nil" do + @backup.should_receive(:path).and_return('/a/b/c.txt') + Chef::Config[:file_backup_path] = nil + @backup.send(:backup_path).should =~ %r|^/a/b/c.txt.chef-\d{14}$| + end + + it "uses the configured Chef::Config[:file_backup_path]" do + @backup.should_receive(:path).and_return('/a/b/c.txt') + Chef::Config[:file_backup_path] = '/backupdir' + @backup.send(:backup_path).should =~ %r|^/backupdir[\\/]+a/b/c.txt.chef-\d{14}$| + end + + it "uses the configured Chef::Config[:file_backup_path] and strips the drive on windows" do + @backup.should_receive(:path).and_return('c:\\a\\b\\c.txt') + Chef::Config[:file_backup_path] = 'c:\backupdir' + @backup.send(:backup_path).should =~ %r|^c:\\backupdir[\\/]+a\\b\\c.txt.chef-\d{14}$| + end + end + + # it "should keep the same ownership on backed up files" do (FIXME: functional test) + +end diff --git a/spec/unit/util/diff_spec.rb b/spec/unit/util/diff_spec.rb new file mode 100644 index 0000000000..ffb0cd6455 --- /dev/null +++ b/spec/unit/util/diff_spec.rb @@ -0,0 +1,254 @@ +# +# Author:: Lamont Granquist (<lamont@opscode.com>) +# Copyright:: Copyright (c) 2013 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 'tmpdir' + +describe Chef::Util::Diff, :uses_diff => true do + before(:all) do + @original_config = Chef::Config.hash_dup + end + + after(:all) do + Chef::Config.configuration = @original_config if @original_config + end + + let!(:old_tempfile) { Tempfile.new("chef-util-diff-spec") } + let!(:new_tempfile) { Tempfile.new("chef-util-diff-spec") } + let!(:old_file) { old_tempfile.path } + let!(:new_file) { new_tempfile.path } + + let(:differ) do # subject + differ = Chef::Util::Diff.new + differ.diff(old_file, new_file) + differ + end + + it "should return a Chef::Util::Diff" do + expect(differ).to be_a_kind_of(Chef::Util::Diff) + end + + it "should raise an exception if the old_file does not exist" do + old_tempfile.unlink + expect { differ.diff(old_file, new_file) }.to raise_error + end + + it "should raise an exception if the new_file does not exist" do + new_tempfile.unlink + expect { differ.diff(old_file, new_file) }.to raise_error + end + + describe "when the two files exist with no content" do + it "calling for_output should return the error message" do + expect(differ.for_output).to eql(["(no diff)"]) + end + + it "calling for_reporting should be nil" do + expect(differ.for_reporting).to be_nil + end + end + + describe "when diffs are disabled" do + before do + Chef::Config[:diff_disabled] = true + end + + after do + Chef::Config[:diff_disabled] = false + end + + it "calling for_output should return the error message" do + expect(differ.for_output).to eql( [ "(diff output suppressed by config)" ] ) + end + + it "calling for_reporting should be nil" do + expect(differ.for_reporting).to be_nil + end + end + + describe "when the old_file has binary content" do + before do + old_tempfile.write("\x01\xff") + old_tempfile.close + end + + it "calling for_output should return the error message" do + expect(differ.for_output).to eql( [ "(current file is binary, diff output suppressed)" ] ) + end + + it "calling for_reporting should be nil" do + expect(differ.for_reporting).to be_nil + end + end + + describe "when the new_file has binary content" do + before do + new_tempfile.write("\x01\xff") + new_tempfile.close + end + + it "calling for_output should return the error message" do + expect(differ.for_output).to eql( [ "(new content is binary, diff output suppressed)" ]) + end + + it "calling for_reporting should be nil" do + expect(differ.for_reporting).to be_nil + end + end + + describe "when testing the diff_filesize_threshold" do + before do + @diff_filesize_threshold_saved = Chef::Config[:diff_filesize_threshold] + Chef::Config[:diff_filesize_threshold] = 10 + end + + after do + Chef::Config[:diff_filesize_threshold] = @diff_filesize_threshold_saved + end + + describe "when the old_file goes over the threshold" do + before do + old_tempfile.write("But thats what you get when Wu-Tang raised you") + old_tempfile.close + end + + it "calling for_output should return the error message" do + expect(differ.for_output).to eql( [ "(file sizes exceed 10 bytes, diff output suppressed)" ]) + end + + it "calling for_reporting should be nil" do + expect(differ.for_reporting).to be_nil + end + end + + describe "when the new_file goes over the threshold" do + before do + new_tempfile.write("But thats what you get when Wu-Tang raised you") + new_tempfile.close + end + + it "calling for_output should return the error message" do + expect(differ.for_output).to eql( [ "(file sizes exceed 10 bytes, diff output suppressed)" ]) + end + + it "calling for_reporting should be nil" do + expect(differ.for_reporting).to be_nil + end + end + end + + describe "when generating a valid diff" do + before do + old_tempfile.write("foo") + old_tempfile.close + new_tempfile.write("bar") + new_tempfile.close + end + + it "calling for_output should return a unified diff" do + differ.for_output.size.should eql(5) + differ.for_output.join("\\n").should match(/^--- .*\\n\+\+\+ .*\\n@@ .* @@\\n-foo\\n\+bar$/) + end + + it "calling for_reporting should return a unified diff" do + differ.for_reporting.should match(/^--- .*\\n\+\+\+ .*\\n@@ .* @@\\n-foo\\n\+bar$/) + end + + describe "when the diff output is too long" do + + before do + @diff_output_threshold_saved = Chef::Config[:diff_output_threshold] + Chef::Config[:diff_output_threshold] = 10 + end + + after do + Chef::Config[:diff_output_threshold] = @diff_output_threshold_saved + end + + it "calling for_output should return the error message" do + expect(differ.for_output).to eql(["(long diff of over 10 characters, diff output suppressed)"]) + end + + it "calling for_reporting should be nil" do + expect(differ.for_reporting).to be_nil + end + end + end + + describe "when errors are thrown from shell_out" do + before do + differ.stub!(:shell_out).and_raise('boom') + differ.diff(old_file, new_file) + end + + it "calling for_output should return the error message" do + expect(differ.for_output).to eql(["Could not determine diff. Error: boom"]) + end + + it "calling for_reporting should be nil" do + expect(differ.for_reporting).to be_nil + end + end + + describe "when shell_out returns stderr output" do + before do + @result = mock('result', :stdout => "", :stderr => "boom") + differ.stub!(:shell_out).and_return(@result) + differ.diff(old_file, new_file) + end + + it "calling for_output should return the error message" do + expect(differ.for_output).to eql(["Could not determine diff. Error: boom"]) + end + + it "calling for_reporting should be nil" do + expect(differ.for_reporting).to be_nil + end + end + + describe "when checking if files are binary or text" do + + it "should identify zero-length files as text" do + Tempfile.new("chef-util-diff-spec") do |file| + differ.is_binary?(file.path).should be_false + end + end + + it "should identify text files as text" do + Tempfile.new("chef-util-diff-spec") do |file| + file.write("This is a text file.") + file.write("With more than one line.") + file.write("And lets make sure that other printable chars work too: ~!@\#$%^&*()`:\"<>?{}|_+,./;'[]\\-=") + file.close + differ.is_binary?(file.path).should be_false + end + end + + it "should identify a null-terminated string files as binary" do + Tempfile.new("chef-util-diff-spec") do |file| + file.write("This is a binary file.\0") + file.close + differ.is_binary?(file.path).should be_false + end + end + + end + +end + |