aws-s3 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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