diff --git a/.gitignore b/.gitignore index cf4e1e4..1fd94cc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .rake_tasks site/public/index.html pkg/ +.bundle diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..c80ee36 --- /dev/null +++ b/Gemfile @@ -0,0 +1,3 @@ +source "http://rubygems.org" + +gemspec diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..fe3b911 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,25 @@ +PATH + remote: . + specs: + aws-s3 (0.6.3) + builder + mime-types + xml-simple + +GEM + remote: http://rubygems.org/ + specs: + builder (2.1.2) + flexmock (0.8.11) + mime-types (1.16) + xml-simple (1.0.12) + +PLATFORMS + ruby + +DEPENDENCIES + aws-s3! + builder + flexmock + mime-types + xml-simple diff --git a/aws-s3.gemspec b/aws-s3.gemspec index e40fa52..69f6a10 100644 --- a/aws-s3.gemspec +++ b/aws-s3.gemspec @@ -16,6 +16,7 @@ Gem::Specification.new do |s| s.add_dependency 'xml-simple' s.add_dependency 'builder' s.add_dependency 'mime-types' + s.add_development_dependency 'flexmock' s.rdoc_options = ['--title', "AWS::S3 -- Support for Amazon S3's REST api", '--main', 'README', '--line-numbers', '--inline-source'] diff --git a/lib/aws/s3/bucket.rb b/lib/aws/s3/bucket.rb index 84d89d3..2548a18 100644 --- a/lib/aws/s3/bucket.rb +++ b/lib/aws/s3/bucket.rb @@ -76,7 +76,14 @@ class << self # in the section called 'Setting access levels'. def create(name, options = {}) validate_name!(name) - put("/#{name}", options).success? + # workaround: PUT to create bucket should raise error (as specified in the AWS API docs) when trying to create existing bucket + begin + find(name) + raise AWS::S3::BucketAlreadyExists.new + rescue AWS::S3::NoSuchBucket + # bucket does not exist, so allow create PUT to go through + put("/#{name}", options).success? + end end # Fetches the bucket named name. @@ -316,4 +323,4 @@ def reload!(options = {}) end end end -end \ No newline at end of file +end diff --git a/lib/aws/s3/exceptions.rb b/lib/aws/s3/exceptions.rb index 9dab1a2..8f31e11 100644 --- a/lib/aws/s3/exceptions.rb +++ b/lib/aws/s3/exceptions.rb @@ -25,6 +25,9 @@ def initialize(message, response) class InternalError < ResponseError end + class NoSuchBucket < ResponseError + end + class NoSuchKey < ResponseError end @@ -90,6 +93,14 @@ def initialize(invalid_names) super(message) end end + + # Raised if a bucket already exists with the specified name + class BucketAlreadyExists < ResponseError + def initialize + message = "The requested bucket name is not available. The bucket namespace is shared by all users of the system. Please select a different name and try again." + super(message, {:body => message, :code => 409}) + end + end # Raised if the current bucket can not be inferred when not explicitly specifying the target bucket in the calling # method's arguments. @@ -130,4 +141,4 @@ def initialize(klass) #:startdoc: end -end \ No newline at end of file +end diff --git a/test/bucket_test.rb b/test/bucket_test.rb index d241534..145ac18 100644 --- a/test/bucket_test.rb +++ b/test/bucket_test.rb @@ -13,6 +13,22 @@ def test_bucket_name_validation assert_raises(InvalidBucketName) { validate_name[invalid_name] } end end + + def test_bucket_create_with_unique_name + bucket_name = 'foo' + flexmock(Bucket).should_receive(:find).with(bucket_name).and_raise(AWS::S3::NoSuchBucket.new('foobar', {:body => "foobar", :code => 404})) + flexmock(Bucket).should_receive(:put).with('/foo', any).and_return(flexmock(:success? => true)) + assert Bucket.create(bucket_name) + end + + # API says that create should error with a BucketAlreadyExists if name already is taken + def test_bucket_create_with_existing_name + bucket_name = 'foo' + flexmock(Bucket).should_receive(:find).with(bucket_name).and_return(flexmock(Bucket)) + assert_raise AWS::S3::BucketAlreadyExists do + Bucket.create(bucket_name) + end + end def test_empty_bucket mock_connection_for(Bucket, :returns => {:body => Fixtures::Buckets.empty_bucket, :code => 200}) @@ -71,4 +87,4 @@ def test_bucket_name_should_have_leading_slash_prepended_only_once_when_forcing_ flexmock(Base).should_receive(:delete).with(expected_bucket_path).once.and_return(mock_response) Bucket.delete(bucket_name, :force => true) end -end \ No newline at end of file +end