summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorlamont-granquist <lamont@scriptkiddie.org>2014-04-21 15:51:04 -0700
committerlamont-granquist <lamont@scriptkiddie.org>2014-04-21 15:51:04 -0700
commit480aeb8b5cda4292411d0bc66e1f05614000acfe (patch)
tree8a7ad036246a5bb63a9b29b805df786436f3c5cc /spec
parent5e6a1ad1c477acda4d75437cd356be12ffa5989b (diff)
parent7c126d5e02e784c0f6a94e429830004ee6840260 (diff)
downloadchef-480aeb8b5cda4292411d0bc66e1f05614000acfe.tar.gz
Merge pull request #1377 from opscode/lcg/CHEF-5198-3-moar-func-tests
CHEF-5198: adding func tests for Chef::HTTP clients
Diffstat (limited to 'spec')
-rw-r--r--spec/functional/http/simple_spec.rb59
-rw-r--r--spec/functional/resource/remote_file_spec.rb142
-rw-r--r--spec/functional/rest_spec.rb57
-rw-r--r--spec/support/shared/functional/http.rb219
4 files changed, 343 insertions, 134 deletions
diff --git a/spec/functional/http/simple_spec.rb b/spec/functional/http/simple_spec.rb
new file mode 100644
index 0000000000..2df40b6272
--- /dev/null
+++ b/spec/functional/http/simple_spec.rb
@@ -0,0 +1,59 @@
+#
+# Author:: Lamont Granquist (<lamont@getchef.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 'tiny_server'
+require 'support/shared/functional/http'
+
+describe Chef::HTTP::Simple do
+ include ChefHTTPShared
+
+ let(:http_client) { described_class.new(source) }
+ let(:http_client_disable_gzip) { described_class.new(source, { :disable_gzip => true } ) }
+
+ before(:all) do
+ start_tiny_server
+ end
+
+ after(:all) do
+ stop_tiny_server
+ end
+
+ shared_examples_for "downloads requests correctly" do
+ it "successfully downloads a streaming request" do
+ tempfile = http_client.streaming_request(source, {})
+ tempfile.close
+ Digest::MD5.hexdigest(binread(tempfile.path)).should == Digest::MD5.hexdigest(expected_content)
+ end
+ it "successfully does a non-streaming GET request" do
+ Digest::MD5.hexdigest(http_client.get(source)).should == Digest::MD5.hexdigest(expected_content)
+ end
+ end
+
+ shared_examples_for "validates content length and throws an exception" do
+ it "successfully downloads a streaming request" do
+ expect { http_client.streaming_request(source) }.to raise_error(Chef::Exceptions::ContentLengthMismatch)
+ end
+ it "successfully does a non-streaming GET request" do
+ expect { http_client.get(source) }.to raise_error(Chef::Exceptions::ContentLengthMismatch)
+ end
+ end
+
+ it_behaves_like "downloading all the things"
+end
+
diff --git a/spec/functional/resource/remote_file_spec.rb b/spec/functional/resource/remote_file_spec.rb
index 4468951a7a..6385efd563 100644
--- a/spec/functional/resource/remote_file_spec.rb
+++ b/spec/functional/resource/remote_file_spec.rb
@@ -18,8 +18,10 @@
require 'spec_helper'
require 'tiny_server'
+require 'support/shared/functional/http'
describe Chef::Resource::RemoteFile do
+ include ChefHTTPShared
let(:file_cache_path) { Dir.mktmpdir }
@@ -52,107 +54,6 @@ 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(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(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
- @server.stop
- @server = @api = nil
- end
-
context "when fetching files over HTTP" do
before(:all) do
start_tiny_server
@@ -177,13 +78,7 @@ describe Chef::Resource::RemoteFile do
context "when using normal encoding" do
let(:source) { 'http://localhost:9000/nyan_cat.png' }
- let(:expected_content) do
- content = File.open(File.join(CHEF_SPEC_DATA, 'remote_file', 'nyan_cat.png'), "rb") do |f|
- f.read
- end
- content.force_encoding(Encoding::BINARY) if content.respond_to?(:force_encoding)
- content
- end
+ let(:expected_content) { binread(nyan_uncompressed_filename) }
it_behaves_like "a file resource"
@@ -192,13 +87,7 @@ describe Chef::Resource::RemoteFile do
context "when using gzip encoding" do
let(:source) { 'http://localhost:9000/nyan_cat.png.gz' }
- let(:expected_content) do
- content = File.open(File.join(CHEF_SPEC_DATA, 'remote_file', 'nyan_cat.png.gz'), "rb") do |f|
- f.read
- end
- content.force_encoding(Encoding::BINARY) if content.respond_to?(:force_encoding)
- content
- end
+ let(:expected_content) { binread(nyan_compressed_filename) }
it_behaves_like "a file resource"
@@ -229,28 +118,13 @@ describe Chef::Resource::RemoteFile do
let(:source) { 'https://localhost:9000/nyan_cat.png' }
- let(:expected_content) do
- content = File.open(File.join(CHEF_SPEC_DATA, 'remote_file', 'nyan_cat.png'), "rb") do |f|
- f.read
- end
- content.force_encoding(Encoding::BINARY) if content.respond_to?(:force_encoding)
- content
- end
+ let(:expected_content) { binread(nyan_uncompressed_filename) }
it_behaves_like "a file resource"
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
@@ -260,7 +134,7 @@ describe Chef::Resource::RemoteFile do
end
context "when downloading compressed data" do
- let(:expected_content) { binread( File.join(CHEF_SPEC_DATA, 'remote_file', 'nyan_cat.png') ) }
+ let(:expected_content) { binread(nyan_uncompressed_filename) }
let(:source) { 'http://localhost:9000/nyan_cat_content_length_compressed.png' }
before do
@@ -282,7 +156,7 @@ describe Chef::Resource::RemoteFile do
end
context "when downloding uncompressed data" do
- let(:expected_content) { binread( File.join(CHEF_SPEC_DATA, 'remote_file', 'nyan_cat.png') ) }
+ let(:expected_content) { binread(nyan_uncompressed_filename) }
let(:source) { 'http://localhost:9000/nyan_cat_content_length.png' }
before do
@@ -330,7 +204,7 @@ describe Chef::Resource::RemoteFile do
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(:expected_content) { binread(nyan_uncompressed_filename) }
let(:source) { 'http://localhost:9000/nyan_cat_transfer_encoding.png' }
before do
diff --git a/spec/functional/rest_spec.rb b/spec/functional/rest_spec.rb
new file mode 100644
index 0000000000..7b87705d77
--- /dev/null
+++ b/spec/functional/rest_spec.rb
@@ -0,0 +1,57 @@
+#
+# Author:: Lamont Granquist (<lamont@getchef.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 'tiny_server'
+require 'support/shared/functional/http'
+
+describe Chef::REST do
+ include ChefHTTPShared
+
+ let(:http_client) { described_class.new(source) }
+ let(:http_client_disable_gzip) { described_class.new(source, Chef::Config[:node_name], Chef::Config[:client_key], { :disable_gzip => true } ) }
+
+ shared_examples_for "downloads requests correctly" do
+ it "successfully downloads a streaming request" do
+ tempfile = http_client.streaming_request(source, {})
+ tempfile.close
+ Digest::MD5.hexdigest(binread(tempfile.path)).should == Digest::MD5.hexdigest(expected_content)
+ end
+ end
+
+ shared_examples_for "validates content length and throws an exception" do
+ it "fails validation on a streaming download" do
+ expect { http_client.streaming_request(source, {}) }.to raise_error(Chef::Exceptions::ContentLengthMismatch)
+ end
+ end
+
+ before do
+ Chef::Config[:node_name] = "webmonkey.example.com"
+ Chef::Config[:client_key] = CHEF_SPEC_DATA + "/ssl/private_key.pem"
+ end
+
+ before(:all) do
+ start_tiny_server
+ end
+
+ after(:all) do
+ stop_tiny_server
+ end
+
+ it_behaves_like "downloading all the things"
+end
diff --git a/spec/support/shared/functional/http.rb b/spec/support/shared/functional/http.rb
new file mode 100644
index 0000000000..86fe467d92
--- /dev/null
+++ b/spec/support/shared/functional/http.rb
@@ -0,0 +1,219 @@
+#
+# Author:: Lamont Granquist (<lamont@getchef.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.
+#
+
+#
+# shared code for Chef::REST and Chef::HTTP::Simple and other Chef::HTTP wrappers
+#
+
+module ChefHTTPShared
+ def nyan_uncompressed_filename
+ File.join(CHEF_SPEC_DATA, 'remote_file', 'nyan_cat.png')
+ end
+
+ def nyan_compressed_filename
+ File.join(CHEF_SPEC_DATA, 'remote_file', 'nyan_cat.png.gz')
+ end
+
+ 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
+
+ def start_tiny_server(server_opts={})
+ 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
+ #
+
+ # just a normal file
+ # (expected_content should be uncompressed)
+ @api.get("/nyan_cat.png", 200) {
+ File.open(nyan_uncompressed_filename, "rb") do |f|
+ f.read
+ end
+ }
+
+ # this ends in .gz, we do not uncompress it and drop it on the filesystem as a .gz file (the internet often lies)
+ # (expected_content should be compressed)
+ @api.get("/nyan_cat.png.gz", 200, nil, { 'Content-Type' => 'application/gzip', 'Content-Encoding' => 'gzip' } ) {
+ File.open(nyan_compressed_filename, "rb") do |f|
+ f.read
+ end
+ }
+
+ # this is an uncompressed file that was compressed by some mod_gzip-ish webserver thingy, so we will expand it
+ # (expected_content should be uncompressed)
+ @api.get("/nyan_cat_compressed.png", 200, nil, { 'Content-Type' => 'application/gzip', 'Content-Encoding' => 'gzip' } ) {
+ File.open(nyan_compressed_filename, "rb") do |f|
+ f.read
+ end
+ }
+
+ #
+ # endpoints that set Content-Length correctly
+ #
+
+ # (expected_content should be uncompressed)
+ @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
+ }
+
+ # (expected_content should be uncompressed)
+ @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)
+ #
+
+ # (expected_content should be uncompressed)
+ @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
+ }
+
+ # (expected_content should be uncompressed)
+ @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)
+ #
+
+ # (expected_content should be uncompressed)
+ @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
+ @server.stop
+ @server = @api = nil
+ end
+
+end
+
+shared_examples_for "downloading all the things" do
+
+ describe "when downloading a simple uncompressed file" do
+ let(:source) { 'http://localhost:9000/nyan_cat.png' }
+ let(:expected_content) { binread(nyan_uncompressed_filename) }
+
+ it_behaves_like "downloads requests correctly"
+ end
+
+ describe "when downloading a compressed file that should be left compressed" do
+ let(:source) { 'http://localhost:9000/nyan_cat.png.gz' }
+ let(:expected_content) { binread(nyan_compressed_filename) }
+
+ # its the callers responsibility to disable_gzip when downloading a .gz url
+ let(:http_client) { http_client_disable_gzip }
+
+ it_behaves_like "downloads requests correctly"
+ end
+
+ describe "when downloading a file that has been compressed by the webserver" do
+ let(:source) { 'http://localhost:9000/nyan_cat_compressed.png' }
+ let(:expected_content) { binread(nyan_uncompressed_filename) }
+
+ it_behaves_like "downloads requests correctly"
+ end
+
+ describe "when downloading an uncompressed file with a correct content_length" do
+ let(:source) { 'http://localhost:9000/nyan_cat_content_length.png' }
+ let(:expected_content) { binread(nyan_uncompressed_filename) }
+
+ it_behaves_like "downloads requests correctly"
+ end
+
+ describe "when downloading a file that has been compressed by the webserver with a correct content_length" do
+ let(:source) { 'http://localhost:9000/nyan_cat_content_length_compressed.png' }
+ let(:expected_content) { binread(nyan_uncompressed_filename) }
+
+ it_behaves_like "downloads requests correctly"
+ end
+
+ describe "when downloading an uncompressed file that is truncated" do
+ let(:source) { 'http://localhost:9000/nyan_cat_truncated.png' }
+ let(:expected_content) { binread(nyan_uncompressed_filename) }
+
+ it_behaves_like "validates content length and throws an exception"
+ end
+
+ describe "when downloading a file that has been compressed by the webserver that is truncated" do
+ let(:source) { 'http://localhost:9000/nyan_cat_truncated_compressed.png' }
+ let(:expected_content) { binread(nyan_uncompressed_filename) }
+
+ it_behaves_like "validates content length and throws an exception"
+ end
+
+ describe "when downloading a file that has transfer encoding set with a bad content length that should be ignored" do
+ let(:source) { 'http://localhost:9000/nyan_cat_transfer_encoding.png' }
+ let(:expected_content) { binread(nyan_uncompressed_filename) }
+
+ it_behaves_like "downloads requests correctly"
+ end
+end
+