aliyun-oss-ruby-sdk 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +95 -0
  3. data/README.md +423 -0
  4. data/examples/aliyun/oss/bucket.rb +144 -0
  5. data/examples/aliyun/oss/callback.rb +61 -0
  6. data/examples/aliyun/oss/object.rb +182 -0
  7. data/examples/aliyun/oss/resumable_download.rb +42 -0
  8. data/examples/aliyun/oss/resumable_upload.rb +49 -0
  9. data/examples/aliyun/oss/streaming.rb +124 -0
  10. data/examples/aliyun/oss/using_sts.rb +48 -0
  11. data/examples/aliyun/sts/assume_role.rb +59 -0
  12. data/lib/aliyun_sdk/common.rb +6 -0
  13. data/lib/aliyun_sdk/common/exception.rb +18 -0
  14. data/lib/aliyun_sdk/common/logging.rb +46 -0
  15. data/lib/aliyun_sdk/common/struct.rb +56 -0
  16. data/lib/aliyun_sdk/oss.rb +16 -0
  17. data/lib/aliyun_sdk/oss/bucket.rb +661 -0
  18. data/lib/aliyun_sdk/oss/client.rb +106 -0
  19. data/lib/aliyun_sdk/oss/config.rb +39 -0
  20. data/lib/aliyun_sdk/oss/download.rb +255 -0
  21. data/lib/aliyun_sdk/oss/exception.rb +108 -0
  22. data/lib/aliyun_sdk/oss/http.rb +338 -0
  23. data/lib/aliyun_sdk/oss/iterator.rb +92 -0
  24. data/lib/aliyun_sdk/oss/multipart.rb +74 -0
  25. data/lib/aliyun_sdk/oss/object.rb +15 -0
  26. data/lib/aliyun_sdk/oss/protocol.rb +1499 -0
  27. data/lib/aliyun_sdk/oss/struct.rb +208 -0
  28. data/lib/aliyun_sdk/oss/upload.rb +238 -0
  29. data/lib/aliyun_sdk/oss/util.rb +89 -0
  30. data/lib/aliyun_sdk/sts.rb +9 -0
  31. data/lib/aliyun_sdk/sts/client.rb +38 -0
  32. data/lib/aliyun_sdk/sts/config.rb +22 -0
  33. data/lib/aliyun_sdk/sts/exception.rb +53 -0
  34. data/lib/aliyun_sdk/sts/protocol.rb +130 -0
  35. data/lib/aliyun_sdk/sts/struct.rb +64 -0
  36. data/lib/aliyun_sdk/sts/util.rb +48 -0
  37. data/lib/aliyun_sdk/version.rb +7 -0
  38. data/spec/aliyun/oss/bucket_spec.rb +597 -0
  39. data/spec/aliyun/oss/client/bucket_spec.rb +554 -0
  40. data/spec/aliyun/oss/client/client_spec.rb +297 -0
  41. data/spec/aliyun/oss/client/resumable_download_spec.rb +220 -0
  42. data/spec/aliyun/oss/client/resumable_upload_spec.rb +413 -0
  43. data/spec/aliyun/oss/http_spec.rb +83 -0
  44. data/spec/aliyun/oss/multipart_spec.rb +686 -0
  45. data/spec/aliyun/oss/object_spec.rb +785 -0
  46. data/spec/aliyun/oss/service_spec.rb +142 -0
  47. data/spec/aliyun/oss/util_spec.rb +50 -0
  48. data/spec/aliyun/sts/client_spec.rb +150 -0
  49. data/spec/aliyun/sts/util_spec.rb +39 -0
  50. data/tests/config.rb +31 -0
  51. data/tests/test_content_encoding.rb +54 -0
  52. data/tests/test_content_type.rb +95 -0
  53. data/tests/test_custom_headers.rb +70 -0
  54. data/tests/test_encoding.rb +77 -0
  55. data/tests/test_large_file.rb +66 -0
  56. data/tests/test_multipart.rb +97 -0
  57. data/tests/test_object_acl.rb +49 -0
  58. data/tests/test_object_key.rb +68 -0
  59. data/tests/test_object_url.rb +69 -0
  60. data/tests/test_resumable.rb +40 -0
  61. metadata +240 -0
@@ -0,0 +1,686 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'spec_helper'
4
+ require 'yaml'
5
+ require 'nokogiri'
6
+
7
+ module AliyunSDK
8
+ module OSS
9
+
10
+ describe Multipart do
11
+
12
+ before :all do
13
+ @endpoint = 'oss.aliyuncs.com'
14
+ @protocol = Protocol.new(
15
+ Config.new(:endpoint => @endpoint,
16
+ :access_key_id => 'xxx', :access_key_secret => 'yyy'))
17
+
18
+ @bucket = 'rubysdk-bucket'
19
+ @object = 'rubysdk-object'
20
+ end
21
+
22
+ def request_path
23
+ "#{@bucket}.#{@endpoint}/#{@object}"
24
+ end
25
+
26
+ def mock_txn_id(txn_id)
27
+ Nokogiri::XML::Builder.new do |xml|
28
+ xml.InitiateMultipartUploadResult {
29
+ xml.Bucket @bucket
30
+ xml.Key @object
31
+ xml.UploadId txn_id
32
+ }
33
+ end.to_xml
34
+ end
35
+
36
+ def mock_multiparts(multiparts, more = {})
37
+ Nokogiri::XML::Builder.new do |xml|
38
+ xml.ListMultipartUploadsResult {
39
+ {
40
+ :prefix => 'Prefix',
41
+ :limit => 'MaxUploads',
42
+ :id_marker => 'UploadIdMarker',
43
+ :next_id_marker => 'NextUploadIdMarker',
44
+ :key_marker => 'KeyMarker',
45
+ :next_key_marker => 'NextKeyMarker',
46
+ :truncated => 'IsTruncated',
47
+ :encoding => 'EncodingType'
48
+ }.map do |k, v|
49
+ xml.send(v, more[k]) if more[k]
50
+ end
51
+
52
+ multiparts.each do |m|
53
+ xml.Upload {
54
+ xml.Key m.object
55
+ xml.UploadId m.id
56
+ xml.Initiated m.creation_time.rfc822
57
+ }
58
+ end
59
+ }
60
+ end.to_xml
61
+ end
62
+
63
+ def mock_parts(parts, more = {})
64
+ Nokogiri::XML::Builder.new do |xml|
65
+ xml.ListPartsResult {
66
+ {
67
+ :marker => 'PartNumberMarker',
68
+ :next_marker => 'NextPartNumberMarker',
69
+ :limit => 'MaxParts',
70
+ :truncated => 'IsTruncated',
71
+ :encoding => 'EncodingType'
72
+ }.map do |k, v|
73
+ xml.send(v, more[k]) if more[k]
74
+ end
75
+
76
+ parts.each do |p|
77
+ xml.Part {
78
+ xml.PartNumber p.number
79
+ xml.LastModified p.last_modified.rfc822
80
+ xml.ETag p.etag
81
+ xml.Size p.size
82
+ }
83
+ end
84
+ }
85
+ end.to_xml
86
+ end
87
+
88
+ def mock_error(code, message)
89
+ Nokogiri::XML::Builder.new do |xml|
90
+ xml.Error {
91
+ xml.Code code
92
+ xml.Message message
93
+ xml.RequestId '0000'
94
+ }
95
+ end.to_xml
96
+ end
97
+
98
+ def err(msg, reqid = '0000')
99
+ "#{msg} RequestId: #{reqid}"
100
+ end
101
+
102
+ context "Initiate multipart upload" do
103
+
104
+ it "should POST to create transaction" do
105
+ query = {'uploads' => ''}
106
+ stub_request(:post, request_path).with(:query => query)
107
+
108
+ @protocol.initiate_multipart_upload(
109
+ @bucket, @object, :metas => {
110
+ 'year' => '2015',
111
+ 'people' => 'mary'
112
+ })
113
+
114
+ expect(WebMock).to have_requested(:post, request_path)
115
+ .with(:body => nil, :query => query,
116
+ :headers => {
117
+ 'x-oss-meta-year' => '2015',
118
+ 'x-oss-meta-people' => 'mary'
119
+ })
120
+ end
121
+
122
+ it "should return transaction id" do
123
+ query = {'uploads' => ''}
124
+ return_txn_id = 'zyx'
125
+ stub_request(:post, request_path).
126
+ with(:query => query).
127
+ to_return(:body => mock_txn_id(return_txn_id))
128
+
129
+ txn_id = @protocol.initiate_multipart_upload(@bucket, @object)
130
+
131
+ expect(WebMock).to have_requested(:post, request_path)
132
+ .with(:body => nil, :query => query)
133
+ expect(txn_id).to eq(return_txn_id)
134
+ end
135
+
136
+ it "should raise Exception on error" do
137
+ query = {'uploads' => ''}
138
+
139
+ code = 'InvalidArgument'
140
+ message = 'Invalid argument.'
141
+ stub_request(:post, request_path)
142
+ .with(:query => query)
143
+ .to_return(:status => 400, :body => mock_error(code, message))
144
+
145
+ expect {
146
+ @protocol.initiate_multipart_upload(@bucket, @object)
147
+ }.to raise_error(ServerError, err(message))
148
+
149
+ expect(WebMock).to have_requested(:post, request_path)
150
+ .with(:body => nil, :query => query)
151
+ end
152
+ end # initiate multipart
153
+
154
+ context "Upload part" do
155
+
156
+ it "should PUT to upload a part" do
157
+ txn_id = 'xxxyyyzzz'
158
+ part_no = 1
159
+ query = {'partNumber' => part_no, 'uploadId' => txn_id}
160
+
161
+ stub_request(:put, request_path).with(:query => query)
162
+
163
+ @protocol.upload_part(@bucket, @object, txn_id, part_no) {}
164
+
165
+ expect(WebMock).to have_requested(:put, request_path)
166
+ .with(:body => nil, :query => query)
167
+ end
168
+
169
+ it "should return part etag" do
170
+ part_no = 1
171
+ txn_id = 'xxxyyyzzz'
172
+ query = {'partNumber' => part_no, 'uploadId' => txn_id}
173
+
174
+ return_etag = 'etag_1'
175
+ stub_request(:put, request_path)
176
+ .with(:query => query)
177
+ .to_return(:headers => {'ETag' => return_etag})
178
+
179
+ body = 'hello world'
180
+ p = @protocol.upload_part(@bucket, @object, txn_id, part_no) do |content|
181
+ content << body
182
+ end
183
+
184
+ expect(WebMock).to have_requested(:put, request_path)
185
+ .with(:body => body, :query => query)
186
+ expect(p.number).to eq(part_no)
187
+ expect(p.etag).to eq(return_etag)
188
+ end
189
+
190
+ it "should raise Exception on error" do
191
+ txn_id = 'xxxyyyzzz'
192
+ part_no = 1
193
+ query = {'partNumber' => part_no, 'uploadId' => txn_id}
194
+
195
+ code = 'InvalidArgument'
196
+ message = 'Invalid argument.'
197
+
198
+ stub_request(:put, request_path)
199
+ .with(:query => query)
200
+ .to_return(:status => 400, :body => mock_error(code, message))
201
+
202
+ expect {
203
+ @protocol.upload_part(@bucket, @object, txn_id, part_no) {}
204
+ }.to raise_error(ServerError, err(message))
205
+
206
+ expect(WebMock).to have_requested(:put, request_path)
207
+ .with(:body => nil, :query => query)
208
+ end
209
+
210
+ end # upload part
211
+
212
+ context "Upload part by copy object" do
213
+
214
+ it "should PUT to upload a part by copy object" do
215
+ txn_id = 'xxxyyyzzz'
216
+ part_no = 1
217
+ copy_source = "/#{@bucket}/src_obj"
218
+
219
+ query = {'partNumber' => part_no, 'uploadId' => txn_id}
220
+ headers = {'x-oss-copy-source' => copy_source}
221
+
222
+ stub_request(:put, request_path)
223
+ .with(:query => query, :headers => headers)
224
+
225
+ @protocol.upload_part_by_copy(@bucket, @object, txn_id, part_no, 'src_obj')
226
+
227
+ expect(WebMock).to have_requested(:put, request_path)
228
+ .with(:body => nil, :query => query, :headers => headers)
229
+ end
230
+
231
+ it "should upload a part by copy object from different bucket" do
232
+ txn_id = 'xxxyyyzzz'
233
+ part_no = 1
234
+ src_bucket = 'source-bucket'
235
+ copy_source = "/#{src_bucket}/src_obj"
236
+
237
+ query = {'partNumber' => part_no, 'uploadId' => txn_id}
238
+ headers = {'x-oss-copy-source' => copy_source}
239
+
240
+ stub_request(:put, request_path)
241
+ .with(:query => query, :headers => headers)
242
+
243
+ @protocol.upload_part_by_copy(
244
+ @bucket, @object, txn_id, part_no, 'src_obj', :src_bucket => src_bucket)
245
+
246
+ expect(WebMock).to have_requested(:put, request_path)
247
+ .with(:body => nil, :query => query, :headers => headers)
248
+ end
249
+
250
+ it "should return part etag" do
251
+ txn_id = 'xxxyyyzzz'
252
+ part_no = 1
253
+ copy_source = "/#{@bucket}/src_obj"
254
+
255
+ query = {'partNumber' => part_no, 'uploadId' => txn_id}
256
+ headers = {'x-oss-copy-source' => copy_source}
257
+ return_etag = 'etag_1'
258
+
259
+ stub_request(:put, request_path)
260
+ .with(:query => query, :headers => headers)
261
+ .to_return(:headers => {'ETag' => return_etag})
262
+
263
+ p = @protocol.upload_part_by_copy(@bucket, @object, txn_id, part_no, 'src_obj')
264
+
265
+ expect(WebMock).to have_requested(:put, request_path)
266
+ .with(:body => nil, :query => query, :headers => headers)
267
+ expect(p.number).to eq(part_no)
268
+ expect(p.etag).to eq(return_etag)
269
+ end
270
+
271
+ it "should set range and conditions when copy" do
272
+ txn_id = 'xxxyyyzzz'
273
+ part_no = 1
274
+ copy_source = "/#{@bucket}/src_obj"
275
+
276
+ query = {'partNumber' => part_no, 'uploadId' => txn_id}
277
+ modified_since = Time.now
278
+ unmodified_since = Time.now
279
+ headers = {
280
+ 'Range' => 'bytes=1-4',
281
+ 'x-oss-copy-source' => copy_source,
282
+ 'x-oss-copy-source-if-modified-since' => modified_since.httpdate,
283
+ 'x-oss-copy-source-if-unmodified-since' => unmodified_since.httpdate,
284
+ 'x-oss-copy-source-if-match' => 'me',
285
+ 'x-oss-copy-source-if-none-match' => 'ume'
286
+ }
287
+ return_etag = 'etag_1'
288
+
289
+ stub_request(:put, request_path)
290
+ .with(:query => query, :headers => headers)
291
+ .to_return(:headers => {'ETag' => return_etag})
292
+
293
+ p = @protocol.upload_part_by_copy(
294
+ @bucket, @object, txn_id, part_no, 'src_obj',
295
+ {:range => [1, 5],
296
+ :condition => {
297
+ :if_modified_since => modified_since,
298
+ :if_unmodified_since => unmodified_since,
299
+ :if_match_etag => 'me',
300
+ :if_unmatch_etag => 'ume'
301
+ }})
302
+
303
+ expect(WebMock).to have_requested(:put, request_path)
304
+ .with(:body => nil, :query => query, :headers => headers)
305
+ expect(p.number).to eq(part_no)
306
+ expect(p.etag).to eq(return_etag)
307
+ end
308
+
309
+ it "should raise Exception on error" do
310
+ txn_id = 'xxxyyyzzz'
311
+ part_no = 1
312
+ copy_source = "/#{@bucket}/src_obj"
313
+
314
+ query = {'partNumber' => part_no, 'uploadId' => txn_id}
315
+ headers = {'x-oss-copy-source' => copy_source}
316
+
317
+ code = 'PreconditionFailed'
318
+ message = 'Precondition check failed.'
319
+ stub_request(:put, request_path)
320
+ .with(:query => query, :headers => headers)
321
+ .to_return(:status => 412, :body => mock_error(code, message))
322
+
323
+ expect {
324
+ @protocol.upload_part_by_copy(@bucket, @object, txn_id, part_no, 'src_obj')
325
+ }.to raise_error(ServerError, err(message))
326
+
327
+ expect(WebMock).to have_requested(:put, request_path)
328
+ .with(:body => nil, :query => query, :headers => headers)
329
+ end
330
+ end # upload part by copy object
331
+
332
+ context "Commit multipart" do
333
+
334
+ it "should POST to complete multipart" do
335
+ txn_id = 'xxxyyyzzz'
336
+
337
+ query = {'uploadId' => txn_id}
338
+ parts = (1..5).map do |i|
339
+ Multipart::Part.new(:number => i, :etag => "etag_#{i}")
340
+ end
341
+
342
+ stub_request(:post, request_path).with(:query => query)
343
+
344
+ @protocol.complete_multipart_upload(@bucket, @object, txn_id, parts)
345
+
346
+ parts_body = Nokogiri::XML::Builder.new do |xml|
347
+ xml.CompleteMultipartUpload {
348
+ parts.each do |p|
349
+ xml.Part {
350
+ xml.PartNumber p.number
351
+ xml.ETag p.etag
352
+ }
353
+ end
354
+ }
355
+ end.to_xml
356
+
357
+ expect(WebMock).to have_requested(:post, request_path)
358
+ .with(:body => parts_body, :query => query)
359
+ end
360
+
361
+ it "should raise Exception on error" do
362
+ txn_id = 'xxxyyyzzz'
363
+ query = {'uploadId' => txn_id}
364
+
365
+ code = 'InvalidDigest'
366
+ message = 'Content md5 does not match.'
367
+
368
+ stub_request(:post, request_path)
369
+ .with(:query => query)
370
+ .to_return(:status => 400, :body => mock_error(code, message))
371
+
372
+ expect {
373
+ @protocol.complete_multipart_upload(@bucket, @object, txn_id, [])
374
+ }.to raise_error(ServerError, err(message))
375
+
376
+ expect(WebMock).to have_requested(:post, request_path)
377
+ .with(:query => query)
378
+ end
379
+ end # commit multipart
380
+
381
+ context "Abort multipart" do
382
+
383
+ it "should DELETE to abort multipart" do
384
+ txn_id = 'xxxyyyzzz'
385
+
386
+ query = {'uploadId' => txn_id}
387
+
388
+ stub_request(:delete, request_path).with(:query => query)
389
+
390
+ @protocol.abort_multipart_upload(@bucket, @object, txn_id)
391
+
392
+ expect(WebMock).to have_requested(:delete, request_path)
393
+ .with(:body => nil, :query => query)
394
+ end
395
+
396
+ it "should raise Exception on error" do
397
+ txn_id = 'xxxyyyzzz'
398
+ query = {'uploadId' => txn_id}
399
+
400
+ code = 'NoSuchUpload'
401
+ message = 'The multipart transaction does not exist.'
402
+
403
+ stub_request(:delete, request_path)
404
+ .with(:query => query)
405
+ .to_return(:status => 404, :body => mock_error(code, message))
406
+
407
+ expect {
408
+ @protocol.abort_multipart_upload(@bucket, @object, txn_id)
409
+ }.to raise_error(ServerError, err(message))
410
+
411
+ expect(WebMock).to have_requested(:delete, request_path)
412
+ .with(:body => nil, :query => query)
413
+ end
414
+ end # abort multipart
415
+
416
+ context "List multiparts" do
417
+
418
+ it "should GET to list multiparts" do
419
+ request_path = "#{@bucket}.#{@endpoint}/"
420
+ query = {'uploads' => ''}
421
+
422
+ stub_request(:get, request_path).with(:query => query)
423
+
424
+ @protocol.list_multipart_uploads(@bucket)
425
+
426
+ expect(WebMock).to have_requested(:get, request_path)
427
+ .with(:body => nil, :query => query)
428
+ end
429
+
430
+ it "should send extra params when list multiparts" do
431
+ request_path = "#{@bucket}.#{@endpoint}/"
432
+ query = {
433
+ 'uploads' => '',
434
+ 'prefix' => 'foo-',
435
+ 'upload-id-marker' => 'id-marker',
436
+ 'key-marker' => 'key-marker',
437
+ 'max-uploads' => 10,
438
+ 'encoding-type' => KeyEncoding::URL
439
+ }
440
+
441
+ stub_request(:get, request_path).with(:query => query)
442
+
443
+ @protocol.list_multipart_uploads(
444
+ @bucket,
445
+ :prefix => 'foo-',
446
+ :id_marker => 'id-marker',
447
+ :key_marker => 'key-marker',
448
+ :limit => 10,
449
+ :encoding => KeyEncoding::URL
450
+ )
451
+
452
+ expect(WebMock).to have_requested(:get, request_path)
453
+ .with(:body => nil, :query => query)
454
+ end
455
+
456
+ it "should get multipart transactions" do
457
+ request_path = "#{@bucket}.#{@endpoint}/"
458
+ query = {
459
+ 'uploads' => '',
460
+ 'prefix' => 'foo-',
461
+ 'upload-id-marker' => 'id-marker',
462
+ 'key-marker' => 'key-marker',
463
+ 'max-uploads' => 100,
464
+ 'encoding-type' => KeyEncoding::URL
465
+ }
466
+
467
+ return_multiparts = (1..5).map do |i|
468
+ Multipart::Transaction.new(
469
+ :id => "id-#{i}",
470
+ :object => "key-#{i}",
471
+ :bucket => @bucket,
472
+ :creation_time => Time.parse(Time.now.rfc822))
473
+ end
474
+
475
+ return_more = {
476
+ :prefix => 'foo-',
477
+ :id_marker => 'id-marker',
478
+ :key_marker => 'key-marker',
479
+ :next_id_marker => 'next-id-marker',
480
+ :next_key_marker => 'next-key-marker',
481
+ :limit => 100,
482
+ :truncated => true
483
+ }
484
+ stub_request(:get, request_path)
485
+ .with(:query => query)
486
+ .to_return(:body => mock_multiparts(return_multiparts, return_more))
487
+
488
+ txns, more = @protocol.list_multipart_uploads(
489
+ @bucket,
490
+ :prefix => 'foo-',
491
+ :id_marker => 'id-marker',
492
+ :key_marker => 'key-marker',
493
+ :limit => 100,
494
+ :encoding => KeyEncoding::URL)
495
+
496
+ expect(WebMock).to have_requested(:get, request_path)
497
+ .with(:body => nil, :query => query)
498
+ expect(txns.map {|x| x.to_s}.join(';'))
499
+ .to eq(return_multiparts.map {|x| x.to_s}.join(';'))
500
+ expect(more).to eq(return_more)
501
+ end
502
+
503
+ it "should decode object key" do
504
+ request_path = "#{@bucket}.#{@endpoint}/"
505
+ query = {
506
+ 'uploads' => '',
507
+ 'prefix' => 'foo-',
508
+ 'upload-id-marker' => 'id-marker',
509
+ 'key-marker' => 'key-marker',
510
+ 'max-uploads' => 100,
511
+ 'encoding-type' => KeyEncoding::URL
512
+ }
513
+
514
+ return_multiparts = (1..5).map do |i|
515
+ Multipart::Transaction.new(
516
+ :id => "id-#{i}",
517
+ :object => "中国-#{i}",
518
+ :bucket => @bucket,
519
+ :creation_time => Time.parse(Time.now.rfc822))
520
+ end
521
+
522
+ es_multiparts = return_multiparts.map do |x|
523
+ Multipart::Transaction.new(
524
+ :id => x.id,
525
+ :object => CGI.escape(x.object),
526
+ :creation_time => x.creation_time)
527
+ end
528
+
529
+ return_more = {
530
+ :prefix => 'foo-',
531
+ :id_marker => 'id-marker',
532
+ :key_marker => '杭州のruby',
533
+ :next_id_marker => 'next-id-marker',
534
+ :next_key_marker => '西湖のruby',
535
+ :limit => 100,
536
+ :truncated => true,
537
+ :encoding => KeyEncoding::URL
538
+ }
539
+
540
+ es_more = {
541
+ :prefix => 'foo-',
542
+ :id_marker => 'id-marker',
543
+ :key_marker => CGI.escape('杭州のruby'),
544
+ :next_id_marker => 'next-id-marker',
545
+ :next_key_marker => CGI.escape('西湖のruby'),
546
+ :limit => 100,
547
+ :truncated => true,
548
+ :encoding => KeyEncoding::URL
549
+ }
550
+
551
+ stub_request(:get, request_path)
552
+ .with(:query => query)
553
+ .to_return(:body => mock_multiparts(es_multiparts, es_more))
554
+
555
+ txns, more = @protocol.list_multipart_uploads(
556
+ @bucket,
557
+ :prefix => 'foo-',
558
+ :id_marker => 'id-marker',
559
+ :key_marker => 'key-marker',
560
+ :limit => 100,
561
+ :encoding => KeyEncoding::URL)
562
+
563
+ expect(WebMock).to have_requested(:get, request_path)
564
+ .with(:body => nil, :query => query)
565
+ expect(txns.map {|x| x.to_s}.join(';'))
566
+ .to eq(return_multiparts.map {|x| x.to_s}.join(';'))
567
+ expect(more).to eq(return_more)
568
+ end
569
+
570
+ it "should raise Exception on error" do
571
+ request_path = "#{@bucket}.#{@endpoint}/"
572
+ query = {'uploads' => ''}
573
+
574
+ code = 'InvalidArgument'
575
+ message = 'Invalid argument.'
576
+ stub_request(:get, request_path)
577
+ .with(:query => query)
578
+ .to_return(:status => 400, :body => mock_error(code, message))
579
+
580
+ expect {
581
+ @protocol.list_multipart_uploads(@bucket)
582
+ }.to raise_error(ServerError, err(message))
583
+
584
+ expect(WebMock).to have_requested(:get, request_path)
585
+ .with(:body => nil, :query => query)
586
+ end
587
+ end # list multiparts
588
+
589
+ context "List parts" do
590
+
591
+ it "should GET to list parts" do
592
+ txn_id = 'yyyxxxzzz'
593
+ query = {'uploadId' => txn_id}
594
+
595
+ stub_request(:get, request_path).with(:query => query)
596
+
597
+ @protocol.list_parts(@bucket, @object, txn_id)
598
+
599
+ expect(WebMock).to have_requested(:get, request_path)
600
+ .with(:body => nil, :query => query)
601
+ end
602
+
603
+ it "should send extra params when list parts" do
604
+ txn_id = 'yyyxxxzzz'
605
+ query = {
606
+ 'uploadId' => txn_id,
607
+ 'part-number-marker' => 'foo-',
608
+ 'max-parts' => 100,
609
+ 'encoding-type' => KeyEncoding::URL
610
+ }
611
+
612
+ stub_request(:get, request_path).with(:query => query)
613
+
614
+ @protocol.list_parts(@bucket, @object, txn_id,
615
+ :marker => 'foo-',
616
+ :limit => 100,
617
+ :encoding => KeyEncoding::URL)
618
+
619
+ expect(WebMock).to have_requested(:get, request_path)
620
+ .with(:body => nil, :query => query)
621
+ end
622
+
623
+ it "should get parts" do
624
+ txn_id = 'yyyxxxzzz'
625
+ query = {
626
+ 'uploadId' => txn_id,
627
+ 'part-number-marker' => 'foo-',
628
+ 'max-parts' => 100,
629
+ 'encoding-type' => KeyEncoding::URL
630
+ }
631
+
632
+ return_parts = (1..5).map do |i|
633
+ Multipart::Part.new(
634
+ :number => i,
635
+ :etag => "etag-#{i}",
636
+ :size => 1024,
637
+ :last_modified => Time.parse(Time.now.rfc822))
638
+ end
639
+
640
+ return_more = {
641
+ :marker => 'foo-',
642
+ :next_marker => 'bar-',
643
+ :limit => 100,
644
+ :truncated => true
645
+ }
646
+
647
+ stub_request(:get, request_path)
648
+ .with(:query => query)
649
+ .to_return(:body => mock_parts(return_parts, return_more))
650
+
651
+ parts, more = @protocol.list_parts(@bucket, @object, txn_id,
652
+ :marker => 'foo-',
653
+ :limit => 100,
654
+ :encoding => KeyEncoding::URL)
655
+
656
+ expect(WebMock).to have_requested(:get, request_path)
657
+ .with(:body => nil, :query => query)
658
+ part_numbers = return_parts.map {|x| x.number}
659
+ expect(parts.map {|x| x.number}).to match_array(part_numbers)
660
+ expect(more).to eq(return_more)
661
+ end
662
+
663
+ it "should raise Exception on error" do
664
+ txn_id = 'yyyxxxzzz'
665
+ query = {'uploadId' => txn_id}
666
+
667
+ code = 'InvalidArgument'
668
+ message = 'Invalid argument.'
669
+
670
+ stub_request(:get, request_path)
671
+ .with(:query => query)
672
+ .to_return(:status => 400, :body => mock_error(code, message))
673
+
674
+ expect {
675
+ @protocol.list_parts(@bucket, @object, txn_id)
676
+ }.to raise_error(ServerError, err(message))
677
+
678
+ expect(WebMock).to have_requested(:get, request_path)
679
+ .with(:body => nil, :query => query)
680
+ end
681
+ end # list parts
682
+
683
+ end # Multipart
684
+
685
+ end # OSS
686
+ end # Aliyun