From dae13d496cd491045641fcb0d218ac7da7a654ec Mon Sep 17 00:00:00 2001 From: Wesley Beary Date: Sun, 16 Aug 2009 13:31:36 -0700 Subject: [PATCH] custom error classes, specs for error expectations and mocks raise errors --- lib/fog/aws/requests/s3/copy_object.rb | 1 + lib/fog/aws/requests/s3/delete_bucket.rb | 1 + lib/fog/aws/requests/s3/delete_object.rb | 3 +- lib/fog/aws/requests/s3/get_bucket.rb | 7 +- .../aws/requests/s3/get_bucket_location.rb | 1 + lib/fog/aws/requests/s3/get_object.rb | 1 + .../aws/requests/s3/get_request_payment.rb | 1 + lib/fog/aws/requests/s3/put_object.rb | 1 + .../aws/requests/s3/put_request_payment.rb | 1 + lib/fog/connection.rb | 49 +------ lib/fog/errors.rb | 131 ++++++++++++++++++ spec/aws/s3/copy_object_spec.rb | 27 ++++ spec/aws/s3/delete_bucket_spec.rb | 6 + spec/aws/s3/delete_object_spec.rb | 10 ++ spec/aws/s3/get_bucket_location_spec.rb | 6 + spec/aws/s3/get_bucket_spec.rb | 6 + spec/aws/s3/get_object_spec.rb | 12 ++ spec/aws/s3/get_request_payment_spec.rb | 6 + spec/aws/s3/put_bucket_spec.rb | 4 + spec/aws/s3/put_object_spec.rb | 13 ++ spec/aws/s3/put_request_payment_spec.rb | 6 + 21 files changed, 242 insertions(+), 51 deletions(-) create mode 100644 lib/fog/errors.rb diff --git a/lib/fog/aws/requests/s3/copy_object.rb b/lib/fog/aws/requests/s3/copy_object.rb index b1fb41604..3f5476e2e 100644 --- a/lib/fog/aws/requests/s3/copy_object.rb +++ b/lib/fog/aws/requests/s3/copy_object.rb @@ -67,6 +67,7 @@ else } else response.status = 404 + raise(Fog::Errors.status_error(200, 404, response)) end response diff --git a/lib/fog/aws/requests/s3/delete_bucket.rb b/lib/fog/aws/requests/s3/delete_bucket.rb index e66425dd7..208d2fc0b 100644 --- a/lib/fog/aws/requests/s3/delete_bucket.rb +++ b/lib/fog/aws/requests/s3/delete_bucket.rb @@ -37,6 +37,7 @@ else response.status = 204 else response.status = 404 + raise(Fog::Errors.status_error(204, 404, response)) end response end diff --git a/lib/fog/aws/requests/s3/delete_object.rb b/lib/fog/aws/requests/s3/delete_object.rb index 3918810f9..3f2d8ffca 100644 --- a/lib/fog/aws/requests/s3/delete_object.rb +++ b/lib/fog/aws/requests/s3/delete_object.rb @@ -35,11 +35,12 @@ else def delete_object(bucket_name, object_name) response = Fog::Response.new - if (bucket = @data[:buckets][bucket_name]) && @data[:buckets][bucket_name][:objects][object_name] + if bucket = @data[:buckets][bucket_name] response.status = 204 bucket[:objects].delete(object_name) else response.status = 404 + raise(Fog::Errors.status_error(204, 404, response)) end response end diff --git a/lib/fog/aws/requests/s3/get_bucket.rb b/lib/fog/aws/requests/s3/get_bucket.rb index b6a236bfd..ae999bfc8 100644 --- a/lib/fog/aws/requests/s3/get_bucket.rb +++ b/lib/fog/aws/requests/s3/get_bucket.rb @@ -61,9 +61,7 @@ else def get_bucket(bucket_name, options = {}) response = Fog::Response.new - unless bucket = @data[:buckets][bucket_name] - response.status = 404 - else + if bucket = @data[:buckets][bucket_name] response.status = 200 response.body = { 'Contents' => bucket[:objects].values.map do |object| @@ -80,6 +78,9 @@ else 'Name' => bucket['Name'], 'Prefix' => options['Prefix'] || '' } + else + response.status = 404 + raise(Fog::Errors.status_error(200, 404, response)) end response end diff --git a/lib/fog/aws/requests/s3/get_bucket_location.rb b/lib/fog/aws/requests/s3/get_bucket_location.rb index 81d1699bd..3fc348fb6 100644 --- a/lib/fog/aws/requests/s3/get_bucket_location.rb +++ b/lib/fog/aws/requests/s3/get_bucket_location.rb @@ -41,6 +41,7 @@ else response.body = {'LocationConstraint' => bucket['LocationConstraint'] } else response.status = 404 + raise(Fog::Errors.status_error(200, 404, response)) end response end diff --git a/lib/fog/aws/requests/s3/get_object.rb b/lib/fog/aws/requests/s3/get_object.rb index f750ebf4d..b4f382e09 100644 --- a/lib/fog/aws/requests/s3/get_object.rb +++ b/lib/fog/aws/requests/s3/get_object.rb @@ -69,6 +69,7 @@ else end else response.status = 404 + raise(Fog::Errors.status_error(200, 404, response)) end response end diff --git a/lib/fog/aws/requests/s3/get_request_payment.rb b/lib/fog/aws/requests/s3/get_request_payment.rb index cba65a085..7733d13d3 100644 --- a/lib/fog/aws/requests/s3/get_request_payment.rb +++ b/lib/fog/aws/requests/s3/get_request_payment.rb @@ -41,6 +41,7 @@ else response.body = { 'Payer' => bucket['Payer'] } else response.status = 404 + raise(Fog::Errors.status_error(200, 404, response)) end response end diff --git a/lib/fog/aws/requests/s3/put_object.rb b/lib/fog/aws/requests/s3/put_object.rb index 5d1d3a974..f3ff2dfaa 100644 --- a/lib/fog/aws/requests/s3/put_object.rb +++ b/lib/fog/aws/requests/s3/put_object.rb @@ -63,6 +63,7 @@ else } else response.status = 404 + raise(Fog::Errors.status_error(200, 404, response)) end response end diff --git a/lib/fog/aws/requests/s3/put_request_payment.rb b/lib/fog/aws/requests/s3/put_request_payment.rb index fe3fc370d..759df4d10 100644 --- a/lib/fog/aws/requests/s3/put_request_payment.rb +++ b/lib/fog/aws/requests/s3/put_request_payment.rb @@ -43,6 +43,7 @@ else bucket['Payer'] = payer else response.status = 404 + raise(Fog::Errors.status_error(200, 404, response)) end response end diff --git a/lib/fog/connection.rb b/lib/fog/connection.rb index 14afebb71..526d6ee5a 100644 --- a/lib/fog/connection.rb +++ b/lib/fog/connection.rb @@ -3,6 +3,7 @@ require 'openssl' require 'socket' require 'uri' +require "#{File.dirname(__FILE__)}/errors" require "#{File.dirname(__FILE__)}/response" unless Fog.mocking? @@ -22,52 +23,6 @@ unless Fog.mocking? end end - # Messages for nicer exceptions, from rfc2616 - def error_message(expected, actual, response) - @messages ||= { - 100 => 'Continue', - 101 => 'Switching Protocols', - 200 => 'OK', - 201 =>'Created', - 202 => 'Accepted', - 203 => 'Non-Authoritative Information', - 204 => 'No Content', - 205 => 'Reset Content', - 206 => 'Partial Content', - 300 => 'Multiple Choices', - 301 => 'Moved Permanently', - 302 => 'Found', - 303 => 'See Other', - 304 => 'Not Modified', - 305 => 'Use Proxy', - 307 => 'Temporary Redirect', - 400 => 'Bad Request', - 401 => 'Unauthorized', - 402 => 'Payment Required', - 403 => 'Forbidden', - 404 => 'Not Found', - 405 => 'Method Not Allowed', - 406 => 'Not Acceptable', - 407 => 'Proxy Authentication Required', - 408 => 'Request Timeout', - 409 => 'Conflict', - 410 => 'Gone', - 411 => 'Length Required', - 412 => 'Precondition Failed', - 413 => 'Request Entity Too Large', - 414 => 'Request-URI Too Long', - 415 => 'Unsupported Media Type', - 416 => 'Requested Range Not Satisfiable', - 417 => 'Expectation Failed', - 500 => 'Internal Server Error', - 501 => 'Not Implemented', - 502 => 'Bad Gateway', - 503 => 'Service Unavailable', - 504 => 'Gateway Timeout' - } - "Expected(#{expected} #{@messages[expected]}) <=> Got(#{actual} #{@messages[actual]}) #{response.inspect}" - end - def request(params) params[:path] ||= '' unless params[:path][0] == '/' @@ -130,7 +85,7 @@ unless Fog.mocking? end if params[:expects] && params[:expects] != response.status - raise(error_message(params[:expects], response.status, response)) + raise(Fog::Errors.status_error(params[:expects], response.status, response)) else response end diff --git a/lib/fog/errors.rb b/lib/fog/errors.rb new file mode 100644 index 000000000..a38207b18 --- /dev/null +++ b/lib/fog/errors.rb @@ -0,0 +1,131 @@ +module Fog + module Errors + class Continue < StandardError; end # 100 + class SwitchingProtocols < StandardError; end # 101 + class OK < StandardError; end # 200 + class Created < StandardError; end # 201 + class Accepted < StandardError; end # 202 + class NonAuthoritativeInformation < StandardError; end # 203 + class NoContent < StandardError; end # 204 + class ResetContent < StandardError; end # 205 + class PartialContent < StandardError; end # 206 + class MultipleChoices < StandardError; end # 300 + class MovedPermanently < StandardError; end # 301 + class Found < StandardError; end # 302 + class SeeOther < StandardError; end # 303 + class NotModified < StandardError; end # 304 + class UseProxy < StandardError; end # 305 + class TemporaryRedirect < StandardError; end # 307 + class BadRequest < StandardError; end # 400 + class Unauthorized < StandardError; end # 401 + class PaymentRequired < StandardError; end # 402 + class Forbidden < StandardError; end # 403 + class NotFound < StandardError; end # 404 + class MethodNotAllowed < StandardError; end # 405 + class NotAcceptable < StandardError; end #406 + class ProxyAuthenticationRequired < StandardError; end #407 + class RequestTimeout < StandardError; end # 408 + class Conflict < StandardError; end # 409 + class Gone < StandardError; end # 410 + class LengthRequired < StandardError; end # 411 + class PreconditionFailed < StandardError; end # 412 + class RequestEntityTooLarge < StandardError; end # 412 + class RequestURITooLong < StandardError; end # 414 + class UnsupportedMediaType < StandardError; end # 415 + class RequestedRangeNotSatisfiable < StandardError; end # 416 + class ExpectationFailed < StandardError; end # 417 + class InternalServerError < StandardError; end # 500 + class NotImplemented < StandardError; end # 501 + class BadGateway < StandardError; end # 502 + class ServiceUnavailable < StandardError; end # 503 + class GatewayTimeout < StandardError; end # 504 + + # Messages for nicer exceptions, from rfc2616 + def self.status_error(expected, actual, response) + @errors ||= { + 100 => Fog::Errors::Continue, + 101 => Fog::Errors::SwitchingProtocols, + 200 => Fog::Errors::OK, + 201 => Fog::Errors::Created, + 202 => Fog::Errors::Accepted, + 203 => Fog::Errors::NonAuthoritativeInformation, + 204 => Fog::Errors::NoContent, + 205 => Fog::Errors::ResetContent, + 206 => Fog::Errors::PartialContent, + 300 => Fog::Errors::MultipleChoices, + 301 => Fog::Errors::MovedPermanently, + 302 => Fog::Errors::Found, + 303 => Fog::Errors::SeeOther, + 304 => Fog::Errors::NotModified, + 305 => Fog::Errors::UseProxy, + 307 => Fog::Errors::TemporaryRedirect, + 400 => Fog::Errors::BadRequest, + 401 => Fog::Errors::Unauthorized, + 402 => Fog::Errors::PaymentRequired, + 403 => Fog::Errors::Forbidden, + 404 => Fog::Errors::NotFound, + 405 => Fog::Errors::MethodNotAllowed, + 406 => Fog::Errors::NotAcceptable, + 407 => Fog::Errors::ProxyAuthenticationRequired, + 408 => Fog::Errors::RequestTimeout, + 409 => Fog::Errors::Conflict, + 410 => Fog::Errors::Gone, + 411 => Fog::Errors::LengthRequired, + 412 => Fog::Errors::PreconditionFailed, + 413 => Fog::Errors::RequestEntityTooLarge, + 414 => Fog::Errors::RequestURITooLong, + 415 => Fog::Errors::UnsupportedMediaType, + 416 => Fog::Errors::RequestedRangeNotSatisfiable, + 417 => Fog::Errors::ExpectationFailed, + 500 => Fog::Errors::InternalServerError, + 501 => Fog::Errors::NotImplemented, + 502 => Fog::Errors::BadGateway, + 503 => Fog::Errors::ServiceUnavailable, + 504 => Fog::Errors::GatewayTimeout + } + @messages ||= { + 100 => 'Continue', + 101 => 'Switching Protocols', + 200 => 'OK', + 201 =>'Created', + 202 => 'Accepted', + 203 => 'Non-Authoritative Information', + 204 => 'No Content', + 205 => 'Reset Content', + 206 => 'Partial Content', + 300 => 'Multiple Choices', + 301 => 'Moved Permanently', + 302 => 'Found', + 303 => 'See Other', + 304 => 'Not Modified', + 305 => 'Use Proxy', + 307 => 'Temporary Redirect', + 400 => 'Bad Request', + 401 => 'Unauthorized', + 402 => 'Payment Required', + 403 => 'Forbidden', + 404 => 'Not Found', + 405 => 'Method Not Allowed', + 406 => 'Not Acceptable', + 407 => 'Proxy Authentication Required', + 408 => 'Request Timeout', + 409 => 'Conflict', + 410 => 'Gone', + 411 => 'Length Required', + 412 => 'Precondition Failed', + 413 => 'Request Entity Too Large', + 414 => 'Request-URI Too Long', + 415 => 'Unsupported Media Type', + 416 => 'Requested Range Not Satisfiable', + 417 => 'Expectation Failed', + 500 => 'Internal Server Error', + 501 => 'Not Implemented', + 502 => 'Bad Gateway', + 503 => 'Service Unavailable', + 504 => 'Gateway Timeout' + } + @errors[actual].new("Expected(#{expected} #{@messages[expected]}) <=> Actual(#{actual} #{@messages[actual]}) #{response.inspect}") + end + + end +end \ No newline at end of file diff --git a/spec/aws/s3/copy_object_spec.rb b/spec/aws/s3/copy_object_spec.rb index 63aad96c9..8967fba4d 100644 --- a/spec/aws/s3/copy_object_spec.rb +++ b/spec/aws/s3/copy_object_spec.rb @@ -27,4 +27,31 @@ describe 'S3.copy_object' do actual.body['LastModified'].should be_a(Time) end + it 'should raise a NotFound error if the source_bucket does not exist' do + lambda { + @s3.copy_object( + 'fognotabucket', 'fog_copy_object_source', + 'fogcopyobjectdestination', 'fog_copy_object_destination' + ) + }.should raise_error(Fog::Errors::NotFound) + end + + it 'should raise a NotFound error if the source_object does not exist' do + lambda { + @s3.copy_object( + 'fogcopyobjectsource', 'fog_not_an_object', + 'fogcopyobjectdestination', 'fog_copy_object_destination' + ) + }.should raise_error(Fog::Errors::NotFound) + end + + it 'should raise a NotFound error if the target_bucket does not exist' do + lambda { + @s3.copy_object( + 'fogcopyobjectsource', 'fog_copy_object_source', + 'fognotabucket', 'fog_copy_object_destination' + ) + }.should raise_error(Fog::Errors::NotFound) + end + end \ No newline at end of file diff --git a/spec/aws/s3/delete_bucket_spec.rb b/spec/aws/s3/delete_bucket_spec.rb index 8c3c42903..decb450b9 100644 --- a/spec/aws/s3/delete_bucket_spec.rb +++ b/spec/aws/s3/delete_bucket_spec.rb @@ -12,4 +12,10 @@ describe 'S3.delete_bucket' do actual.status.should == 204 end + it 'should raise a NotFound error if the bucket does not exist' do + lambda { + @s3.delete_bucket('fognotabucket') + }.should raise_error(Fog::Errors::NotFound) + end + end diff --git a/spec/aws/s3/delete_object_spec.rb b/spec/aws/s3/delete_object_spec.rb index e5a5f13dd..e72b4cf41 100644 --- a/spec/aws/s3/delete_object_spec.rb +++ b/spec/aws/s3/delete_object_spec.rb @@ -18,4 +18,14 @@ describe 'S3.delete_object' do actual.status.should == 204 end + it 'should raise NotFound error if the bucket does not exist' do + lambda { + @s3.delete_object('fognotabucket', 'fog_delete_object') + }.should raise_error(Fog::Errors::NotFound) + end + + it 'should not raise an error if the object does not exist' do + @s3.delete_object('fogdeleteobject', 'fog_not_an_object') + end + end \ No newline at end of file diff --git a/spec/aws/s3/get_bucket_location_spec.rb b/spec/aws/s3/get_bucket_location_spec.rb index ae1549a55..e6ad0511f 100644 --- a/spec/aws/s3/get_bucket_location_spec.rb +++ b/spec/aws/s3/get_bucket_location_spec.rb @@ -21,4 +21,10 @@ describe 'S3.get_bucket_location' do actual.body['LocationConstraint'].should == 'EU' end + it 'should raise NotFound error if bucket does not exist' do + lambda { + @s3.get_bucket_location('fognotabucket') + }.should raise_error(Fog::Errors::NotFound) + end + end \ No newline at end of file diff --git a/spec/aws/s3/get_bucket_spec.rb b/spec/aws/s3/get_bucket_spec.rb index 26ae622bb..69096d829 100644 --- a/spec/aws/s3/get_bucket_spec.rb +++ b/spec/aws/s3/get_bucket_spec.rb @@ -33,4 +33,10 @@ describe 'S3.get_bucket' do object['StorageClass'].should be_a(String) end + it 'should raise a NotFound error if the bucket does not exist' do + lambda { + @s3.get_bucket('fognotabucket') + }.should raise_error(Fog::Errors::NotFound) + end + end diff --git a/spec/aws/s3/get_object_spec.rb b/spec/aws/s3/get_object_spec.rb index 3f5d05d9b..b626eae05 100644 --- a/spec/aws/s3/get_object_spec.rb +++ b/spec/aws/s3/get_object_spec.rb @@ -25,4 +25,16 @@ describe 'S3.get_object' do actual.headers['Last-Modified'].should be_a(String) end + it 'should raise a NotFound error if the bucket does not exist' do + lambda { + @s3.get_object('fognotabucket', 'fog_get_object') + }.should raise_error(Fog::Errors::NotFound) + end + + it 'should raise a NotFound error if the object does not exist' do + lambda { + @s3.get_object('foggetobject', 'fog_not_an_object') + }.should raise_error(Fog::Errors::NotFound) + end + end diff --git a/spec/aws/s3/get_request_payment_spec.rb b/spec/aws/s3/get_request_payment_spec.rb index 916d72ae7..600f3292f 100644 --- a/spec/aws/s3/get_request_payment_spec.rb +++ b/spec/aws/s3/get_request_payment_spec.rb @@ -17,4 +17,10 @@ describe 'S3.get_request_payment' do actual.body['Payer'].should == 'BucketOwner' end + it 'should raise a NotFound error if the bucket does not exist' do + lambda { + @s3.get_request_payment('fognotabucket') + }.should raise_error(Fog::Errors::NotFound) + end + end \ No newline at end of file diff --git a/spec/aws/s3/put_bucket_spec.rb b/spec/aws/s3/put_bucket_spec.rb index f18032201..18260743c 100644 --- a/spec/aws/s3/put_bucket_spec.rb +++ b/spec/aws/s3/put_bucket_spec.rb @@ -15,4 +15,8 @@ describe 'S3.put_bucket' do actual.status.should == 200 end + it 'should not raise an error if the bucket already exists' do + @s3.put_bucket('fogputbucket') + end + end diff --git a/spec/aws/s3/put_object_spec.rb b/spec/aws/s3/put_object_spec.rb index 71689dd07..d75248619 100644 --- a/spec/aws/s3/put_object_spec.rb +++ b/spec/aws/s3/put_object_spec.rb @@ -18,4 +18,17 @@ describe 'S3.put_object' do actual.status.should == 200 end + it 'should raise a NotFound error if the bucket does not exist' do + lambda { + file = File.open(File.dirname(__FILE__) + '/../../lorem.txt', 'r') + @s3.put_object('fognotabucket', 'fog_put_object', file) + }.should raise_error(Fog::Errors::NotFound) + end + + it 'should not raise an error if the object already exists' do + file = File.open(File.dirname(__FILE__) + '/../../lorem.txt', 'r') + actual = @s3.put_object('fogputobject', 'fog_put_object', file) + actual.status.should == 200 + end + end \ No newline at end of file diff --git a/spec/aws/s3/put_request_payment_spec.rb b/spec/aws/s3/put_request_payment_spec.rb index fb63232f8..175925fc9 100644 --- a/spec/aws/s3/put_request_payment_spec.rb +++ b/spec/aws/s3/put_request_payment_spec.rb @@ -16,4 +16,10 @@ describe 'S3.put_request_payment' do actual.status.should == 200 end + it 'should raise a NotFound error if bucket does not exist' do + lambda { + @s3.put_request_payment('fognotabucket', 'Requester') + }.should raise_error(Fog::Errors::NotFound) + end + end \ No newline at end of file