diff options
author | Lamont Granquist <lamont@scriptkiddie.org> | 2014-03-20 17:04:02 -0700 |
---|---|---|
committer | sersut <serdar@opscode.com> | 2014-03-27 15:37:26 -0700 |
commit | 77b5d44143f94ad604de7d6013dd9be4f503a6e5 (patch) | |
tree | ea3c5742dbe461add803356784ab19d4f22545b7 /spec/unit/http | |
parent | 12e0d2468f09ed107d240cd49b7b3f2b0e3d5dbe (diff) | |
download | chef-77b5d44143f94ad604de7d6013dd9be4f503a6e5.tar.gz |
CHEF-5100:
- Enable Content Validation Check for Chef::HTTP::Simple
- Tidy up debug logs / comments
- More specs.
Diffstat (limited to 'spec/unit/http')
-rw-r--r-- | spec/unit/http/simple_spec.rb | 32 | ||||
-rw-r--r-- | spec/unit/http/validate_content_length_spec.rb | 187 |
2 files changed, 219 insertions, 0 deletions
diff --git a/spec/unit/http/simple_spec.rb b/spec/unit/http/simple_spec.rb new file mode 100644 index 0000000000..b33ef1d553 --- /dev/null +++ b/spec/unit/http/simple_spec.rb @@ -0,0 +1,32 @@ +# +# Author:: Serdar Sutay (<serdar@opscode.com>) +# Copyright:: Copyright (c) 2014 Chef Software, 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::HTTP::Simple do + it "should have content length validation middleware after compressor middleware" do + client = Chef::HTTP::Simple.new("dummy.com") + middlewares = client.instance_variable_get(:@middlewares) + content_length = middlewares.find_index { |e| e.is_a? Chef::HTTP::ValidateContentLength } + decompressor = middlewares.find_index { |e| e.is_a? Chef::HTTP::Decompressor } + + content_length.should_not be_nil + decompressor.should_not be_nil + (decompressor < content_length).should be_true + end +end diff --git a/spec/unit/http/validate_content_length_spec.rb b/spec/unit/http/validate_content_length_spec.rb new file mode 100644 index 0000000000..091f2b0757 --- /dev/null +++ b/spec/unit/http/validate_content_length_spec.rb @@ -0,0 +1,187 @@ +# +# Author:: Serdar Sutay (<serdar@opscode.com>) +# Copyright:: Copyright (c) 2014 Chef Software, 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 'stringio' + +describe Chef::HTTP::ValidateContentLength do + class TestClient < Chef::HTTP + use Chef::HTTP::ValidateContentLength + end + + let(:method) { "GET" } + let(:url) { "http://dummy.com" } + let(:headers) { {} } + let(:data) { false } + + let(:request) { } + let(:return_value) { "200" } + + # Test Variables + let(:request_type) { :streaming } + let(:content_length_value) { 23 } + let(:streaming_length) { 23 } + let(:response_body) { "Thanks for checking in." } + let(:response_headers) { + { + "content-length" => content_length_value + } + } + + let(:response) { + m = double('HttpResponse', :body => response_body) + m.stub(:[]) do |key| + response_headers[key] + end + + m + } + + let(:middleware) { + client = TestClient.new(url) + client.middlewares[0] + } + + def run_content_length_validation + stream_handler = middleware.stream_response_handler(response) + middleware.handle_request(method, url, headers, data) + + case request_type + when :streaming + # First stream the data + data_length = streaming_length + while data_length > 0 + chunk_size = data_length > 10 ? 10 : data_length + stream_handler.handle_chunk(double("Chunk", :bytesize => chunk_size)) + data_length -= chunk_size + end + + # Finally call stream complete + middleware.handle_stream_complete(response, request, return_value) + when :direct + middleware.handle_response(response, request, return_value) + else + raise "Unknown request_type: #{request_type}" + end + end + + let(:debug_stream) { StringIO.new } + let(:debug_output) { debug_stream.string } + + before(:each) { + Chef::Log.level = :debug + Chef::Log.stub(:debug) do |message| + debug_stream.puts message + end + } + + describe "without response body" do + let(:request_type) { :direct } + let(:response_body) { "Thanks for checking in." } + + it "shouldn't raise error" do + lambda { run_content_length_validation }.should_not raise_error + end + end + + describe "without Content-Length header" do + let(:response_headers) { { } } + + [ "direct", "streaming" ].each do |req_type| + describe "when running #{req_type} request" do + let(:request_type) { req_type.to_sym } + + it "should skip validation and log for debug" do + run_content_length_validation + debug_output.should include("HTTP server did not include a Content-Length header in response") + end + end + end + end + + describe "with correct Content-Length header" do + [ "direct", "streaming" ].each do |req_type| + describe "when running #{req_type} request" do + let(:request_type) { req_type.to_sym } + + it "should validate correctly" do + run_content_length_validation + debug_output.should include("Content-Length validated correctly.") + end + end + end + end + + describe "with wrong Content-Length header" do + let(:content_length_value) { 25 } + [ "direct", "streaming" ].each do |req_type| + describe "when running #{req_type} request" do + let(:request_type) { req_type.to_sym } + + it "should raise ContentLengthMismatch error" do + lambda { run_content_length_validation }.should raise_error(Chef::Exceptions::ContentLengthMismatch) + end + end + end + end + + describe "when download is interrupted" do + let(:streaming_length) { 12 } + + it "should raise ContentLengthMismatch error" do + lambda { run_content_length_validation }.should raise_error(Chef::Exceptions::ContentLengthMismatch) + end + end + + describe "when Transfer-Encoding & Content-Length is set" do + let(:response_headers) { + { + "content-length" => content_length_value, + "transfer-encoding" => "chunked" + } + } + + [ "direct", "streaming" ].each do |req_type| + describe "when running #{req_type} request" do + let(:request_type) { req_type.to_sym } + + it "should skip validation and log for debug" do + run_content_length_validation + debug_output.should include("Transfer-Encoding header is set, skipping Content-Length check.") + end + end + end + end + + describe "when client is being reused" do + before do + run_content_length_validation + debug_output.should include("Content-Length validated correctly.") + end + + it "should reset internal counter" do + middleware.instance_variable_get(:@content_length_counter).should be_nil + end + + it "should validate correctly second time" do + run_content_length_validation + debug_output.should include("Content-Length validated correctly.") + end + end + +end |