aliyun-sdk 0.1.1

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.
@@ -0,0 +1,338 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'spec_helper'
4
+ require 'yaml'
5
+ require 'nokogiri'
6
+
7
+ module Aliyun
8
+ module OSS
9
+
10
+ describe Bucket do
11
+
12
+ before :all do
13
+ @endpoint = 'oss-cn-hangzhou.aliyuncs.com'
14
+ @bucket_name = 'rubysdk-bucket'
15
+ @bucket = Client.new(
16
+ :endpoint => @endpoint,
17
+ :access_key_id => 'xxx',
18
+ :access_key_secret => 'yyy').get_bucket(@bucket_name)
19
+ end
20
+
21
+ def bucket_url
22
+ "#{@bucket_name}.#{@endpoint}"
23
+ end
24
+
25
+ def object_url(object)
26
+ "#{@bucket_name}.#{@endpoint}/#{object}"
27
+ end
28
+
29
+ def resource_path(object)
30
+ "/#{@bucket_name}/#{object}"
31
+ end
32
+
33
+ def mock_objects(objects, more = {})
34
+ Nokogiri::XML::Builder.new do |xml|
35
+ xml.ListBucketResult {
36
+ {
37
+ :prefix => 'Prefix',
38
+ :delimiter => 'Delimiter',
39
+ :limit => 'MaxKeys',
40
+ :marker => 'Marker',
41
+ :next_marker => 'NextMarker',
42
+ :truncated => 'IsTruncated',
43
+ :encoding => 'EncodingType'
44
+ }.map do |k, v|
45
+ xml.send(v, more[k]) if more[k] != nil
46
+ end
47
+
48
+ objects.each do |o|
49
+ xml.Contents {
50
+ xml.Key o.key
51
+ xml.Size o.size
52
+ xml.ETag o.etag
53
+ }
54
+ end
55
+
56
+ (more[:common_prefixes] || []).each do |p|
57
+ xml.CommonPrefixes {
58
+ xml.Prefix p
59
+ }
60
+ end
61
+ }
62
+ end.to_xml
63
+ end
64
+
65
+ def mock_acl(acl)
66
+ Nokogiri::XML::Builder.new do |xml|
67
+ xml.AccessControlPolicy {
68
+ xml.Owner {
69
+ xml.ID 'owner_id'
70
+ xml.DisplayName 'owner_name'
71
+ }
72
+
73
+ xml.AccessControlList {
74
+ xml.Grant acl
75
+ }
76
+ }
77
+ end.to_xml
78
+ end
79
+
80
+ context "bucket operations" do
81
+ it "should get acl" do
82
+ query = {'acl' => ''}
83
+ return_acl = ACL::PUBLIC_READ
84
+
85
+ stub_request(:get, bucket_url)
86
+ .with(:query => query)
87
+ .to_return(:body => mock_acl(return_acl))
88
+
89
+ acl = @bucket.acl
90
+
91
+ expect(WebMock).to have_requested(:get, bucket_url)
92
+ .with(:query => query, :body => nil)
93
+ expect(acl).to eq(return_acl)
94
+ end
95
+
96
+ it "should set acl" do
97
+ query = {'acl' => ''}
98
+
99
+ stub_request(:put, bucket_url).with(:query => query)
100
+
101
+ @bucket.acl = ACL::PUBLIC_READ
102
+
103
+ expect(WebMock).to have_requested(:put, bucket_url)
104
+ .with(:query => query, :body => nil)
105
+ end
106
+
107
+ it "should delete logging setting" do
108
+ query = {'logging' => ''}
109
+
110
+ stub_request(:delete, bucket_url).with(:query => query)
111
+
112
+ @bucket.logging = BucketLogging.new(:enable => false)
113
+
114
+ expect(WebMock).to have_requested(:delete, bucket_url)
115
+ .with(:query => query, :body => nil)
116
+ end
117
+
118
+ it "should get bucket url" do
119
+ expect(@bucket.bucket_url)
120
+ .to eq('http://rubysdk-bucket.oss-cn-hangzhou.aliyuncs.com')
121
+ end
122
+
123
+ it "should get access key id" do
124
+ expect(@bucket.access_key_id).to eq('xxx')
125
+ end
126
+ end # bucket operations
127
+
128
+ context "object operations" do
129
+ it "should list objects" do
130
+ query_1 = {
131
+ :prefix => 'list-',
132
+ :delimiter => '-'
133
+ }
134
+ return_obj_1 = (1..5).map{ |i| Object.new(
135
+ :key => "obj-#{i}",
136
+ :size => 1024 * i,
137
+ :etag => "etag-#{i}")}
138
+ return_more_1 = {
139
+ :next_marker => 'foo',
140
+ :truncated => true,
141
+ :common_prefixes => ['hello', 'world']
142
+ }
143
+
144
+ query_2 = {
145
+ :prefix => 'list-',
146
+ :delimiter => '-',
147
+ :marker => 'foo'
148
+ }
149
+ return_obj_2 = (6..8).map{ |i| Object.new(
150
+ :key => "obj-#{i}",
151
+ :size => 1024 * i,
152
+ :etag => "etag-#{i}")}
153
+ return_more_2 = {
154
+ :next_marker => 'bar',
155
+ :truncated => false,
156
+ :common_prefixes => ['rock', 'suck']
157
+ }
158
+
159
+ stub_request(:get, bucket_url)
160
+ .with(:query => query_1)
161
+ .to_return(:body => mock_objects(return_obj_1, return_more_1))
162
+
163
+ stub_request(:get, bucket_url)
164
+ .with(:query => query_2)
165
+ .to_return(:body => mock_objects(return_obj_2, return_more_2))
166
+
167
+ list = @bucket.list_objects :prefix => 'list-', :delimiter => '-'
168
+ all = list.to_a
169
+
170
+ expect(WebMock).to have_requested(:get, bucket_url)
171
+ .with(:query => query_1).times(1)
172
+ expect(WebMock).to have_requested(:get, bucket_url)
173
+ .with(:query => query_2).times(1)
174
+
175
+ objs = all.select{ |x| x.is_a?(Object) }
176
+ common_prefixes = all.select{ |x| x.is_a?(String) }
177
+ all_objs = (1..8).map{ |i| Object.new(
178
+ :key => "obj-#{i}",
179
+ :size => 1024 * i,
180
+ :etag => "etag-#{i}")}
181
+ expect(objs.map{ |o| o.to_s }).to match_array(all_objs.map{ |o| o.to_s })
182
+ all_prefixes = ['hello', 'world', 'rock', 'suck']
183
+ expect(common_prefixes).to match_array(all_prefixes)
184
+ end
185
+
186
+ it "should put object from file" do
187
+ key = 'ruby'
188
+ stub_request(:put, object_url(key))
189
+
190
+ content = (1..10).map{ |i| i.to_s.rjust(9, '0') }.join("\n")
191
+ File.open('/tmp/x', 'w'){ |f| f.write(content) }
192
+
193
+ @bucket.put_object(key, :file => '/tmp/x')
194
+
195
+ expect(WebMock).to have_requested(:put, object_url(key))
196
+ .with(:body => content, :query => {})
197
+ end
198
+
199
+ it "should get object to file" do
200
+ key = 'ruby'
201
+ # 100 KB
202
+ content = (1..1024).map{ |i| i.to_s.rjust(99, '0') }.join(",")
203
+
204
+ stub_request(:get, object_url(key)).to_return(:body => content)
205
+
206
+ @bucket.get_object(key, :file => '/tmp/x')
207
+
208
+ expect(WebMock).to have_requested(:get, object_url(key))
209
+ .with(:body => nil, :query => {})
210
+ expect(File.read('/tmp/x')).to eq(content)
211
+ end
212
+
213
+ it "should only get meta when get object without :file or block" do
214
+ key = 'ruby'
215
+
216
+ last_modified = Time.now.rfc822
217
+ return_headers = {
218
+ 'x-oss-object-type' => 'Normal',
219
+ 'ETag' => 'xxxyyyzzz',
220
+ 'Content-Length' => 1024,
221
+ 'Last-Modified' => last_modified,
222
+ 'x-oss-meta-year' => '2015',
223
+ 'x-oss-meta-people' => 'mary'
224
+ }
225
+ stub_request(:head, object_url(key))
226
+ .to_return(:headers => return_headers)
227
+
228
+ obj = @bucket.get_object(key)
229
+
230
+ expect(WebMock).to have_requested(:head, object_url(key))
231
+ .with(:body => nil, :query => {})
232
+
233
+ expect(obj.key).to eq(key)
234
+ expect(obj.type).to eq('Normal')
235
+ expect(obj.etag).to eq('xxxyyyzzz')
236
+ expect(obj.size).to eq(1024)
237
+ expect(obj.last_modified.rfc822).to eq(last_modified)
238
+ expect(obj.metas).to eq({'year' => '2015', 'people' => 'mary'})
239
+ end
240
+
241
+ it "should append object from file" do
242
+ key = 'ruby'
243
+ query = {'append' => '', 'position' => 11}
244
+ stub_request(:post, object_url(key)).with(:query => query)
245
+
246
+ content = (1..10).map{ |i| i.to_s.rjust(9, '0') }.join("\n")
247
+ content = "<html>" + content + "</html>"
248
+ File.open('/tmp/x.html', 'w'){ |f| f.write(content) }
249
+
250
+ @bucket.append_object(key, 11, :file => '/tmp/x.html')
251
+
252
+ expect(WebMock).to have_requested(:post, object_url(key))
253
+ .with(:query => query, :body => content,
254
+ :headers => {'Content-Type' => 'text/html'})
255
+ end
256
+
257
+ it "should answer object exists?" do
258
+ key = 'ruby'
259
+
260
+ stub_request(:head, object_url(key))
261
+ .to_return(:status => 404).times(3)
262
+
263
+ expect {
264
+ @bucket.get_object(key)
265
+ }.to raise_error(Exception, "UnknownError, HTTP Code: 404")
266
+
267
+ expect(@bucket.object_exists?(key)).to be false
268
+ expect(@bucket.object_exist?(key)).to be false
269
+
270
+ last_modified = Time.now.rfc822
271
+ return_headers = {
272
+ 'x-oss-object-type' => 'Normal',
273
+ 'ETag' => 'xxxyyyzzz',
274
+ 'Content-Length' => 1024,
275
+ 'Last-Modified' => last_modified,
276
+ 'x-oss-meta-year' => '2015',
277
+ 'x-oss-meta-people' => 'mary'
278
+ }
279
+
280
+ stub_request(:head, object_url(key))
281
+ .to_return(:headers => return_headers).times(2)
282
+
283
+ expect(@bucket.object_exists?(key)).to be true
284
+ expect(@bucket.object_exist?(key)).to be true
285
+
286
+ stub_request(:head, object_url(key))
287
+ .to_return(:status => 500)
288
+
289
+ expect {
290
+ @bucket.object_exists?(key)
291
+ }.to raise_error(Exception, "UnknownError, HTTP Code: 500")
292
+ end
293
+
294
+ it "should update object metas" do
295
+ key = 'ruby'
296
+
297
+ stub_request(:put, object_url(key))
298
+
299
+ @bucket.update_object_metas(
300
+ key, {'people' => 'mary', 'year' => '2016'})
301
+
302
+ expect(WebMock).to have_requested(:put, object_url(key))
303
+ .with(:body => nil,
304
+ :headers => {
305
+ 'x-oss-copy-source' => resource_path(key),
306
+ 'x-oss-metadata-directive' => 'REPLACE',
307
+ 'x-oss-meta-year' => '2016',
308
+ 'x-oss-meta-people' => 'mary'})
309
+ end
310
+
311
+ it "should get object url" do
312
+ url = @bucket.object_url('yeah', false)
313
+ object_url = 'http://rubysdk-bucket.oss-cn-hangzhou.aliyuncs.com/yeah'
314
+ expect(url).to eq(object_url)
315
+
316
+ url = @bucket.object_url('yeah')
317
+ path = url[0, url.index('?')]
318
+ expect(path).to eq(object_url)
319
+
320
+ query = {}
321
+ url[url.index('?') + 1, url.size].split('&')
322
+ .each { |s| k, v = s.split('='); query[k] = v }
323
+
324
+ expect(query.key?('Expires')).to be true
325
+ expect(query['OSSAccessKeyId']).to eq('xxx')
326
+ expires = query['Expires']
327
+ signature = CGI.unescape(query['Signature'])
328
+
329
+ string_to_sign =
330
+ "GET\n" + "\n\n" + "#{expires}\n" + "/rubysdk-bucket/yeah"
331
+ sig = Util.sign('yyy', string_to_sign)
332
+ expect(signature).to eq(sig)
333
+ end
334
+ end # object operations
335
+
336
+ end # Bucket
337
+ end # OSS
338
+ end # Aliyun
@@ -0,0 +1,228 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'spec_helper'
4
+ require 'yaml'
5
+ require 'nokogiri'
6
+
7
+ module Aliyun
8
+ module OSS
9
+
10
+ describe Client do
11
+
12
+ context "construct" do
13
+ it "should setup endpoint and a/k", :focus => true do
14
+ endpoint = 'oss-cn-hangzhou.aliyuncs.com'
15
+ client = Client.new(
16
+ :endpoint => endpoint,
17
+ :access_key_id => 'xxx', :access_key_secret => 'yyy')
18
+
19
+ config = client.instance_variable_get('@config')
20
+ expect(config.endpoint.to_s).to eq("http://#{endpoint}")
21
+ expect(config.access_key_id).to eq('xxx')
22
+ expect(config.access_key_secret).to eq('yyy')
23
+ end
24
+
25
+ it "should not set Authorization with anonymous client" do
26
+ endpoint = 'oss-cn-hangzhou.aliyuncs.com'
27
+ bucket = 'rubysdk-bucket'
28
+ object = 'rubysdk-object'
29
+ client = Client.new(:endpoint => endpoint)
30
+
31
+ stub_request(:get, "#{bucket}.#{endpoint}/#{object}")
32
+
33
+ client.get_bucket(bucket).get_object(object) {}
34
+
35
+ expect(WebMock)
36
+ .to have_requested(:get, "#{bucket}.#{endpoint}/#{object}")
37
+ .with{ |req| not req.headers.has_key?('Authorization') }
38
+ end
39
+
40
+ it "should construct different client" do
41
+ bucket = 'rubysdk-bucket'
42
+ object = 'rubysdk-object'
43
+ ep1 = 'oss-cn-hangzhou.aliyuncs.com'
44
+ c1 = Client.new(
45
+ :endpoint => ep1,
46
+ :access_key_id => 'xxx', :access_key_secret => 'yyy')
47
+ ep2 = 'oss-cn-beijing.aliyuncs.com'
48
+ c2 = Client.new(
49
+ :endpoint => ep2,
50
+ :access_key_id => 'aaa', :access_key_secret => 'bbb')
51
+
52
+ stub_request(:get, "#{bucket}.#{ep1}/#{object}")
53
+ stub_request(:put, "#{bucket}.#{ep2}/#{object}")
54
+
55
+ c1.get_bucket(bucket).get_object(object) {}
56
+ c2.get_bucket(bucket).put_object(object)
57
+
58
+ expect(WebMock).to have_requested(:get, "#{bucket}.#{ep1}/#{object}")
59
+ expect(WebMock).to have_requested(:put, "#{bucket}.#{ep2}/#{object}")
60
+ end
61
+ end # construct
62
+
63
+ def mock_buckets(buckets, more = {})
64
+ Nokogiri::XML::Builder.new do |xml|
65
+ xml.ListAllMyBucketsResult {
66
+ xml.Owner {
67
+ xml.ID 'owner_id'
68
+ xml.DisplayName 'owner_name'
69
+ }
70
+ xml.Buckets {
71
+ buckets.each do |b|
72
+ xml.Bucket {
73
+ xml.Location b.location
74
+ xml.Name b.name
75
+ xml.CreationDate b.creation_time.to_s
76
+ }
77
+ end
78
+ }
79
+
80
+ unless more.empty?
81
+ xml.Prefix more[:prefix]
82
+ xml.Marker more[:marker]
83
+ xml.MaxKeys more[:limit].to_s
84
+ xml.NextMarker more[:next_marker]
85
+ xml.IsTruncated more[:truncated]
86
+ end
87
+ }
88
+ end.to_xml
89
+ end
90
+
91
+ def mock_location(location)
92
+ Nokogiri::XML::Builder.new do |xml|
93
+ xml.CreateBucketConfiguration {
94
+ xml.LocationConstraint location
95
+ }
96
+ end.to_xml
97
+ end
98
+
99
+ def mock_acl(acl)
100
+ Nokogiri::XML::Builder.new do |xml|
101
+ xml.AccessControlPolicy {
102
+ xml.Owner {
103
+ xml.ID 'owner_id'
104
+ xml.DisplayName 'owner_name'
105
+ }
106
+
107
+ xml.AccessControlList {
108
+ xml.Grant acl
109
+ }
110
+ }
111
+ end.to_xml
112
+ end
113
+
114
+ context "bucket operations" do
115
+ before :all do
116
+ @endpoint = 'oss.aliyuncs.com'
117
+ @client = Client.new(
118
+ :endpoint => @endpoint,
119
+ :access_key_id => 'xxx',
120
+ :access_key_secret => 'yyy')
121
+ @bucket = 'rubysdk-bucket'
122
+ end
123
+
124
+ def bucket_url
125
+ @bucket + "." + @endpoint
126
+ end
127
+
128
+ it "should create bucket" do
129
+ location = 'oss-cn-hangzhou'
130
+
131
+ stub_request(:put, bucket_url).with(:body => mock_location(location))
132
+
133
+ @client.create_bucket(@bucket, :location => 'oss-cn-hangzhou')
134
+
135
+ expect(WebMock).to have_requested(:put, bucket_url)
136
+ .with(:body => mock_location(location), :query => {})
137
+ end
138
+
139
+ it "should delete bucket" do
140
+ stub_request(:delete, bucket_url)
141
+
142
+ @client.delete_bucket(@bucket)
143
+
144
+ expect(WebMock).to have_requested(:delete, bucket_url)
145
+ .with(:body => nil, :query => {})
146
+ end
147
+
148
+ it "should paging list buckets" do
149
+ return_buckets_1 = (1..5).map do |i|
150
+ name = "rubysdk-bucket-#{i.to_s.rjust(3, '0')}"
151
+ Bucket.new(
152
+ :name => name,
153
+ :location => 'oss-cn-hangzhou',
154
+ :creation_time => Time.now)
155
+ end
156
+
157
+ more_1 = {:next_marker => return_buckets_1.last.name, :truncated => true}
158
+
159
+ return_buckets_2 = (6..10).map do |i|
160
+ name = "rubysdk-bucket-#{i.to_s.rjust(3, '0')}"
161
+ Bucket.new(
162
+ :name => name,
163
+ :location => 'oss-cn-hangzhou',
164
+ :creation_time => Time.now)
165
+ end
166
+
167
+ more_2 = {:truncated => false}
168
+
169
+ stub_request(:get, /#{@endpoint}.*/)
170
+ .to_return(:body => mock_buckets(return_buckets_1, more_1)).then
171
+ .to_return(:body => mock_buckets(return_buckets_2, more_2))
172
+
173
+ buckets = @client.list_buckets
174
+
175
+ expect(buckets.map {|b| b.to_s}.join(";"))
176
+ .to eq((return_buckets_1 + return_buckets_2).map {|b| b.to_s}.join(";"))
177
+ expect(WebMock).to have_requested(:get, /#{@endpoint}.*/).times(2)
178
+ end
179
+
180
+ it "should test bucket existence" do
181
+ query = {'acl' => ''}
182
+ return_acl = ACL::PUBLIC_READ
183
+ stub_request(:get, bucket_url)
184
+ .with(:query => query)
185
+ .to_return(:body => mock_acl(return_acl)).then
186
+ .to_return(:status => 404)
187
+
188
+ exist = @client.bucket_exists?(@bucket)
189
+ expect(exist).to be true
190
+
191
+ exist = @client.bucket_exists?(@bucket)
192
+ expect(exist).to be false
193
+
194
+ expect(WebMock).to have_requested(:get, bucket_url)
195
+ .with(:query => query, :body => nil).times(2)
196
+ end
197
+
198
+ it "should not list buckets when endpoint is cname" do
199
+ cname_client = Client.new(
200
+ :endpoint => @endpoint,
201
+ :access_key_id => 'xxx',
202
+ :access_key_secret => 'yyy',
203
+ :cname => true)
204
+
205
+ expect {
206
+ cname_client.list_buckets
207
+ }.to raise_error(ClientError)
208
+ end
209
+
210
+ it "should use HTTPS" do
211
+ stub_request(:put, "https://#{bucket_url}")
212
+
213
+ https_client = Client.new(
214
+ :endpoint => "https://#{@endpoint}",
215
+ :access_key_id => 'xxx',
216
+ :access_key_secret => 'yyy',
217
+ :cname => false)
218
+
219
+ https_client.create_bucket(@bucket)
220
+
221
+ expect(WebMock).to have_requested(:put, "https://#{bucket_url}")
222
+ end
223
+ end # bucket operations
224
+
225
+ end # Client
226
+
227
+ end # OSS
228
+ end # Aliyun