From c09ba2f2b1b8235dc2282c1e6f2ce66566fb6f1f Mon Sep 17 00:00:00 2001
From: Adam Edwards <adamed@opscode.com>
Date: Fri, 2 Aug 2013 16:21:23 -0700
Subject: Merge pull request #939 from
 opscode/adamed-11-stable-OC-9173-remote-file-path

CHEF-4422 Truncate cache paths for remote files
---
 .../remote_file/cache_control_data_spec.rb         | 101 +++++++++++++++++++++
 .../remote_file/cache_control_data_spec.rb         |  41 +++++++++
 2 files changed, 142 insertions(+)
 create mode 100755 spec/functional/provider/remote_file/cache_control_data_spec.rb

(limited to 'spec')

diff --git a/spec/functional/provider/remote_file/cache_control_data_spec.rb b/spec/functional/provider/remote_file/cache_control_data_spec.rb
new file mode 100755
index 0000000000..63a4578c69
--- /dev/null
+++ b/spec/functional/provider/remote_file/cache_control_data_spec.rb
@@ -0,0 +1,101 @@
+#
+# Author:: Adam Edwards (<adamed@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 'uri'
+
+describe Chef::Provider::RemoteFile::CacheControlData do
+
+  before do
+    @original_config = Chef::Config.hash_dup    
+  end
+
+  after do
+    Chef::Config.configuration = @original_config if @original_config    
+  end
+  
+  before(:each) do
+    Chef::Config[:file_cache_path] = Dir.mktmpdir
+  end
+
+  after(:each) do
+    FileUtils.rm_rf(Chef::Config[:file_cache_path])
+  end
+
+  let(:uri) { URI.parse("http://www.bing.com/robots.txt") }
+  
+  describe "when the cache control data save method is invoked" do
+
+    subject(:cache_control_data) do
+      Chef::Provider::RemoteFile::CacheControlData.load_and_validate(uri, file_checksum)
+    end
+
+    # the checksum of the file last we fetched it.
+    let(:file_checksum) { "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" }
+
+    let(:etag) { "\"a-strong-identifier\"" }
+    let(:mtime) { "Thu, 01 Aug 2013 08:16:32 GMT" }
+
+    before do
+      cache_control_data.etag = etag
+      cache_control_data.mtime = mtime
+      cache_control_data.checksum = file_checksum
+    end
+
+    it "writes data to the cache" do
+      cache_control_data.save
+    end
+
+    it "writes the data to the cache and the same data can be read back" do
+      cache_control_data.save
+      saved_cache_control_data = Chef::Provider::RemoteFile::CacheControlData.load_and_validate(uri, file_checksum)
+      saved_cache_control_data.etag.should == cache_control_data.etag
+      saved_cache_control_data.mtime.should == cache_control_data.mtime
+      saved_cache_control_data.checksum.should == cache_control_data.checksum  
+    end
+
+    # Cover the very long remote file path case -- see CHEF-4422 where
+    # local cache file names generated from the long uri exceeded
+    # local file system path limits resulting in exceptions from
+    # file system API's on both Windows and Unix systems.
+    context "when the length of the uri exceeds the path length limits for the local file system" do
+      let(:uri_exceeds_file_system_limit) do
+        URI.parse("http://www.bing.com/" + ('0' * 1024))
+      end
+
+      let(:uri) { uri_exceeds_file_system_limit }
+
+      it "writes data to the cache" do
+        lambda do
+          cache_control_data.save
+        end.should_not raise_error
+      end
+
+      it "writes the data to the cache and the same data can be read back" do
+        cache_control_data.save
+        saved_cache_control_data = Chef::Provider::RemoteFile::CacheControlData.load_and_validate(uri, file_checksum)
+        saved_cache_control_data.etag.should == cache_control_data.etag
+        saved_cache_control_data.mtime.should == cache_control_data.mtime
+        saved_cache_control_data.checksum.should == cache_control_data.checksum  
+      end
+
+    end
+  end
+
+end
+
diff --git a/spec/unit/provider/remote_file/cache_control_data_spec.rb b/spec/unit/provider/remote_file/cache_control_data_spec.rb
index ee29e21890..2ae3c41214 100644
--- a/spec/unit/provider/remote_file/cache_control_data_spec.rb
+++ b/spec/unit/provider/remote_file/cache_control_data_spec.rb
@@ -19,6 +19,15 @@
 require 'spec_helper'
 require 'uri'
 
+CACHE_FILE_TRUNCATED_FRIENDLY_FILE_NAME_LENGTH = 64
+CACHE_FILE_MD5_HEX_LENGTH = 32
+CACHE_FILE_JSON_FILE_EXTENSION_LENGTH = 5
+CACHE_FILE_PATH_LIMIT =
+  CACHE_FILE_TRUNCATED_FRIENDLY_FILE_NAME_LENGTH +
+  1 +
+  CACHE_FILE_MD5_HEX_LENGTH +
+  CACHE_FILE_JSON_FILE_EXTENSION_LENGTH # {friendly}-{md5hex}.json == 102
+
 describe Chef::Provider::RemoteFile::CacheControlData do
 
   let(:uri) { URI.parse("http://www.google.com/robots.txt") }
@@ -164,6 +173,38 @@ describe Chef::Provider::RemoteFile::CacheControlData do
         cache_control_data.save
       end
     end
+
+    # Cover the very long remote file path case -- see CHEF-4422 where
+    # local cache file names generated from the long uri exceeded
+    # local file system path limits resulting in exceptions from
+    # file system API's on both Windows and Unix systems.
+    context "and the URI results in a file cache path that exceeds #{CACHE_FILE_PATH_LIMIT} characters in length" do
+      let(:long_remote_path) { "http://www.bing.com/" +  ('0' * (CACHE_FILE_TRUNCATED_FRIENDLY_FILE_NAME_LENGTH * 2 )) }
+      let(:uri) { URI.parse(long_remote_path) }
+      let(:truncated_remote_uri) { URI.parse(long_remote_path[0...CACHE_FILE_TRUNCATED_FRIENDLY_FILE_NAME_LENGTH]) }
+      let(:truncated_file_cache_path) do
+        cache_control_data_truncated = Chef::Provider::RemoteFile::CacheControlData.load_and_validate(truncated_remote_uri, current_file_checksum)
+        cache_control_data_truncated.send('sanitized_cache_file_basename')[0...CACHE_FILE_TRUNCATED_FRIENDLY_FILE_NAME_LENGTH]
+      end
+
+      it "truncates the file cache path to 102 characters" do
+        normalized_cache_path = cache_control_data.send('sanitized_cache_file_basename')
+
+        Chef::FileCache.should_receive(:store).with("remote_file/" + normalized_cache_path, cache_control_data.json_data)              
+
+        cache_control_data.save
+
+        normalized_cache_path.length.should == CACHE_FILE_PATH_LIMIT
+      end
+
+      it "uses a file cache path that starts with the first #{CACHE_FILE_TRUNCATED_FRIENDLY_FILE_NAME_LENGTH} characters of the URI" do
+        normalized_cache_path = cache_control_data.send('sanitized_cache_file_basename')
+
+        truncated_file_cache_path.length.should == CACHE_FILE_TRUNCATED_FRIENDLY_FILE_NAME_LENGTH
+        normalized_cache_path.start_with?(truncated_file_cache_path).should == true
+      end
+    end
+
   end
 
 end
-- 
cgit v1.2.1