aws-s3 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -15,34 +15,60 @@ class BucketTest < Test::Unit::TestCase
15
15
  end
16
16
 
17
17
  def test_empty_bucket
18
- Bucket.request_always_returns :body => Fixtures::Buckets.empty_bucket, :code => 200 do
19
- bucket = Bucket.find('marcel_molina')
20
- assert bucket.empty?
21
- end
18
+ mock_connection_for(Bucket, :returns => {:body => Fixtures::Buckets.empty_bucket, :code => 200})
19
+ bucket = Bucket.find('marcel_molina')
20
+ assert bucket.empty?
22
21
  end
23
22
 
24
23
  def test_bucket_with_one_file
25
- Bucket.request_always_returns :body => Fixtures::Buckets.bucket_with_one_key, :code => 200 do
26
- bucket = Bucket.find('marcel_molina')
27
- assert !bucket.empty?
28
- assert_equal 1, bucket.size
29
- assert_equal %w(tongue_overload.jpg), bucket.objects.map {|object| object.key}
30
- assert bucket['tongue_overload.jpg']
31
- end
24
+ mock_connection_for(Bucket, :returns => {:body => Fixtures::Buckets.bucket_with_one_key, :code => 200})
25
+ bucket = Bucket.find('marcel_molina')
26
+ assert !bucket.empty?
27
+ assert_equal 1, bucket.size
28
+ assert_equal %w(tongue_overload.jpg), bucket.objects.map {|object| object.key}
29
+ assert bucket['tongue_overload.jpg']
32
30
  end
33
31
 
34
32
  def test_bucket_with_more_than_one_file
35
- Bucket.request_always_returns :body => Fixtures::Buckets.bucket_with_more_than_one_key, :code => 200 do
36
- bucket = Bucket.find('marcel_molina')
37
- assert !bucket.empty?
38
- assert_equal 2, bucket.size
39
- assert_equal %w(beluga_baby.jpg tongue_overload.jpg), bucket.objects.map {|object| object.key}.sort
40
- assert bucket['tongue_overload.jpg']
41
- end
33
+ mock_connection_for(Bucket, :returns => {:body => Fixtures::Buckets.bucket_with_more_than_one_key, :code => 200})
34
+ bucket = Bucket.find('marcel_molina')
35
+ assert !bucket.empty?
36
+ assert_equal 2, bucket.size
37
+ assert_equal %w(beluga_baby.jpg tongue_overload.jpg), bucket.objects.map {|object| object.key}.sort
38
+ assert bucket['tongue_overload.jpg']
42
39
  end
43
40
 
44
41
  def test_bucket_path
45
42
  assert_equal '/bucket_name?max-keys=2', Bucket.send(:path, 'bucket_name', :max_keys => 2)
46
43
  assert_equal '/bucket_name', Bucket.send(:path, 'bucket_name', {})
47
44
  end
45
+
46
+ def test_should_not_be_truncated
47
+ mock_connection_for(Bucket, :returns => {:body => Fixtures::Buckets.bucket_with_more_than_one_key, :code => 200})
48
+ bucket = Bucket.find('marcel_molina')
49
+ assert !bucket.is_truncated
50
+ end
51
+
52
+ def test_should_be_truncated
53
+ mock_connection_for(Bucket, :returns => {:body => Fixtures::Buckets.truncated_bucket_with_more_than_one_key, :code => 200})
54
+ bucket = Bucket.find('marcel_molina')
55
+ assert bucket.is_truncated
56
+ end
57
+
58
+ def test_bucket_name_should_have_leading_slash_prepended_only_once_when_forcing_a_delete
59
+ # References bug: http://rubyforge.org/tracker/index.php?func=detail&aid=19158&group_id=2409&atid=9356
60
+ bucket_name = 'foo'
61
+ expected_bucket_path = "/#{bucket_name}"
62
+
63
+ mock_bucket = flexmock('Mock bucket') do |mock|
64
+ mock.should_receive(:delete_all).once
65
+ end
66
+ mock_response = flexmock('Mock delete response') do |mock|
67
+ mock.should_receive(:success?).once
68
+ end
69
+
70
+ flexmock(Bucket).should_receive(:find).with(bucket_name).once.and_return(mock_bucket)
71
+ flexmock(Base).should_receive(:delete).with(expected_bucket_path).once.and_return(mock_response)
72
+ Bucket.delete(bucket_name, :force => true)
73
+ end
48
74
  end
@@ -1,42 +1,49 @@
1
1
  require File.dirname(__FILE__) + '/test_helper'
2
2
 
3
3
  class ConnectionTest < Test::Unit::TestCase
4
+ attr_reader :keys
4
5
  def setup
5
6
  @keys = {:access_key_id => '123', :secret_access_key => 'abc'}
6
7
  end
7
8
 
8
9
  def test_creating_a_connection
9
- connection = Connection.new(@keys)
10
+ connection = Connection.new(keys)
10
11
  assert_kind_of Net::HTTP, connection.http
11
12
  end
12
13
 
13
14
  def test_use_ssl_option_is_set_in_connection
14
- connection = Connection.new(@keys.merge(:use_ssl => true))
15
+ connection = Connection.new(keys.merge(:use_ssl => true))
15
16
  assert connection.http.use_ssl?
16
17
  end
17
18
 
18
19
  def test_setting_port_to_443_implies_use_ssl
19
- connection = Connection.new(@keys.merge(:port => 443))
20
+ connection = Connection.new(keys.merge(:port => 443))
20
21
  assert connection.http.use_ssl?
21
22
  end
22
23
 
23
24
  def test_protocol
24
- connection = Connection.new(@keys)
25
+ connection = Connection.new(keys)
25
26
  assert_equal 'http://', connection.protocol
26
- connection = Connection.new(@keys.merge(:use_ssl => true))
27
+ connection = Connection.new(keys.merge(:use_ssl => true))
27
28
  assert_equal 'https://', connection.protocol
28
29
  end
29
30
 
30
- def test_connection_is_persistent_by_default
31
- connection = Connection.new(@keys)
32
- assert connection.persistent?
33
-
34
- connection = Connection.new(@keys.merge(:persistent => false))
31
+ def test_url_for_honors_use_ssl_option_if_it_is_false_even_if_connection_has_use_ssl_option_set
32
+ # References bug: http://rubyforge.org/tracker/index.php?func=detail&aid=17628&group_id=2409&atid=9356
33
+ connection = Connection.new(keys.merge(:use_ssl => true))
34
+ assert_match %r(^http://), connection.url_for('/pathdoesnotmatter', :authenticated => false, :use_ssl => false)
35
+ end
36
+
37
+ def test_connection_is_not_persistent_by_default
38
+ connection = Connection.new(keys)
35
39
  assert !connection.persistent?
40
+
41
+ connection = Connection.new(keys.merge(:persistent => true))
42
+ assert connection.persistent?
36
43
  end
37
44
 
38
45
  def test_server_and_port_are_passed_onto_connection
39
- connection = Connection.new(@keys)
46
+ connection = Connection.new(keys)
40
47
  options = connection.instance_variable_get('@options')
41
48
  assert_equal connection.http.address, options[:server]
42
49
  assert_equal connection.http.port, options[:port]
@@ -52,18 +59,18 @@ class ConnectionTest < Test::Unit::TestCase
52
59
  end
53
60
 
54
61
  assert_nothing_raised do
55
- Connection.new(@keys)
62
+ Connection.new(keys)
56
63
  end
57
64
  end
58
65
 
59
66
  def test_access_keys_extracted
60
- connection = Connection.new(@keys)
67
+ connection = Connection.new(keys)
61
68
  assert_equal '123', connection.access_key_id
62
69
  assert_equal 'abc', connection.secret_access_key
63
70
  end
64
71
 
65
72
  def test_request_method_class_lookup
66
- c = Connection.new(@keys)
73
+ connection = Connection.new(keys)
67
74
  expectations = {
68
75
  :get => Net::HTTP::Get, :post => Net::HTTP::Post,
69
76
  :put => Net::HTTP::Put, :delete => Net::HTTP::Delete,
@@ -71,7 +78,7 @@ class ConnectionTest < Test::Unit::TestCase
71
78
  }
72
79
 
73
80
  expectations.each do |verb, klass|
74
- assert_equal klass, c.send(:request_method, verb)
81
+ assert_equal klass, connection.send(:request_method, verb)
75
82
  end
76
83
  end
77
84
 
@@ -99,10 +106,29 @@ class ConnectionTest < Test::Unit::TestCase
99
106
  def test_connecting_through_a_proxy
100
107
  connection = nil
101
108
  assert_nothing_raised do
102
- connection = Connection.new(@keys.merge(:proxy => sample_proxy_settings))
109
+ connection = Connection.new(keys.merge(:proxy => sample_proxy_settings))
103
110
  end
104
111
  assert connection.http.proxy?
105
112
  end
113
+
114
+ def test_request_only_escapes_the_path_the_first_time_it_runs_and_not_subsequent_times
115
+ connection = Connection.new(@keys)
116
+ unescaped_path = 'path with spaces'
117
+ escaped_path = 'path%20with%20spaces'
118
+
119
+ flexmock(Connection).should_receive(:prepare_path).with(unescaped_path).once.and_return(escaped_path).ordered
120
+ flexmock(connection.http).should_receive(:request).and_raise(Errno::EPIPE).ordered
121
+ flexmock(connection.http).should_receive(:request).ordered
122
+ connection.request :put, unescaped_path
123
+ end
124
+
125
+ def test_if_request_has_no_body_then_the_content_length_is_set_to_zero
126
+ # References bug: http://rubyforge.org/tracker/index.php?func=detail&aid=13052&group_id=2409&atid=9356
127
+ connection = Connection.new(@keys)
128
+ flexmock(Net::HTTP::Put).new_instances.should_receive(:content_length=).once.with(0).ordered
129
+ flexmock(connection.http).should_receive(:request).once.ordered
130
+ connection.request :put, 'path does not matter'
131
+ end
106
132
  end
107
133
 
108
134
  class ConnectionOptionsTest < Test::Unit::TestCase
@@ -4,9 +4,6 @@ class ErrorTest < Test::Unit::TestCase
4
4
  def setup
5
5
  @container = AWS::S3
6
6
  @error = Error.new(Parsing::XmlParser.new(Fixtures::Errors.access_denied))
7
- end
8
-
9
- def teardown
10
7
  @container.send(:remove_const, :NotImplemented) if @container.const_defined?(:NotImplemented)
11
8
  end
12
9
 
@@ -54,22 +51,20 @@ class ErrorTest < Test::Unit::TestCase
54
51
  end
55
52
 
56
53
  def test_error_response_handles_attributes_with_no_value
57
- Bucket.in_test_mode do
58
- Bucket.request_returns :body => Fixtures::Errors.error_with_no_message, :code => 500
59
-
60
- begin
61
- Bucket.create('foo', 'invalid-argument' => 'bad juju')
62
- rescue ResponseError => error
63
- end
54
+ mock_connection_for(Bucket, :returns => {:body => Fixtures::Errors.error_with_no_message, :code => 500})
55
+
56
+ begin
57
+ Bucket.create('foo', 'invalid-argument' => 'bad juju')
58
+ rescue ResponseError => error
59
+ end
60
+
61
+ assert_nothing_raised do
62
+ error.response.error.message
63
+ end
64
+ assert_nil error.response.error.message
64
65
 
65
- assert_nothing_raised do
66
- error.response.error.message
67
- end
68
- assert_nil error.response.error.message
69
-
70
- assert_raises(NoMethodError) do
71
- error.response.error.non_existant_method
72
- end
66
+ assert_raises(NoMethodError) do
67
+ error.response.error.non_existant_method
73
68
  end
74
69
  end
75
70
  end
@@ -100,3 +100,34 @@ bucket_with_more_than_one_key: >
100
100
  <StorageClass>STANDARD</StorageClass>
101
101
  </Contents>
102
102
  </ListBucketResult>
103
+
104
+ truncated_bucket_with_more_than_one_key: >
105
+ <ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
106
+ <Name>marcel_molina</Name>
107
+ <Prefix></Prefix>
108
+ <Marker></Marker>
109
+ <MaxKeys>2</MaxKeys>
110
+ <IsTruncated>true</IsTruncated>
111
+ <Contents>
112
+ <Key>beluga_baby.jpg</Key>
113
+ <LastModified>2006-10-05T02:55:10.000Z</LastModified>
114
+ <ETag>&quot;b2453d4a39a7387674a8c505112a2f0b&quot;</ETag>
115
+ <Size>35807</Size>
116
+ <Owner>
117
+ <ID>bb2041a25975c3d4ce9775fe9e93e5b77a6a9fad97dc7e00686191f3790b13f1</ID>
118
+ <DisplayName>mmolina@onramp.net</DisplayName>
119
+ </Owner>
120
+ <StorageClass>STANDARD</StorageClass>
121
+ </Contents>
122
+ <Contents>
123
+ <Key>tongue_overload.jpg</Key>
124
+ <LastModified>2006-10-05T02:42:22.000Z</LastModified>
125
+ <ETag>&quot;f21f7c4e8ea6e34b268887b07d6da745&quot;</ETag>
126
+ <Size>60673</Size>
127
+ <Owner>
128
+ <ID>bb2041a25975c3d4ce9775fe9e93e5b77a6a9fad97dc7e00686191f3790b13f1</ID>
129
+ <DisplayName>mmolina@onramp.net</DisplayName>
130
+ </Owner>
131
+ <StorageClass>STANDARD</StorageClass>
132
+ </Contents>
133
+ </ListBucketResult>
@@ -0,0 +1,26 @@
1
+ module AWS
2
+ module S3
3
+ class FakeResponse
4
+ attr_reader :code, :body, :headers
5
+ def initialize(options = {})
6
+ @code = options.delete(:code) || 200
7
+ @body = options.delete(:body) || ''
8
+ @headers = {'content-type' => 'application/xml'}.merge(options.delete(:headers) || {})
9
+ end
10
+
11
+ # For ErrorResponse
12
+ def response
13
+ body
14
+ end
15
+
16
+ def [](header)
17
+ headers[header]
18
+ end
19
+
20
+ def each(&block)
21
+ headers.each(&block)
22
+ end
23
+ alias_method :each_header, :each
24
+ end
25
+ end
26
+ end
@@ -7,25 +7,23 @@ class ObjectTest < Test::Unit::TestCase
7
7
  end
8
8
 
9
9
  def test_header_settings_reader_and_writer
10
- S3Object.in_test_mode do
11
- headers = {'content-type' => 'text/plain'}
12
- S3Object.request_returns :headers => headers
13
-
14
- assert_nothing_raised do
15
- @object.content_type
16
- end
10
+ headers = {'content-type' => 'text/plain'}
11
+ mock_connection_for(S3Object, :returns => {:headers => headers})
17
12
 
18
- assert_equal 'text/plain', @object.content_type
19
-
20
- assert_nothing_raised do
21
- @object.content_type = 'image/jpg'
22
- end
23
-
24
- assert_equal 'image/jpg', @object.content_type
25
-
26
- assert_raises(NoMethodError) do
27
- @object.non_existant_header_setting
28
- end
13
+ assert_nothing_raised do
14
+ @object.content_type
15
+ end
16
+
17
+ assert_equal 'text/plain', @object.content_type
18
+
19
+ assert_nothing_raised do
20
+ @object.content_type = 'image/jpg'
21
+ end
22
+
23
+ assert_equal 'image/jpg', @object.content_type
24
+
25
+ assert_raises(NoMethodError) do
26
+ @object.non_existant_header_setting
29
27
  end
30
28
  end
31
29
 
@@ -75,91 +73,81 @@ class ObjectTest < Test::Unit::TestCase
75
73
  end
76
74
 
77
75
  def test_fetching_object_value_generates_value_object
78
- S3Object.in_test_mode do
79
- S3Object.request_returns :body => 'hello!'
80
- value = S3Object.value('foo', 'bar')
81
- assert_kind_of S3Object::Value, value
82
- assert_equal 'hello!', value
83
- end
76
+ mock_connection_for(S3Object, :returns => {:body => 'hello!'})
77
+ value = S3Object.value('foo', 'bar')
78
+ assert_kind_of S3Object::Value, value
79
+ assert_equal 'hello!', value
84
80
  end
85
81
 
86
82
  def test_fetching_file_by_name_raises_when_heuristic_fails
87
- S3Object.request_always_returns :body => Fixtures::Buckets.bucket_with_one_key do
88
- assert_raises(NoSuchKey) do
89
- S3Object.find('not_tongue_overload.jpg', 'marcel_molina')
90
- end
91
-
92
- object = nil # Block scoping
93
- assert_nothing_raised do
94
- object = S3Object.find('tongue_overload.jpg', 'marcel_molina')
95
- end
96
- assert_kind_of S3Object, object
97
- assert_equal 'tongue_overload.jpg', object.key
83
+ mock_connection_for(Bucket, :returns => {:body => Fixtures::Buckets.bucket_with_one_key})
84
+ assert_raises(NoSuchKey) do
85
+ S3Object.find('not_tongue_overload.jpg', 'marcel_molina')
98
86
  end
87
+
88
+ object = nil # Block scoping
89
+ assert_nothing_raised do
90
+ object = S3Object.find('tongue_overload.jpg', 'marcel_molina')
91
+ end
92
+ assert_kind_of S3Object, object
93
+ assert_equal 'tongue_overload.jpg', object.key
99
94
  end
100
95
 
101
96
  def test_about
102
- S3Object.in_test_mode do
103
- headers = {'content-size' => '12345', 'date' => Time.now.httpdate, 'content-type' => 'application/xml'}
104
- S3Object.request_returns :headers => headers
105
- about = S3Object.about('foo', 'bar')
106
- assert_kind_of S3Object::About, about
107
- assert_equal headers, about
108
-
109
- S3Object.request_returns :code => 404
110
- assert_raises(NoSuchKey) do
111
- S3Object.about('foo', 'bar')
112
- end
97
+ headers = {'content-size' => '12345', 'date' => Time.now.httpdate, 'content-type' => 'application/xml'}
98
+ mock_connection_for(S3Object, :returns => [
99
+ {:headers => headers},
100
+ {:code => 404}
101
+ ]
102
+ )
103
+ about = S3Object.about('foo', 'bar')
104
+ assert_kind_of S3Object::About, about
105
+ assert_equal headers, about
106
+
107
+ assert_raises(NoSuchKey) do
108
+ S3Object.about('foo', 'bar')
113
109
  end
114
110
  end
115
111
 
116
- def test_exists?
117
- S3Object.in_test_mode do
118
- S3Object.request_returns :code => 404
119
- assert_equal false, S3Object.exists?('foo', 'bar')
120
-
121
- S3Object.request_returns :code => 200
122
- assert_equal true, S3Object.exists?('foo', 'bar')
123
- end
112
+ def test_can_tell_that_an_s3object_does_not_exist
113
+ mock_connection_for(S3Object, :returns => {:code => 404})
114
+ assert_equal false, S3Object.exists?('foo', 'bar')
115
+ end
116
+
117
+ def test_can_tell_that_an_s3object_exists
118
+ mock_connection_for(S3Object, :returns => {:code => 200})
119
+ assert_equal true, S3Object.exists?('foo', 'bar')
124
120
  end
125
121
 
126
122
  def test_s3object_equality
127
- Bucket.in_test_mode do
128
- Bucket.request_returns :body => Fixtures::Buckets.bucket_with_more_than_one_key
129
- file1, file2 = Bucket.objects('does not matter')
130
- assert file1 == file1
131
- assert file2 == file2
132
- assert !(file1 == file2) # /!\ Parens required /!\
133
- end
123
+ mock_connection_for(Bucket, :returns => {:body => Fixtures::Buckets.bucket_with_more_than_one_key})
124
+ file1, file2 = Bucket.objects('does not matter')
125
+ assert file1 == file1
126
+ assert file2 == file2
127
+ assert !(file1 == file2) # /!\ Parens required /!\
134
128
  end
135
129
 
136
130
  def test_inspect
137
- S3Object.in_test_mode do
138
- S3Object.request_returns :body => Fixtures::Buckets.bucket_with_one_key
139
- object = S3Object.find('tongue_overload.jpg', 'bucket does not matter')
140
- assert object.path
141
- assert_nothing_raised { object.inspect }
142
- assert object.inspect[object.path]
143
- end
144
- end
131
+ mock_connection_for(Bucket, :returns => {:body => Fixtures::Buckets.bucket_with_one_key})
132
+ object = S3Object.find('tongue_overload.jpg', 'bucket does not matter')
133
+ assert object.path
134
+ assert_nothing_raised { object.inspect }
135
+ assert object.inspect[object.path]
136
+ end
145
137
 
146
- def test_etag
147
- S3Object.in_test_mode do
148
- S3Object.request_returns :body => Fixtures::Buckets.bucket_with_one_key
138
+ def test_etag
139
+ mock_connection_for(Bucket, :returns => {:body => Fixtures::Buckets.bucket_with_one_key})
149
140
  file = S3Object.find('tongue_overload.jpg', 'bucket does not matter')
150
141
  assert file.etag
151
142
  assert_equal 'f21f7c4e8ea6e34b268887b07d6da745', file.etag
152
143
  end
153
- end
154
144
 
155
- def test_fetching_information_about_an_object_that_does_not_exist_raises_no_such_key
156
- S3Object.in_test_mode do
157
- S3Object.request_returns :body => '', :code => 404
158
- assert_raises(NoSuchKey) do
159
- S3Object.about('asdfasdfasdfas-this-does-not-exist', 'bucket does not matter')
160
- end
161
- end
162
- end
145
+ def test_fetching_information_about_an_object_that_does_not_exist_raises_no_such_key
146
+ mock_connection_for(S3Object, :returns => {:body => '', :code => 404})
147
+ assert_raises(NoSuchKey) do
148
+ S3Object.about('asdfasdfasdfas-this-does-not-exist', 'bucket does not matter')
149
+ end
150
+ end
163
151
  end
164
152
 
165
153
  class MetadataTest < Test::Unit::TestCase