summaryrefslogtreecommitdiff
path: root/spec/unit/util
diff options
context:
space:
mode:
authorLamont Granquist <lamont@opscode.com>2013-03-15 15:17:07 -0700
committerLamont Granquist <lamont@opscode.com>2013-03-15 16:39:35 -0700
commitb480aca6eb0167928cabfb47291a91ddcb50e434 (patch)
treeb2375ab1e65ed8535ee4dd9a5fb552a5f5285a72 /spec/unit/util
parent6b653284a81195d13c6561371fdcf70bb0fa0ee7 (diff)
downloadchef-b480aca6eb0167928cabfb47291a91ddcb50e434.tar.gz
refactoring of file providers
Diffstat (limited to 'spec/unit/util')
-rw-r--r--spec/unit/util/backup_spec.rb151
-rw-r--r--spec/unit/util/diff_spec.rb254
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
+