diff options
-rw-r--r-- | spec/functional/resource/remote_file_spec.rb | 194 |
1 files changed, 192 insertions, 2 deletions
diff --git a/spec/functional/resource/remote_file_spec.rb b/spec/functional/resource/remote_file_spec.rb index bfc09dccd9..4468951a7a 100644 --- a/spec/functional/resource/remote_file_spec.rb +++ b/spec/functional/resource/remote_file_spec.rb @@ -53,20 +53,99 @@ describe Chef::Resource::RemoteFile do let(:default_mode) { ((0100666 - File.umask) & 07777).to_s(8) } def start_tiny_server(server_opts={}) + nyan_uncompressed_filename = File.join(CHEF_SPEC_DATA, 'remote_file', 'nyan_cat.png') + nyan_compressed_filename = File.join(CHEF_SPEC_DATA, 'remote_file', 'nyan_cat.png.gz') + nyan_uncompressed_size = File::Stat.new(nyan_uncompressed_filename).size + nyan_compressed_size = File::Stat.new(nyan_compressed_filename).size + @server = TinyServer::Manager.new(server_opts) @server.start @api = TinyServer::API.instance @api.clear + + # + # trivial endpoints + # + @api.get("/nyan_cat.png", 200) { - File.open(File.join(CHEF_SPEC_DATA, 'remote_file', 'nyan_cat.png'), "rb") do |f| + File.open(nyan_uncompressed_filename, "rb") do |f| f.read end } @api.get("/nyan_cat.png.gz", 200, nil, { 'Content-Type' => 'application/gzip', 'Content-Encoding' => 'gzip' } ) { - File.open(File.join(CHEF_SPEC_DATA, 'remote_file', 'nyan_cat.png.gz'), "rb") do |f| + File.open(nyan_compressed_filename, "rb") do |f| + f.read + end + } + + # + # endpoints that set Content-Length correctly + # + + @api.get("/nyan_cat_content_length.png", 200, nil, + { + 'Content-Length' => nyan_uncompressed_size.to_s, + } + ) { + File.open(nyan_uncompressed_filename, "rb") do |f| + f.read + end + } + + # this is sent over the wire compressed by the server, but does not have a .gz extension + @api.get("/nyan_cat_content_length_compressed.png", 200, nil, + { + 'Content-Length' => nyan_compressed_size.to_s, + 'Content-Type' => 'application/gzip', + 'Content-Encoding' => 'gzip' + } + ) { + File.open(nyan_compressed_filename, "rb") do |f| f.read end } + + # + # endpoints that simulate truncated downloads (bad content-length header) + # + + @api.get("/nyan_cat_truncated.png", 200, nil, + { + 'Content-Length' => (nyan_uncompressed_size + 1).to_s, + } + ) { + File.open(nyan_uncompressed_filename, "rb") do |f| + f.read + end + } + # this is sent over the wire compressed by the server, but does not have a .gz extension + @api.get("/nyan_cat_truncated_compressed.png", 200, nil, + { + 'Content-Length' => (nyan_compressed_size + 1).to_s, + 'Content-Type' => 'application/gzip', + 'Content-Encoding' => 'gzip' + } + ) { + File.open(nyan_compressed_filename, "rb") do |f| + f.read + end + } + + # + # in the presense of a transfer-encoding header, we must ignore the content-length (this bad content-length should work) + # + + @api.get("/nyan_cat_transfer_encoding.png", 200, nil, + { + 'Content-Length' => (nyan_uncompressed_size + 1).to_s, + 'Transfer-Encoding' => 'anything', + } + ) { + File.open(nyan_uncompressed_filename, "rb") do |f| + f.read + end + } + end def stop_tiny_server @@ -162,4 +241,115 @@ describe Chef::Resource::RemoteFile do end + context "when dealing with content length checking" do + + def binread(file) + content = File.open(file, "rb") do |f| + f.read + end + content.force_encoding(Encoding::BINARY) if "".respond_to?(:force_encoding) + content + end + + before(:all) do + start_tiny_server + end + + after(:all) do + stop_tiny_server + end + + context "when downloading compressed data" do + let(:expected_content) { binread( File.join(CHEF_SPEC_DATA, 'remote_file', 'nyan_cat.png') ) } + let(:source) { 'http://localhost:9000/nyan_cat_content_length_compressed.png' } + + before do + File.should_not exist(path) + resource.run_action(:create) + end + + it "should create the file" do + File.should exist(path) + end + + it "should mark the resource as updated" do + resource.should be_updated_by_last_action + end + + it "has the correct content" do + binread(path).should == expected_content + end + end + + context "when downloding uncompressed data" do + let(:expected_content) { binread( File.join(CHEF_SPEC_DATA, 'remote_file', 'nyan_cat.png') ) } + let(:source) { 'http://localhost:9000/nyan_cat_content_length.png' } + + before do + File.should_not exist(path) + resource.run_action(:create) + end + + it "should create the file" do + File.should exist(path) + end + + it "should mark the resource as updated" do + resource.should be_updated_by_last_action + end + + it "has the correct content" do + binread(path).should == expected_content + end + end + + context "when downloading truncated compressed data" do + let(:source) { 'http://localhost:9000/nyan_cat_truncated_compressed.png' } + + before do + File.should_not exist(path) + end + + it "should raise ContentLengthMismatch" do + lambda { resource.run_action(:create) }.should raise_error(Chef::Exceptions::ContentLengthMismatch) + #File.should_not exist(path) # XXX: CHEF-5081 + end + end + + context "when downloding truncated uncompressed data" do + let(:source) { 'http://localhost:9000/nyan_cat_truncated.png' } + + before do + File.should_not exist(path) + end + + it "should raise ContentLengthMismatch" do + lambda { resource.run_action(:create) }.should raise_error(Chef::Exceptions::ContentLengthMismatch) + #File.should_not exist(path) # XXX: CHEF-5081 + end + end + + context "when downloding data with transfer-encoding set" do + let(:expected_content) { binread( File.join(CHEF_SPEC_DATA, 'remote_file', 'nyan_cat.png') ) } + let(:source) { 'http://localhost:9000/nyan_cat_transfer_encoding.png' } + + before do + File.should_not exist(path) + resource.run_action(:create) + end + + it "should create the file" do + File.should exist(path) + end + + it "should mark the resource as updated" do + resource.should be_updated_by_last_action + end + + it "has the correct content" do + binread(path).should == expected_content + end + end + + end end |