aliyun-sdk 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,9 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ module Aliyun
4
+ module OSS
5
+
6
+ VERSION = "0.1.1"
7
+
8
+ end # OSS
9
+ end # Aliyun
@@ -0,0 +1,595 @@
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.aliyuncs.com'
14
+ @protocol = Protocol.new(
15
+ Config.new(:endpoint => @endpoint,
16
+ :access_key_id => 'xxx', :access_key_secret => 'yyy'))
17
+ @bucket = 'rubysdk-bucket'
18
+ end
19
+
20
+ def request_path
21
+ @bucket + "." + @endpoint
22
+ end
23
+
24
+ def mock_location(location)
25
+ Nokogiri::XML::Builder.new do |xml|
26
+ xml.CreateBucketConfiguration {
27
+ xml.LocationConstraint location
28
+ }
29
+ end.to_xml
30
+ end
31
+
32
+ def mock_objects(objects, more = {})
33
+ Nokogiri::XML::Builder.new do |xml|
34
+ xml.ListBucketResult {
35
+ {
36
+ :prefix => 'Prefix',
37
+ :delimiter => 'Delimiter',
38
+ :limit => 'MaxKeys',
39
+ :marker => 'Marker',
40
+ :next_marker => 'NextMarker',
41
+ :truncated => 'IsTruncated',
42
+ :encoding => 'EncodingType'
43
+ }.map do |k, v|
44
+ xml.send(v, more[k]) if more[k]
45
+ end
46
+
47
+ objects.each do |o|
48
+ xml.Contents {
49
+ xml.Key o
50
+ xml.LastModified Time.now.to_s
51
+ xml.Type 'Normal'
52
+ xml.Size 1024
53
+ xml.StorageClass 'Standard'
54
+ xml.Etag 'etag'
55
+ xml.Owner {
56
+ xml.ID '10086'
57
+ xml.DisplayName 'CMCC'
58
+ }
59
+ }
60
+ end
61
+
62
+ (more[:common_prefixes] || []).each do |p|
63
+ xml.CommonPrefixes {
64
+ xml.Prefix p
65
+ }
66
+ end
67
+ }
68
+ end.to_xml
69
+ end
70
+
71
+ def mock_acl(acl)
72
+ Nokogiri::XML::Builder.new do |xml|
73
+ xml.AccessControlPolicy {
74
+ xml.Owner {
75
+ xml.ID 'owner_id'
76
+ xml.DisplayName 'owner_name'
77
+ }
78
+
79
+ xml.AccessControlList {
80
+ xml.Grant acl
81
+ }
82
+ }
83
+ end.to_xml
84
+ end
85
+
86
+ def mock_logging(opts)
87
+ Nokogiri::XML::Builder.new do |xml|
88
+ xml.BucketLoggingStatus {
89
+ if opts.enabled?
90
+ xml.LoggingEnabled {
91
+ xml.TargetBucket opts.target_bucket
92
+ xml.TargetPrefix opts.target_prefix
93
+ }
94
+ end
95
+ }
96
+ end.to_xml
97
+ end
98
+
99
+ def mock_website(opts)
100
+ Nokogiri::XML::Builder.new do |xml|
101
+ xml.WebsiteConfiguration {
102
+ xml.IndexDocument {
103
+ xml.Suffix opts.index
104
+ }
105
+ if opts.error
106
+ xml.ErrorDocument {
107
+ xml.Key opts.error
108
+ }
109
+ end
110
+ }
111
+ end.to_xml
112
+ end
113
+
114
+ def mock_referer(opts)
115
+ Nokogiri::XML::Builder.new do |xml|
116
+ xml.RefererConfiguration {
117
+ xml.AllowEmptyReferer opts.allow_empty?
118
+ xml.RefererList {
119
+ opts.whitelist.each do |r|
120
+ xml.Referer r
121
+ end
122
+ }
123
+ }
124
+ end.to_xml
125
+ end
126
+
127
+ def mock_lifecycle(rules)
128
+ Nokogiri::XML::Builder.new do |xml|
129
+ xml.LifecycleConfiguration {
130
+ rules.each do |r|
131
+ xml.Rule {
132
+ xml.ID r.id if r.id
133
+ xml.Status r.enabled? ? 'Enabled' : 'Disabled'
134
+ xml.Prefix r.prefix
135
+ xml.Expiration {
136
+ if r.expiry.is_a?(Date)
137
+ xml.Date Time.utc(r.expiry.year, r.expiry.month, r.expiry.day)
138
+ .iso8601.sub('Z', '.000Z')
139
+ else
140
+ xml.Days r.expiry.to_i
141
+ end
142
+ }
143
+ }
144
+ end
145
+ }
146
+ end.to_xml
147
+ end
148
+
149
+ def mock_cors(rules)
150
+ Nokogiri::XML::Builder.new do |xml|
151
+ xml.CORSConfiguration {
152
+ rules.each do |r|
153
+ xml.CORSRule {
154
+ r.allowed_origins.each do |x|
155
+ xml.AllowedOrigin x
156
+ end
157
+ r.allowed_methods.each do |x|
158
+ xml.AllowedMethod x
159
+ end
160
+ r.allowed_headers.each do |x|
161
+ xml.AllowedHeader x
162
+ end
163
+ r.expose_headers.each do |x|
164
+ xml.ExposeHeader x
165
+ end
166
+ xml.MaxAgeSeconds r.max_age_seconds if r.max_age_seconds
167
+ }
168
+ end
169
+ }
170
+ end.to_xml
171
+ end
172
+
173
+ def mock_error(code, message)
174
+ builder = Nokogiri::XML::Builder.new do |xml|
175
+ xml.Error {
176
+ xml.Code code
177
+ xml.Message message
178
+ xml.RequestId '0000'
179
+ }
180
+ end
181
+
182
+ builder.to_xml
183
+ end
184
+
185
+ context "Create bucket" do
186
+
187
+ it "should PUT to create bucket" do
188
+ stub_request(:put, request_path)
189
+
190
+ @protocol.create_bucket(@bucket)
191
+
192
+ expect(WebMock).to have_requested(:put, request_path)
193
+ .with(:body => nil, :query => {})
194
+ end
195
+
196
+ it "should set location when create bucket" do
197
+ location = 'oss-cn-hangzhou'
198
+
199
+ stub_request(:put, request_path).with(:body => mock_location(location))
200
+
201
+ @protocol.create_bucket(@bucket, :location => 'oss-cn-hangzhou')
202
+
203
+ expect(WebMock).to have_requested(:put, request_path)
204
+ .with(:body => mock_location(location), :query => {})
205
+ end
206
+ end # create bucket
207
+
208
+ context "List objects" do
209
+
210
+ it "should list all objects" do
211
+ stub_request(:get, request_path)
212
+
213
+ @protocol.list_objects(@bucket)
214
+
215
+ expect(WebMock).to have_requested(:get, request_path)
216
+ .with(:body => nil, :query => {})
217
+ end
218
+
219
+ it "should parse object response" do
220
+ return_objects = ['hello', 'world', 'foo/bar']
221
+ stub_request(:get, request_path)
222
+ .to_return(:body => mock_objects(return_objects))
223
+
224
+ objects, more = @protocol.list_objects(@bucket)
225
+
226
+ expect(WebMock).to have_requested(:get, request_path)
227
+ .with(:body => nil, :query => {})
228
+
229
+ expect(objects.map {|o| o.key}).to match_array(return_objects)
230
+ expect(more).to be_empty
231
+ end
232
+
233
+ it "should list objects with prefix & delimiter" do
234
+ # Webmock cannot capture the request_path encoded query parameters,
235
+ # so we use 'foo-bar' instead of 'foo/bar' to work around
236
+ # the problem
237
+ opts = {
238
+ :marker => 'foo-bar',
239
+ :prefix => 'foo-',
240
+ :delimiter => '-',
241
+ :limit => 10,
242
+ :encoding => KeyEncoding::URL}
243
+
244
+ query = opts.clone
245
+ query['max-keys'] = query.delete(:limit)
246
+ query['encoding-type'] = query.delete(:encoding)
247
+
248
+ stub_request(:get, request_path).with(:query => query)
249
+
250
+ @protocol.list_objects(@bucket, opts)
251
+
252
+ expect(WebMock).to have_requested(:get, request_path)
253
+ .with(:body => "", :query => query)
254
+ end
255
+
256
+ it "should parse object and common prefixes response" do
257
+ return_objects = ['hello', 'world', 'foo-bar']
258
+ return_more = {
259
+ :marker => 'foo-bar',
260
+ :prefix => 'foo-',
261
+ :delimiter => '-',
262
+ :limit => 10,
263
+ :encoding => KeyEncoding::URL,
264
+ :next_marker => 'foo-xxx',
265
+ :truncated => true,
266
+ :common_prefixes => ['foo/bar/', 'foo/xxx/']
267
+ }
268
+
269
+ opts = {
270
+ :marker => 'foo-bar',
271
+ :prefix => 'foo-',
272
+ :delimiter => '-',
273
+ :limit => 10,
274
+ :encoding => KeyEncoding::URL
275
+ }
276
+
277
+ query = opts.clone
278
+ query['max-keys'] = query.delete(:limit)
279
+ query['encoding-type'] = query.delete(:encoding)
280
+
281
+ stub_request(:get, request_path).with(:query => query).
282
+ to_return(:body => mock_objects(return_objects, return_more))
283
+
284
+ objects, more = @protocol.list_objects(@bucket, opts)
285
+
286
+ expect(WebMock).to have_requested(:get, request_path)
287
+ .with(:body => nil, :query => query)
288
+
289
+ expect(objects.map {|o| o.key}).to match_array(return_objects)
290
+ expect(more).to eq(return_more)
291
+ end
292
+
293
+ it "should decode object key" do
294
+ return_objects = ['中国のruby', 'world', 'foo/bar']
295
+ return_more = {
296
+ :marker => '杭州のruby',
297
+ :prefix => 'foo-',
298
+ :delimiter => '分隔のruby',
299
+ :limit => 10,
300
+ :encoding => KeyEncoding::URL,
301
+ :next_marker => '西湖のruby',
302
+ :truncated => true,
303
+ :common_prefixes => ['玉泉のruby', '苏堤のruby']
304
+ }
305
+
306
+ es_objects = [CGI.escape('中国のruby'), 'world', 'foo/bar']
307
+ es_more = {
308
+ :marker => CGI.escape('杭州のruby'),
309
+ :prefix => 'foo-',
310
+ :delimiter => CGI.escape('分隔のruby'),
311
+ :limit => 10,
312
+ :encoding => KeyEncoding::URL,
313
+ :next_marker => CGI.escape('西湖のruby'),
314
+ :truncated => true,
315
+ :common_prefixes => [CGI.escape('玉泉のruby'), CGI.escape('苏堤のruby')]
316
+ }
317
+
318
+ stub_request(:get, request_path)
319
+ .to_return(:body => mock_objects(es_objects, es_more))
320
+
321
+ objects, more = @protocol.list_objects(@bucket)
322
+
323
+ expect(WebMock).to have_requested(:get, request_path)
324
+ .with(:body => nil, :query => {})
325
+
326
+ expect(objects.map {|o| o.key}).to match_array(return_objects)
327
+ expect(more).to eq(return_more)
328
+ end
329
+ end # list objects
330
+
331
+ context "Delete bucket" do
332
+
333
+ it "should send DELETE reqeust" do
334
+ stub_request(:delete, request_path)
335
+
336
+ @protocol.delete_bucket(@bucket)
337
+
338
+ expect(WebMock).to have_requested(:delete, request_path)
339
+ .with(:body => nil, :query => {})
340
+ end
341
+
342
+ it "should raise Exception on error" do
343
+ code = "NoSuchBucket"
344
+ message = "The bucket to delete does not exist."
345
+
346
+ stub_request(:delete, request_path).to_return(
347
+ :status => 404, :body => mock_error(code, message))
348
+
349
+ expect {
350
+ @protocol.delete_bucket(@bucket)
351
+ }.to raise_error(Exception, message)
352
+ end
353
+ end # delete bucket
354
+
355
+ context "acl, logging, website, referer, lifecycle" do
356
+ it "should update acl" do
357
+ query = {'acl' => ''}
358
+ stub_request(:put, request_path).with(:query => query)
359
+
360
+ @protocol.put_bucket_acl(@bucket, ACL::PUBLIC_READ)
361
+
362
+ expect(WebMock).to have_requested(:put, request_path)
363
+ .with(:query => query, :body => nil)
364
+ end
365
+
366
+ it "should get acl" do
367
+ query = {'acl' => ''}
368
+ return_acl = ACL::PUBLIC_READ
369
+ stub_request(:get, request_path)
370
+ .with(:query => query)
371
+ .to_return(:body => mock_acl(return_acl))
372
+
373
+ acl = @protocol.get_bucket_acl(@bucket)
374
+
375
+ expect(WebMock).to have_requested(:get, request_path)
376
+ .with(:query => query, :body => nil)
377
+ expect(acl).to eq(return_acl)
378
+ end
379
+
380
+ it "should enable logging" do
381
+ query = {'logging' => ''}
382
+ stub_request(:put, request_path).with(:query => query)
383
+
384
+ logging_opts = BucketLogging.new(
385
+ :enable => true,
386
+ :target_bucket => 'target-bucket', :target_prefix => 'foo')
387
+ @protocol.put_bucket_logging(@bucket, logging_opts)
388
+
389
+ expect(WebMock).to have_requested(:put, request_path)
390
+ .with(:query => query, :body => mock_logging(logging_opts))
391
+ end
392
+
393
+ it "should disable logging" do
394
+ query = {'logging' => ''}
395
+ stub_request(:put, request_path).with(:query => query)
396
+
397
+ logging_opts = BucketLogging.new(:enable => false)
398
+ @protocol.put_bucket_logging(@bucket, logging_opts)
399
+
400
+ expect(WebMock).to have_requested(:put, request_path)
401
+ .with(:query => query, :body => mock_logging(logging_opts))
402
+ end
403
+
404
+ it "should get logging" do
405
+ query = {'logging' => ''}
406
+ logging_opts = BucketLogging.new(
407
+ :enable => true,
408
+ :target_bucket => 'target-bucket', :target_prefix => 'foo')
409
+
410
+ stub_request(:get, request_path)
411
+ .with(:query => query)
412
+ .to_return(:body => mock_logging(logging_opts))
413
+
414
+ logging = @protocol.get_bucket_logging(@bucket)
415
+
416
+ expect(WebMock).to have_requested(:get, request_path)
417
+ .with(:query => query, :body => nil)
418
+ expect(logging.to_s).to eq(logging_opts.to_s)
419
+ end
420
+
421
+ it "should delete logging" do
422
+ query = {'logging' => ''}
423
+ stub_request(:delete, request_path).with(:query => query)
424
+
425
+ @protocol.delete_bucket_logging(@bucket)
426
+
427
+ expect(WebMock).to have_requested(:delete, request_path)
428
+ .with(:query => query, :body => nil)
429
+ end
430
+
431
+ it "should update website" do
432
+ query = {'website' => ''}
433
+ stub_request(:put, request_path).with(:query => query)
434
+
435
+ website_opts = BucketWebsite.new(
436
+ :enable => true, :index => 'index.html', :error => 'error.html')
437
+ @protocol.put_bucket_website(@bucket, website_opts)
438
+
439
+ expect(WebMock).to have_requested(:put, request_path)
440
+ .with(:query => query, :body => mock_website(website_opts))
441
+ end
442
+
443
+ it "should get website" do
444
+ query = {'website' => ''}
445
+ website_opts = BucketWebsite.new(
446
+ :enable => true, :index => 'index.html', :error => 'error.html')
447
+
448
+ stub_request(:get, request_path)
449
+ .with(:query => query)
450
+ .to_return(:body => mock_website(website_opts))
451
+
452
+ opts = @protocol.get_bucket_website(@bucket)
453
+
454
+ expect(WebMock).to have_requested(:get, request_path)
455
+ .with(:query => query, :body => nil)
456
+ expect(opts.to_s).to eq(website_opts.to_s)
457
+ end
458
+
459
+ it "should delete website" do
460
+ query = {'website' => ''}
461
+ stub_request(:delete, request_path).with(:query => query)
462
+
463
+ @protocol.delete_bucket_website(@bucket)
464
+
465
+ expect(WebMock).to have_requested(:delete, request_path)
466
+ .with(:query => query, :body => nil)
467
+ end
468
+
469
+ it "should update referer" do
470
+ query = {'referer' => ''}
471
+ stub_request(:put, request_path).with(:query => query)
472
+
473
+ referer_opts = BucketReferer.new(
474
+ :allow_empty => true, :whitelist => ['xxx', 'yyy'])
475
+ @protocol.put_bucket_referer(@bucket, referer_opts)
476
+
477
+ expect(WebMock).to have_requested(:put, request_path)
478
+ .with(:query => query, :body => mock_referer(referer_opts))
479
+ end
480
+
481
+ it "should get referer" do
482
+ query = {'referer' => ''}
483
+ referer_opts = BucketReferer.new(
484
+ :allow_empty => true, :whitelist => ['xxx', 'yyy'])
485
+
486
+ stub_request(:get, request_path)
487
+ .with(:query => query)
488
+ .to_return(:body => mock_referer(referer_opts))
489
+
490
+ opts = @protocol.get_bucket_referer(@bucket)
491
+
492
+ expect(WebMock).to have_requested(:get, request_path)
493
+ .with(:query => query, :body => nil)
494
+ expect(opts.to_s).to eq(referer_opts.to_s)
495
+ end
496
+
497
+ it "should update lifecycle" do
498
+ query = {'lifecycle' => ''}
499
+ stub_request(:put, request_path).with(:query => query)
500
+
501
+ rules = (1..5).map do |i|
502
+ LifeCycleRule.new(
503
+ :id => i, :enable => i % 2 == 0, :prefix => "foo#{i}",
504
+ :expiry => (i % 2 == 1 ? Date.today : 10 + i))
505
+ end
506
+
507
+ @protocol.put_bucket_lifecycle(@bucket, rules)
508
+
509
+ expect(WebMock).to have_requested(:put, request_path)
510
+ .with(:query => query, :body => mock_lifecycle(rules))
511
+ end
512
+
513
+ it "should get lifecycle" do
514
+ query = {'lifecycle' => ''}
515
+ return_rules = (1..5).map do |i|
516
+ LifeCycleRule.new(
517
+ :id => i, :enable => i % 2 == 0, :prefix => "foo#{i}",
518
+ :expiry => (i % 2 == 1 ? Date.today : 10 + i))
519
+ end
520
+
521
+ stub_request(:get, request_path)
522
+ .with(:query => query)
523
+ .to_return(:body => mock_lifecycle(return_rules))
524
+
525
+ rules = @protocol.get_bucket_lifecycle(@bucket)
526
+
527
+ expect(WebMock).to have_requested(:get, request_path)
528
+ .with(:query => query, :body => nil)
529
+ expect(rules.map(&:to_s)).to match_array(return_rules.map(&:to_s))
530
+ end
531
+
532
+ it "should delete lifecycle" do
533
+ query = {'lifecycle' => ''}
534
+ stub_request(:delete, request_path).with(:query => query)
535
+
536
+ @protocol.delete_bucket_lifecycle(@bucket)
537
+
538
+ expect(WebMock).to have_requested(:delete, request_path)
539
+ .with(:query => query, :body => nil)
540
+ end
541
+
542
+ it "should set cors" do
543
+ query = {'cors' => ''}
544
+ stub_request(:put, request_path).with(:query => query)
545
+
546
+ rules = (1..5).map do |i|
547
+ CORSRule.new(
548
+ :allowed_origins => (1..3).map {|x| "origin-#{x}"},
549
+ :allowed_methods => ['PUT', 'GET'],
550
+ :allowed_headers => (1..3).map {|x| "header-#{x}"},
551
+ :expose_headers => (1..3).map {|x| "header-#{x}"})
552
+ end
553
+ @protocol.set_bucket_cors(@bucket, rules)
554
+
555
+ expect(WebMock).to have_requested(:put, request_path)
556
+ .with(:query => query, :body => mock_cors(rules))
557
+ end
558
+
559
+ it "should get cors" do
560
+ query = {'cors' => ''}
561
+ return_rules = (1..5).map do |i|
562
+ CORSRule.new(
563
+ :allowed_origins => (1..3).map {|x| "origin-#{x}"},
564
+ :allowed_methods => ['PUT', 'GET'],
565
+ :allowed_headers => (1..3).map {|x| "header-#{x}"},
566
+ :expose_headers => (1..3).map {|x| "header-#{x}"})
567
+ end
568
+
569
+ stub_request(:get, request_path)
570
+ .with(:query => query)
571
+ .to_return(:body => mock_cors(return_rules))
572
+
573
+ rules = @protocol.get_bucket_cors(@bucket)
574
+
575
+ expect(WebMock).to have_requested(:get, request_path)
576
+ .with(:query => query, :body => nil)
577
+ expect(rules.map(&:to_s)).to match_array(return_rules.map(&:to_s))
578
+ end
579
+
580
+ it "should delete cors" do
581
+ query = {'cors' => ''}
582
+
583
+ stub_request(:delete, request_path).with(:query => query)
584
+
585
+ @protocol.delete_bucket_cors(@bucket)
586
+ expect(WebMock).to have_requested(:delete, request_path)
587
+ .with(:query => query, :body => nil)
588
+ end
589
+
590
+ end # acl, logging, cors, etc
591
+
592
+ end # Bucket
593
+
594
+ end # OSS
595
+ end # Aliyun