summaryrefslogtreecommitdiff
path: root/spec/unit/provider/remote_file_spec.rb
diff options
context:
space:
mode:
Diffstat (limited to 'spec/unit/provider/remote_file_spec.rb')
-rw-r--r--spec/unit/provider/remote_file_spec.rb324
1 files changed, 324 insertions, 0 deletions
diff --git a/spec/unit/provider/remote_file_spec.rb b/spec/unit/provider/remote_file_spec.rb
new file mode 100644
index 0000000000..78d7e77121
--- /dev/null
+++ b/spec/unit/provider/remote_file_spec.rb
@@ -0,0 +1,324 @@
+#
+# Author:: Adam Jacob (<adam@opscode.com>)
+# Copyright:: Copyright (c) 2008 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'
+
+describe Chef::Provider::RemoteFile, "action_create" do
+ before(:each) do
+ @resource = Chef::Resource::RemoteFile.new("seattle")
+ @resource.path(File.expand_path(File.join(CHEF_SPEC_DATA, "seattle.txt")))
+ @resource.source("http://foo")
+ @node = Chef::Node.new
+ @node.name "latte"
+
+ @events = Chef::EventDispatch::Dispatcher.new
+ @run_context = Chef::RunContext.new(@node, {}, @events)
+
+ @provider = Chef::Provider::RemoteFile.new(@resource, @run_context)
+ #To prevent the current_resource.checksum from being overridden.
+ @provider.stub!(:load_current_resource)
+ end
+
+ describe "when checking if the file is at the target version" do
+ it "considers the current file to be at the target version if it exists and matches the user-provided checksum" do
+ @provider.current_resource = @resource.dup
+ @resource.checksum("0fd012fdc96e96f8f7cf2046522a54aed0ce470224513e45da6bc1a17a4924aa")
+ @provider.current_resource.checksum("0fd012fdc96e96f8f7cf2046522a54aed0ce470224513e45da6bc1a17a4924aa")
+ @provider.current_resource_matches_target_checksum?.should be_true
+ end
+ end
+
+ describe "when fetching the file from the remote" do
+ before(:each) do
+ @tempfile = Tempfile.new("chef-rspec-remote_file_spec-line#{__LINE__}--")
+
+ @rest = mock(Chef::REST, { })
+ Chef::REST.stub!(:new).and_return(@rest)
+ @rest.stub!(:streaming_request).and_return(@tempfile)
+ @rest.stub!(:create_url) { |url| url }
+ @resource.cookbook_name = "monkey"
+
+ @provider.stub!(:checksum).and_return("0fd012fdc96e96f8f7cf2046522a54aed0ce470224513e45da6bc1a17a4924aa")
+ @provider.current_resource = @resource.clone
+ @provider.current_resource.checksum("0fd012fdc96e96f8f7cf2046522a54aed0ce470224513e45da6bc1a17a4924aa")
+ File.stub!(:exists?).and_return(true)
+ FileUtils.stub!(:cp).and_return(true)
+ Chef::Platform.stub!(:find_platform_and_version).and_return([ :mac_os_x, "10.5.1" ])
+ end
+
+ after do
+ @tempfile.close!
+ end
+
+ before do
+ @resource.source("http://opscode.com/seattle.txt")
+ end
+
+ describe "and the target location's enclosing directory does not exist" do
+ before do
+ @resource.path("/tmp/this/path/does/not/exist/file.txt")
+ end
+
+ it "raises a specific error describing the problem" do
+ lambda {@provider.run_action(:create)}.should raise_error(Chef::Exceptions::EnclosingDirectoryDoesNotExist)
+ end
+ end
+
+ shared_examples_for "source specified with multiple URIs" do
+ it "should try to download the next URI when the first one fails" do
+ @rest.should_receive(:streaming_request).with("http://foo", {}).once.and_raise(SocketError)
+ @rest.should_receive(:streaming_request).with("http://bar", {}).once.and_return(@tempfile)
+ @provider.run_action(:create)
+ end
+
+ it "should raise an exception when all the URIs fail" do
+ @rest.should_receive(:streaming_request).with("http://foo", {}).once.and_raise(SocketError)
+ @rest.should_receive(:streaming_request).with("http://bar", {}).once.and_raise(SocketError)
+ lambda { @provider.run_action(:create) }.should raise_error(SocketError)
+ end
+
+ it "should download from only one URI when the first one works" do
+ @rest.should_receive(:streaming_request).once.and_return(@tempfile)
+ @provider.run_action(:create)
+ end
+
+ end
+
+ describe "and the source specifies multiple URIs using multiple arguments" do
+ it_should_behave_like "source specified with multiple URIs"
+
+ before(:each) do
+ @resource.source("http://foo", "http://bar")
+ end
+ end
+
+ describe "and the source specifies multiple URIs using an array" do
+ it_should_behave_like "source specified with multiple URIs"
+
+ before(:each) do
+ @resource.source([ "http://foo", "http://bar" ])
+ end
+ end
+
+ describe "and the resource specifies a checksum" do
+
+ describe "and the existing file matches the checksum exactly" do
+ before do
+ @resource.checksum("0fd012fdc96e96f8f7cf2046522a54aed0ce470224513e45da6bc1a17a4924aa")
+ end
+
+ it "does not download the file" do
+ @rest.should_not_receive(:fetch).with("http://opscode.com/seattle.txt").and_return(@tempfile)
+ @provider.run_action(:create)
+ end
+
+ it "does not update the resource" do
+ @provider.run_action(:create)
+ @provider.new_resource.should_not be_updated
+ end
+
+ end
+
+ describe "and the existing file matches the given partial checksum" do
+ before do
+ @resource.checksum("0fd012fd")
+ end
+
+ it "should not download the file if the checksum is a partial match from the beginning" do
+ @rest.should_not_receive(:fetch).with("http://opscode.com/seattle.txt").and_return(@tempfile)
+ @provider.run_action(:create)
+ end
+
+ it "does not update the resource" do
+ @provider.run_action(:create)
+ @provider.new_resource.should_not be_updated
+ end
+
+ end
+
+ describe "and the existing file doesn't match the given checksum" do
+ it "downloads the file" do
+ @resource.checksum("this hash doesn't match")
+ @rest.should_receive(:streaming_request).with("http://opscode.com/seattle.txt", {}).and_return(@tempfile)
+ @provider.stub!(:update_new_file_state)
+ @provider.run_action(:create)
+ end
+
+ it "does not consider the checksum a match if the matching string is offset" do
+ # i.e., the existing file is "0fd012fdc96e96f8f7cf2046522a54aed0ce470224513e45da6bc1a17a4924aa"
+ @resource.checksum("fd012fd")
+ @rest.should_receive(:streaming_request).with("http://opscode.com/seattle.txt", {}).and_return(@tempfile)
+ @provider.stub!(:update_new_file_state)
+ @provider.run_action(:create)
+ end
+ end
+
+ end
+
+ describe "and the resource doesn't specify a checksum" do
+ it "should download the file from the remote URL" do
+ @resource.checksum(nil)
+ @rest.should_receive(:streaming_request).with("http://opscode.com/seattle.txt", {}).and_return(@tempfile)
+ @provider.run_action(:create)
+ end
+ end
+
+ # CHEF-3140
+ # Some servers return tarballs as content type tar and encoding gzip, which
+ # is totally wrong. When this happens and gzip isn't disabled, Chef::REST
+ # will decompress the file for you, which is not at all what you expected
+ # to happen (you end up with an uncomressed tar archive instead of the
+ # gzipped tar archive you expected). To work around this behavior, we
+ # detect when users are fetching gzipped files and turn off gzip in
+ # Chef::REST.
+
+ context "and the target file is a tarball" do
+ before do
+ @resource.path(File.expand_path(File.join(CHEF_SPEC_DATA, "seattle.tar.gz")))
+ Chef::REST.should_receive(:new).with("http://opscode.com/seattle.txt", nil, nil, :disable_gzip => true).and_return(@rest)
+ end
+
+ it "disables gzip in the http client" do
+ @provider.action_create
+ end
+
+ end
+
+ context "and the source appears to be a tarball" do
+ before do
+ @resource.source("http://example.com/tarball.tgz")
+ Chef::REST.should_receive(:new).with("http://example.com/tarball.tgz", nil, nil, :disable_gzip => true).and_return(@rest)
+ end
+
+ it "disables gzip in the http client" do
+ @provider.action_create
+ end
+ end
+
+ it "should raise an exception if it's any other kind of retriable response than 304" do
+ r = Net::HTTPMovedPermanently.new("one", "two", "three")
+ e = Net::HTTPRetriableError.new("301", r)
+ @rest.stub!(:streaming_request).and_raise(e)
+ lambda { @provider.run_action(:create) }.should raise_error(Net::HTTPRetriableError)
+ end
+
+ it "should raise an exception if anything else happens" do
+ r = Net::HTTPBadRequest.new("one", "two", "three")
+ e = Net::HTTPServerException.new("fake exception", r)
+ @rest.stub!(:streaming_request).and_raise(e)
+ lambda { @provider.run_action(:create) }.should raise_error(Net::HTTPServerException)
+ end
+
+ it "should checksum the raw file" do
+ @provider.should_receive(:checksum).with(@tempfile.path).and_return("0fd012fdc96e96f8f7cf2046522a54aed0ce470224513e45da6bc1a17a4924aa")
+ @provider.run_action(:create)
+ end
+
+ describe "when the target file does not exist" do
+ before do
+ ::File.stub!(:exists?).with(@resource.path).and_return(false)
+ @provider.stub!(:get_from_server).and_return(@tempfile)
+ end
+
+ it "should copy the raw file to the new resource" do
+ FileUtils.should_receive(:cp).with(@tempfile.path, @resource.path).and_return(true)
+ @provider.stub!(:update_new_file_state)
+ @provider.run_action(:create)
+ end
+
+ it "should set the new resource to updated" do
+ @provider.stub!(:update_new_file_state)
+ @provider.run_action(:create)
+ @resource.should be_updated
+ end
+
+ describe "and create_if_missing is invoked" do
+ it "should invoke action_create" do
+ @provider.should_receive(:action_create)
+ @provider.run_action(:create_if_missing)
+ end
+ end
+ end
+
+ describe "when the target file already exists" do
+ before do
+ ::File.stub!(:exists?).with(@resource.path).and_return(true)
+ @provider.stub!(:diff_current).and_return([
+ "--- /tmp/foo 2012-08-30 21:28:17.632782551 +0000",
+ "+++ /tmp/bar 2012-08-30 21:28:20.816975437 +0000",
+ "@@ -1 +1 @@",
+ "-foo bar",
+ "+bar foo"
+ ])
+ @provider.stub!(:get_from_server).and_return(@tempfile)
+ end
+
+ describe "and create_if_missing is invoked" do
+ it "should take no action" do
+ @provider.should_not_receive(:action_create)
+ @provider.run_action(:create_if_missing)
+ end
+ end
+
+ describe "and the file downloaded from the remote is identical to the current" do
+ it "shouldn't backup the original file" do
+ @provider.should_not_receive(:backup).with(@resource.path)
+ @provider.run_action(:create)
+ end
+
+ it "doesn't mark the resource as updated" do
+ @provider.run_action(:create)
+ @provider.new_resource.should_not be_updated
+ end
+ end
+
+ describe "and the checksum doesn't match" do
+ before do
+ sha2_256 = "0fd012fdc96e96f8f7cf2046522a54aed0ce470224513e45da6bc1a17a4924aa-NO_MATCHY"
+ @provider.current_resource.checksum(sha2_256)
+ end
+
+ it "should backup the original file" do
+ @provider.stub!(:update_new_file_state)
+ @provider.should_receive(:backup).with(@resource.path).and_return(true)
+ @provider.run_action(:create)
+ end
+
+ it "should copy the raw file to the new resource" do
+ @provider.stub!(:update_new_file_state)
+ FileUtils.should_receive(:cp).with(@tempfile.path, @resource.path).and_return(true)
+ @provider.run_action(:create)
+ end
+
+ it "should set the new resource to updated" do
+ @provider.stub!(:update_new_file_state)
+ @provider.run_action(:create)
+ @resource.should be_updated
+ end
+ end
+
+ it "should set permissions" do
+ @provider.should_receive(:set_all_access_controls).and_return(true)
+ @provider.run_action(:create)
+ end
+
+
+ end
+
+ end
+end