aliyun-oss-ruby-sdk 0.4.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.
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