aliyun-oss-ex 0.7.0.1402831795

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.
Files changed (57) hide show
  1. checksums.yaml +7 -0
  2. data/COPYING +19 -0
  3. data/INSTALL +35 -0
  4. data/README +443 -0
  5. data/Rakefile +334 -0
  6. data/bin/oss +6 -0
  7. data/bin/setup.rb +11 -0
  8. data/lib/aliyun/oss.rb +55 -0
  9. data/lib/aliyun/oss/acl.rb +132 -0
  10. data/lib/aliyun/oss/authentication.rb +222 -0
  11. data/lib/aliyun/oss/base.rb +241 -0
  12. data/lib/aliyun/oss/bucket.rb +320 -0
  13. data/lib/aliyun/oss/connection.rb +279 -0
  14. data/lib/aliyun/oss/error.rb +70 -0
  15. data/lib/aliyun/oss/exceptions.rb +134 -0
  16. data/lib/aliyun/oss/extensions.rb +405 -0
  17. data/lib/aliyun/oss/logging.rb +304 -0
  18. data/lib/aliyun/oss/object.rb +612 -0
  19. data/lib/aliyun/oss/owner.rb +45 -0
  20. data/lib/aliyun/oss/parsing.rb +100 -0
  21. data/lib/aliyun/oss/response.rb +181 -0
  22. data/lib/aliyun/oss/service.rb +52 -0
  23. data/lib/aliyun/oss/version.rb +14 -0
  24. data/support/faster-xml-simple/lib/faster_xml_simple.rb +188 -0
  25. data/support/faster-xml-simple/test/regression_test.rb +48 -0
  26. data/support/faster-xml-simple/test/test_helper.rb +18 -0
  27. data/support/faster-xml-simple/test/xml_simple_comparison_test.rb +47 -0
  28. data/support/rdoc/code_info.rb +212 -0
  29. data/test/acl_test.rb +70 -0
  30. data/test/authentication_test.rb +114 -0
  31. data/test/base_test.rb +137 -0
  32. data/test/bucket_test.rb +75 -0
  33. data/test/connection_test.rb +218 -0
  34. data/test/error_test.rb +71 -0
  35. data/test/extensions_test.rb +346 -0
  36. data/test/fixtures.rb +90 -0
  37. data/test/fixtures/buckets.yml +133 -0
  38. data/test/fixtures/errors.yml +34 -0
  39. data/test/fixtures/headers.yml +3 -0
  40. data/test/fixtures/logging.yml +15 -0
  41. data/test/fixtures/loglines.yml +5 -0
  42. data/test/fixtures/logs.yml +7 -0
  43. data/test/fixtures/policies.yml +16 -0
  44. data/test/logging_test.rb +90 -0
  45. data/test/mocks/fake_response.rb +27 -0
  46. data/test/object_test.rb +221 -0
  47. data/test/parsing_test.rb +67 -0
  48. data/test/remote/acl_test.rb +28 -0
  49. data/test/remote/bucket_test.rb +147 -0
  50. data/test/remote/logging_test.rb +86 -0
  51. data/test/remote/object_test.rb +350 -0
  52. data/test/remote/test_file.data +0 -0
  53. data/test/remote/test_helper.rb +34 -0
  54. data/test/response_test.rb +69 -0
  55. data/test/service_test.rb +24 -0
  56. data/test/test_helper.rb +110 -0
  57. metadata +177 -0
@@ -0,0 +1,137 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require File.dirname(__FILE__) + '/test_helper'
3
+
4
+ class BaseTest < Test::Unit::TestCase
5
+ def test_connection_established
6
+ assert_raises(NoConnectionEstablished) do
7
+ Base.connection
8
+ end
9
+
10
+ Base.establish_connection!(:access_key_id => '123', :secret_access_key => 'abc')
11
+ assert_kind_of Connection, Base.connection
12
+
13
+ instance = Base.new
14
+ assert_equal instance.send(:connection), Base.connection
15
+ assert_equal instance.send(:http), Base.connection.http
16
+ end
17
+
18
+ def test_respond_with
19
+ assert_equal Base::Response, Base.send(:response_class)
20
+ Base.send(:respond_with, Bucket::Response) do
21
+ assert_equal Bucket::Response, Base.send(:response_class)
22
+ end
23
+ assert_equal Base::Response, Base.send(:response_class)
24
+ end
25
+
26
+ def test_request_tries_again_when_encountering_an_internal_error
27
+ mock_connection_for(Bucket, :returns => [
28
+ # First request is an internal error
29
+ {:body => Fixtures::Errors.internal_error, :code => 500, :error => true},
30
+ # Second request is a success
31
+ {:body => Fixtures::Buckets.empty_bucket, :code => 200}
32
+ ])
33
+ bucket = nil # Block scope hack
34
+ assert_nothing_raised do
35
+ bucket = Bucket.find('marcel')
36
+ end
37
+ # Don't call objects 'cause we don't want to make another request
38
+ assert bucket.object_cache.empty?
39
+ end
40
+
41
+ def test_request_tries_up_to_three_times
42
+ mock_connection_for(Bucket, :returns => [
43
+ # First request is an internal error
44
+ {:body => Fixtures::Errors.internal_error, :code => 500, :error => true},
45
+ # Second request is also an internal error
46
+ {:body => Fixtures::Errors.internal_error, :code => 500, :error => true},
47
+ # Ditto third
48
+ {:body => Fixtures::Errors.internal_error, :code => 500, :error => true},
49
+ # Fourth works
50
+ {:body => Fixtures::Buckets.empty_bucket, :code => 200}
51
+ ])
52
+ bucket = nil # Block scope hack
53
+ assert_nothing_raised do
54
+ bucket = Bucket.find('marcel')
55
+ end
56
+ # Don't call objects 'cause we don't want to make another request
57
+ assert bucket.object_cache.empty?
58
+ end
59
+
60
+ def test_request_tries_again_three_times_and_gives_up
61
+ mock_connection_for(Bucket, :returns => [
62
+ # First request is an internal error
63
+ {:body => Fixtures::Errors.internal_error, :code => 500, :error => true},
64
+ # Second request is also an internal error
65
+ {:body => Fixtures::Errors.internal_error, :code => 500, :error => true},
66
+ # Ditto third
67
+ {:body => Fixtures::Errors.internal_error, :code => 500, :error => true},
68
+ # Ditto fourth
69
+ {:body => Fixtures::Errors.internal_error, :code => 500, :error => true},
70
+ ])
71
+ assert_raises(InternalError) do
72
+ Bucket.find('marcel')
73
+ end
74
+ end
75
+ end
76
+
77
+ class MultiConnectionsTest < Test::Unit::TestCase
78
+ class ClassToTestSettingCurrentBucket < Base
79
+ set_current_bucket_to 'foo'
80
+ end
81
+
82
+ def setup
83
+ Base.send(:connections).clear
84
+ end
85
+
86
+ def test_default_connection_options_are_used_for_subsequent_connections
87
+ assert !Base.connected?
88
+
89
+ assert_raises(MissingAccessKey) do
90
+ Base.establish_connection!
91
+ end
92
+
93
+ assert !Base.connected?
94
+
95
+ assert_raises(NoConnectionEstablished) do
96
+ Base.connection
97
+ end
98
+
99
+ assert_nothing_raised do
100
+ Base.establish_connection!(:access_key_id => '123', :secret_access_key => 'abc')
101
+ end
102
+
103
+ assert Base.connected?
104
+
105
+ assert_nothing_raised do
106
+ Base.connection
107
+ end
108
+
109
+ # All subclasses are currently using the default connection
110
+ assert_equal Base.connection, Bucket.connection
111
+
112
+ # No need to pass in the required options. The default connection will supply them
113
+ assert_nothing_raised do
114
+ Bucket.establish_connection!(:server => 'foo.oss.aliyuncs.com')
115
+ end
116
+
117
+ assert Base.connection != Bucket.connection
118
+ assert_equal '123', Bucket.connection.access_key_id
119
+ assert_equal 'foo', Bucket.connection.subdomain
120
+ end
121
+
122
+ def test_current_bucket
123
+ Base.establish_connection!(:access_key_id => '123', :secret_access_key => 'abc')
124
+ assert_raises(CurrentBucketNotSpecified) do
125
+ Base.current_bucket
126
+ end
127
+
128
+ OSSObject.establish_connection!(:server => 'foo-bucket.oss.aliyuncs.com')
129
+ assert_nothing_raised do
130
+ assert_equal 'foo-bucket', OSSObject.current_bucket
131
+ end
132
+ end
133
+
134
+ def test_setting_the_current_bucket
135
+ assert_equal 'foo', ClassToTestSettingCurrentBucket.current_bucket
136
+ end
137
+ end
@@ -0,0 +1,75 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require File.dirname(__FILE__) + '/test_helper'
3
+
4
+ class BucketTest < Test::Unit::TestCase
5
+ def test_bucket_name_validation
6
+ valid_names = %w(123 joe step-one step_two step3 step_4 step-5 step.six)
7
+ invalid_names = ['12', 'jo', 'kevin spacey', 'larry@wall', '', 'a' * 256]
8
+ validate_name = Proc.new {|name| Bucket.send(:validate_name!, name)}
9
+ valid_names.each do |valid_name|
10
+ assert_nothing_raised { validate_name[valid_name] }
11
+ end
12
+
13
+ invalid_names.each do |invalid_name|
14
+ assert_raises(InvalidBucketName) { validate_name[invalid_name] }
15
+ end
16
+ end
17
+
18
+ def test_empty_bucket
19
+ mock_connection_for(Bucket, :returns => {:body => Fixtures::Buckets.empty_bucket, :code => 200})
20
+ bucket = Bucket.find('marcel_molina')
21
+ assert bucket.empty?
22
+ end
23
+
24
+ def test_bucket_with_one_file
25
+ mock_connection_for(Bucket, :returns => {:body => Fixtures::Buckets.bucket_with_one_key, :code => 200})
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
32
+
33
+ def test_bucket_with_more_than_one_file
34
+ mock_connection_for(Bucket, :returns => {:body => Fixtures::Buckets.bucket_with_more_than_one_key, :code => 200})
35
+ bucket = Bucket.find('marcel_molina')
36
+ assert !bucket.empty?
37
+ assert_equal 2, bucket.size
38
+ assert_equal %w(beluga_baby.jpg tongue_overload.jpg), bucket.objects.map {|object| object.key}.sort
39
+ assert bucket['tongue_overload.jpg']
40
+ end
41
+
42
+ def test_bucket_path
43
+ assert_equal '/bucket_name?max-keys=2', Bucket.send(:path, 'bucket_name', :max_keys => 2)
44
+ assert_equal '/bucket_name', Bucket.send(:path, 'bucket_name', {})
45
+ end
46
+
47
+ def test_should_not_be_truncated
48
+ mock_connection_for(Bucket, :returns => {:body => Fixtures::Buckets.bucket_with_more_than_one_key, :code => 200})
49
+ bucket = Bucket.find('marcel_molina')
50
+ assert !bucket.is_truncated
51
+ end
52
+
53
+ def test_should_be_truncated
54
+ mock_connection_for(Bucket, :returns => {:body => Fixtures::Buckets.truncated_bucket_with_more_than_one_key, :code => 200})
55
+ bucket = Bucket.find('marcel_molina')
56
+ assert bucket.is_truncated
57
+ end
58
+
59
+ def test_bucket_name_should_have_leading_slash_prepended_only_once_when_forcing_a_delete
60
+ # References bug: http://rubyforge.org/tracker/index.php?func=detail&aid=19158&group_id=2409&atid=9356
61
+ bucket_name = 'foo'
62
+ expected_bucket_path = "/#{bucket_name}"
63
+
64
+ mock_bucket = flexmock('Mock bucket') do |mock|
65
+ mock.should_receive(:delete_all).once
66
+ end
67
+ mock_response = flexmock('Mock delete response') do |mock|
68
+ mock.should_receive(:success?).once
69
+ end
70
+
71
+ flexmock(Bucket).should_receive(:find).with(bucket_name).once.and_return(mock_bucket)
72
+ flexmock(Base).should_receive(:delete).with(expected_bucket_path).once.and_return(mock_response)
73
+ Bucket.delete(bucket_name, :force => true)
74
+ end
75
+ end
@@ -0,0 +1,218 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require File.dirname(__FILE__) + '/test_helper'
3
+
4
+ class ConnectionTest < Test::Unit::TestCase
5
+ attr_reader :keys
6
+ def setup
7
+ @keys = {:access_key_id => '123', :secret_access_key => 'abc'}.freeze
8
+ end
9
+
10
+ def test_creating_a_connection
11
+ connection = Connection.new(keys)
12
+ assert_kind_of Net::HTTP, connection.http
13
+ end
14
+
15
+ def test_use_ssl_option_is_set_in_connection
16
+ connection = Connection.new(keys.merge(:use_ssl => true))
17
+ assert connection.http.use_ssl?
18
+ end
19
+
20
+ def test_setting_port_to_443_implies_use_ssl
21
+ connection = Connection.new(keys.merge(:port => 443))
22
+ assert connection.http.use_ssl?
23
+ end
24
+
25
+ def test_protocol
26
+ connection = Connection.new(keys)
27
+ assert_equal 'http://', connection.protocol
28
+ connection = Connection.new(keys.merge(:use_ssl => true))
29
+ assert_equal 'https://', connection.protocol
30
+ end
31
+
32
+ def test_url_for_honors_use_ssl_option_if_it_is_false_even_if_connection_has_use_ssl_option_set
33
+ # References bug: http://rubyforge.org/tracker/index.php?func=detail&aid=17628&group_id=2409&atid=9356
34
+ connection = Connection.new(keys.merge(:use_ssl => true))
35
+ assert_match %r(^http://), connection.url_for('/pathdoesnotmatter', :authenticated => false, :use_ssl => false)
36
+ end
37
+
38
+ def test_connection_is_not_persistent_by_default
39
+ connection = Connection.new(keys)
40
+ assert !connection.persistent?
41
+
42
+ connection = Connection.new(keys.merge(:persistent => true))
43
+ assert connection.persistent?
44
+ end
45
+
46
+ def test_server_and_port_are_passed_onto_connection
47
+ connection = Connection.new(keys)
48
+ options = connection.instance_variable_get('@options')
49
+ assert_equal connection.http.address, options[:server]
50
+ assert_equal connection.http.port, options[:port]
51
+ end
52
+
53
+ def test_not_including_required_access_keys_raises
54
+ assert_raises(MissingAccessKey) do
55
+ Connection.new
56
+ end
57
+
58
+ assert_raises(MissingAccessKey) do
59
+ Connection.new(:access_key_id => '123')
60
+ end
61
+
62
+ assert_nothing_raised do
63
+ Connection.new(keys)
64
+ end
65
+ end
66
+
67
+ def test_access_keys_extracted
68
+ connection = Connection.new(keys)
69
+ assert_equal '123', connection.access_key_id
70
+ assert_equal 'abc', connection.secret_access_key
71
+ end
72
+
73
+ def test_request_method_class_lookup
74
+ connection = Connection.new(keys)
75
+ expectations = {
76
+ :get => Net::HTTP::Get, :post => Net::HTTP::Post,
77
+ :put => Net::HTTP::Put, :delete => Net::HTTP::Delete,
78
+ :head => Net::HTTP::Head
79
+ }
80
+
81
+ expectations.each do |verb, klass|
82
+ assert_equal klass, connection.send(:request_method, verb)
83
+ end
84
+ end
85
+
86
+ def test_url_for_uses_default_protocol_server_and_port
87
+ connection = Connection.new(:access_key_id => '123', :secret_access_key => 'abc', :port => 80)
88
+ assert_match %r(^http://oss\.aliyuncs\.com/foo\?), connection.url_for('/foo')
89
+
90
+ connection = Connection.new(:access_key_id => '123', :secret_access_key => 'abc', :use_ssl => true, :port => 443)
91
+ assert_match %r(^https://oss\.aliyuncs\.com/foo\?), connection.url_for('/foo')
92
+ end
93
+
94
+ def test_url_for_remembers_custom_protocol_server_and_port
95
+ connection = Connection.new(:access_key_id => '123', :secret_access_key => 'abc', :server => 'example.org', :port => 555, :use_ssl => true)
96
+ assert_match %r(^https://example\.org:555/foo\?), connection.url_for('/foo')
97
+ end
98
+
99
+ def test_url_for_with_and_without_authenticated_urls
100
+ connection = Connection.new(:access_key_id => '123', :secret_access_key => 'abc', :server => 'example.org')
101
+ authenticated = lambda {|url| url['?OSSAccessKeyId']}
102
+ assert authenticated[connection.url_for('/foo')]
103
+ assert authenticated[connection.url_for('/foo', :authenticated => true)]
104
+ assert !authenticated[connection.url_for('/foo', :authenticated => false)]
105
+ end
106
+
107
+ def test_connecting_through_a_proxy
108
+ connection = nil
109
+ assert_nothing_raised do
110
+ connection = Connection.new(keys.merge(:proxy => sample_proxy_settings))
111
+ end
112
+ assert connection.http.proxy?
113
+ end
114
+
115
+ def test_request_only_escapes_the_path_the_first_time_it_runs_and_not_subsequent_times
116
+ connection = Connection.new(@keys)
117
+ unescaped_path = 'path with spaces'
118
+ escaped_path = 'path%20with%20spaces'
119
+
120
+ flexmock(Connection).should_receive(:prepare_path).with(unescaped_path).once.and_return(escaped_path).ordered
121
+ flexmock(connection.http).should_receive(:request).and_raise(Errno::EPIPE).ordered
122
+ flexmock(connection.http).should_receive(:request).ordered
123
+ connection.request :put, unescaped_path
124
+ rescue Net::HTTPBadResponse
125
+ #TODO 阿里云tengine过滤非法请求返回为非标准Http响应
126
+ end
127
+
128
+ def test_if_request_has_no_body_then_the_content_length_is_set_to_zero
129
+ # References bug: http://rubyforge.org/tracker/index.php?func=detail&aid=13052&group_id=2409&atid=9356
130
+ connection = Connection.new(@keys)
131
+ flexmock(Net::HTTP::Put).new_instances.should_receive(:content_length=).once.with(0).ordered
132
+ flexmock(connection.http).should_receive(:request).once.ordered
133
+ connection.request :put, 'path does not matter'
134
+ end
135
+ end
136
+
137
+ class ConnectionOptionsTest < Test::Unit::TestCase
138
+
139
+ def setup
140
+ @options = generate_options(:server => 'example.org', :port => 555)
141
+ @default_options = generate_options
142
+ end
143
+
144
+ def test_server_extracted
145
+ assert_key_transfered(:server, 'example.org', @options)
146
+ end
147
+
148
+ def test_port_extracted
149
+ assert_key_transfered(:port, 555, @options)
150
+ end
151
+
152
+ def test_server_defaults_to_default_host
153
+ assert_equal DEFAULT_HOST, @default_options[:server]
154
+ end
155
+
156
+ def test_port_defaults_to_80_if_use_ssl_is_false
157
+ assert_equal 80, @default_options[:port]
158
+ end
159
+
160
+ def test_port_is_set_to_443_if_use_ssl_is_true
161
+ options = generate_options(:use_ssl => true)
162
+ assert_equal 443, options[:port]
163
+ end
164
+
165
+ def test_explicit_port_trumps_use_ssl
166
+ options = generate_options(:port => 555, :use_ssl => true)
167
+ assert_equal 555, options[:port]
168
+ end
169
+
170
+ def test_invalid_options_raise
171
+ assert_raises(InvalidConnectionOption) do
172
+ generate_options(:host => 'campfire.oss.aliyuncs.com')
173
+ end
174
+ end
175
+
176
+ def test_not_specifying_all_required_proxy_settings_raises
177
+ assert_raises(ArgumentError) do
178
+ generate_options(:proxy => {})
179
+ end
180
+ end
181
+
182
+ def test_not_specifying_proxy_option_at_all_does_not_raise
183
+ assert_nothing_raised do
184
+ generate_options
185
+ end
186
+ end
187
+
188
+ def test_specifying_all_required_proxy_settings
189
+ assert_nothing_raised do
190
+ generate_options(:proxy => sample_proxy_settings)
191
+ end
192
+ end
193
+
194
+ def test_only_host_setting_is_required
195
+ assert_nothing_raised do
196
+ generate_options(:proxy => {:host => 'http://google.com'})
197
+ end
198
+ end
199
+
200
+ def test_proxy_settings_are_extracted
201
+ options = generate_options(:proxy => sample_proxy_settings)
202
+ assert_equal sample_proxy_settings.values.map {|value| value.to_s}.sort, options.proxy_settings.map {|value| value.to_s}.sort
203
+ end
204
+
205
+ def test_recognizing_that_the_settings_want_to_connect_through_a_proxy
206
+ options = generate_options(:proxy => sample_proxy_settings)
207
+ assert options.connecting_through_proxy?
208
+ end
209
+
210
+ private
211
+ def assert_key_transfered(key, value, options)
212
+ assert_equal value, options[key]
213
+ end
214
+
215
+ def generate_options(options = {})
216
+ Connection::Options.new(options)
217
+ end
218
+ end
@@ -0,0 +1,71 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require File.dirname(__FILE__) + '/test_helper'
3
+
4
+ class ErrorTest < Test::Unit::TestCase
5
+ def setup
6
+ @container = Aliyun::OSS
7
+ @error = Error.new(Parsing::XmlParser.new(Fixtures::Errors.access_denied))
8
+ @container.send(:remove_const, :NotImplemented) if @container.const_defined?(:NotImplemented)
9
+ end
10
+
11
+ def test_error_class_is_automatically_generated
12
+ assert !@container.const_defined?('NotImplemented')
13
+ error = Error.new(Parsing::XmlParser.new(Fixtures::Errors.not_implemented))
14
+ assert @container.const_defined?('NotImplemented')
15
+ end
16
+
17
+ def test_error_contains_attributes
18
+ assert_equal 'Access Denied', @error.message
19
+ end
20
+
21
+ def test_error_is_raisable_as_exception
22
+ assert_raises(@container::AccessDenied) do
23
+ @error.raise
24
+ end
25
+ end
26
+
27
+ def test_error_message_is_passed_along_to_exception
28
+ @error.raise
29
+ rescue @container::AccessDenied => e
30
+ assert_equal 'Access Denied', e.message
31
+ end
32
+
33
+ def test_response_is_passed_along_to_exception
34
+ response = Error::Response.new(FakeResponse.new(:code => 409, :body => Fixtures::Errors.access_denied))
35
+ response.error.raise
36
+ rescue @container::ResponseError => e
37
+ assert e.response
38
+ assert_kind_of Error::Response, e.response
39
+ assert_equal response.error, e.response.error
40
+ end
41
+
42
+ def test_exception_class_clash
43
+ assert !@container.const_defined?(:NotImplemented)
44
+ # Create a class that does not inherit from exception that has the same name as the class
45
+ # the Error instance is about to attempt to find or create
46
+ @container.const_set(:NotImplemented, Class.new)
47
+ assert @container.const_defined?(:NotImplemented)
48
+
49
+ assert_raises(ExceptionClassClash) do
50
+ Error.new(Parsing::XmlParser.new(Fixtures::Errors.not_implemented))
51
+ end
52
+ end
53
+
54
+ def test_error_response_handles_attributes_with_no_value
55
+ mock_connection_for(Bucket, :returns => {:body => Fixtures::Errors.error_with_no_message, :code => 500})
56
+
57
+ begin
58
+ Bucket.create('foo', 'invalid-argument' => 'bad juju')
59
+ rescue ResponseError => error
60
+ end
61
+
62
+ assert_nothing_raised do
63
+ error.response.error.message
64
+ end
65
+ assert_nil error.response.error.message
66
+
67
+ assert_raises(NoMethodError) do
68
+ error.response.error.non_existant_method
69
+ end
70
+ end
71
+ end