aliyunoss 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.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +22 -0
- data/README.md +92 -0
- data/Rakefile +8 -0
- data/aliyunoss.gemspec +24 -0
- data/lib/aliyunoss/api.rb +222 -0
- data/lib/aliyunoss/bucket.rb +131 -0
- data/lib/aliyunoss/config.rb +47 -0
- data/lib/aliyunoss/extension.rb +34 -0
- data/lib/aliyunoss/helper.rb +27 -0
- data/lib/aliyunoss/http_response_extension.rb +66 -0
- data/lib/aliyunoss/oss_request.rb +143 -0
- data/lib/aliyunoss/version.rb +5 -0
- data/lib/aliyunoss.rb +12 -0
- data/spec/aliyunoss/aliyun-config.yml.sample +2 -0
- data/spec/aliyunoss/api_spec.rb +123 -0
- data/spec/aliyunoss/bucket_spec.rb +109 -0
- data/spec/aliyunoss/config_spec.rb +47 -0
- data/spec/aliyunoss/incorrect-config.yml +4 -0
- data/spec/aliyunoss/multipart_api_spec.rb +103 -0
- data/spec/aliyunoss/oss_request_spec.rb +51 -0
- data/spec/aliyunoss/test-1.png +0 -0
- data/spec/aliyunoss/test-2.png +0 -0
- data/spec/aliyunoss/test-3.png +0 -0
- metadata +121 -0
@@ -0,0 +1,66 @@
|
|
1
|
+
module Net
|
2
|
+
|
3
|
+
class HTTPResponse
|
4
|
+
|
5
|
+
def raise_if_not(status)
|
6
|
+
raise message unless status === self
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_buckets
|
10
|
+
raise message unless Net::HTTPOK === self
|
11
|
+
nodes = Nokogiri::XML(self.body).xpath('//Bucket') rescue []
|
12
|
+
nodes.map do |node|
|
13
|
+
bucket = Aliyun::Oss::Bucket.new
|
14
|
+
node.elements.each {|e| bucket.send("#{e.name.underscore}=".to_sym, e.content)}
|
15
|
+
bucket
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_objects
|
20
|
+
raise message unless Net::HTTPOK === self
|
21
|
+
nodes = Nokogiri::XML(self.body).xpath('//Contents') rescue []
|
22
|
+
nodes.map do |node|
|
23
|
+
hash = Hash.new
|
24
|
+
node.elements.each {|e| hash[e.name.underscore] = e.content unless e.name == 'Owner' }
|
25
|
+
hash
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_logging_status
|
30
|
+
raise message unless Net::HTTPOK === self
|
31
|
+
node = Nokogiri::XML(self.body).xpath('//LoggingEnabled') rescue []
|
32
|
+
hash = Hash.new
|
33
|
+
node[0].elements.each {|e| hash[e.name.underscore] = e.content }
|
34
|
+
hash
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_website_status
|
38
|
+
raise message unless Net::HTTPOK === self
|
39
|
+
xml = Nokogiri::XML(self.body)
|
40
|
+
{'index_page' => xml.xpath('//Suffix')[0].content, 'error_page' => xml.xpath('//Key')[0].content } rescue {}
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_acl_status
|
44
|
+
raise message unless Net::HTTPOK === self
|
45
|
+
Nokogiri::XML(self.body).xpath('//Grant')[0].content
|
46
|
+
end
|
47
|
+
|
48
|
+
def to_multipart_id
|
49
|
+
raise message unless Net::HTTPOK === self
|
50
|
+
Nokogiri::XML(body).xpath('//UploadId').first.content
|
51
|
+
end
|
52
|
+
|
53
|
+
def to_mutlipart_task
|
54
|
+
raise message unless Net::HTTPOK === self
|
55
|
+
tasks = Array.new
|
56
|
+
nodes = Nokogiri::XML(response.body).xpath('//Upload')
|
57
|
+
nodes.each do |node|
|
58
|
+
path = '/' + node.xpath('Key').first.content
|
59
|
+
id = node.xpath('UploadId').first.content
|
60
|
+
tasks << {'path'=> path, 'upload_id' => id}
|
61
|
+
end
|
62
|
+
tasks
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require 'base64'
|
3
|
+
require 'openssl'
|
4
|
+
|
5
|
+
module Aliyun
|
6
|
+
module Oss
|
7
|
+
|
8
|
+
class OssRequest
|
9
|
+
|
10
|
+
include ConfigHelper
|
11
|
+
attr_accessor :bucket, :path, :body, :queris
|
12
|
+
|
13
|
+
def initialize(bucket, path, queries = {}, headers = {})
|
14
|
+
@bucket = bucket
|
15
|
+
@path = path
|
16
|
+
@queries = queries
|
17
|
+
@headers = {"Content-Type" => "", "Content-MD5" => "", "Date" => Time.now.utc.strftime('%a, %d %b %Y %H:%M:%S GMT')}.merge(headers)
|
18
|
+
end
|
19
|
+
|
20
|
+
def get_uri
|
21
|
+
if @bucket
|
22
|
+
uri = URI("http://#{bucket.name}.#{bucket.location}.#{host}")
|
23
|
+
else
|
24
|
+
uri = URI("http://oss.#{host}")
|
25
|
+
end
|
26
|
+
uri.path = @path
|
27
|
+
uri.query = @queries.to_query_string if @queries.count > 0
|
28
|
+
uri
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.add_operation(verb)
|
32
|
+
define_method(verb) do
|
33
|
+
uri = get_uri
|
34
|
+
|
35
|
+
request = Net::HTTP.send(:const_get, verb.to_s.capitalize).new(uri)
|
36
|
+
|
37
|
+
@headers.each_pair {|k,v| request[k] = v}
|
38
|
+
|
39
|
+
if @body
|
40
|
+
request.body = @body
|
41
|
+
digest = OpenSSL::Digest::MD5.digest(@body)
|
42
|
+
request['Content-MD5'] = Base64.encode64(digest).strip
|
43
|
+
request['Content-Length'] = @body.bytesize
|
44
|
+
end
|
45
|
+
|
46
|
+
request['Authorization'] = 'OSS ' + access_key_id + ':' +
|
47
|
+
signature(request)
|
48
|
+
|
49
|
+
logger.info(verb.to_s.upcase + ' ' + uri.to_s + ' ' + request.to_hash.to_s)
|
50
|
+
|
51
|
+
response = nil
|
52
|
+
Net::HTTP.start(uri.host, uri.port) do |http|
|
53
|
+
response = http.request(request)
|
54
|
+
logger.info(response.code.to_s + ' ' + response.message)
|
55
|
+
logger.debug(response.body)
|
56
|
+
end
|
57
|
+
response
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
add_operation :get
|
62
|
+
add_operation :put
|
63
|
+
add_operation :delete
|
64
|
+
add_operation :head
|
65
|
+
add_operation :post
|
66
|
+
|
67
|
+
def url_for_sharing(expires)
|
68
|
+
raise "not implemented"
|
69
|
+
end
|
70
|
+
|
71
|
+
def [](key)
|
72
|
+
@headers[key]
|
73
|
+
end
|
74
|
+
|
75
|
+
def []=(key, value)
|
76
|
+
@headers[key] = value
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
def signature(req)
|
81
|
+
verb = req.class.to_s.gsub(/Net::HTTP::/, '').upcase
|
82
|
+
data = verb + "\n" + req["Content-MD5"] + "\n" +
|
83
|
+
req["Content-Type"] + "\n" + req["Date"] + "\n" +
|
84
|
+
canonicalized_oss_headers(req) +
|
85
|
+
canonicalized_resource()
|
86
|
+
|
87
|
+
digest = OpenSSL::Digest.new('sha1')
|
88
|
+
hmac = OpenSSL::HMAC.digest(digest, access_key_secret, data)
|
89
|
+
Base64.encode64(hmac).strip
|
90
|
+
end
|
91
|
+
|
92
|
+
# oss api 20140828.pdf - 4.2
|
93
|
+
# 1) 将所有以“x-oss-”为前缀的 HTTP 请求头的名字转换成小写字母。如 ’X-OSS-Meta-Name: TaoBao’
|
94
|
+
# 转换成 ’x-oss-meta-name: TaoBao’ 。
|
95
|
+
# 2) 将上一步得到的所有 HTTP 请求头按照字典序进行升序排列。
|
96
|
+
# 3) 如果有相同名字的请求头,则根据标准 RFC 2616, 4.2 章进行合并(两个值之间只用逗号分隔)。
|
97
|
+
# 如有两个名为’x-oss-meta-name’的请求头,对应的值分别为’TaoBao’和’Alipay’,则合并后
|
98
|
+
# 为: ’x-oss-meta-name:TaoBao,Alipay’ 。
|
99
|
+
# 4) 删除请求头和内容之间分隔符两端出现的任何空格。
|
100
|
+
# 如 ’x-oss-meta-name: TaoBao,Alipay’ 转换成: ’x-oss-meta-name:TaoBao,Alipay’ 。
|
101
|
+
# 5) 将所有的头和内容用 ’\n’ 分隔符分隔拼成最后的 CanonicalizedOSSHeader 。
|
102
|
+
def canonicalized_oss_headers(req)
|
103
|
+
hash = Hash.new
|
104
|
+
req.each_header do |header|
|
105
|
+
header = header.downcase
|
106
|
+
next unless header.start_with?('x-oss-')
|
107
|
+
if hash.has_key?(header)
|
108
|
+
hash[header] = hash[header] + "," + req[header].strip
|
109
|
+
else
|
110
|
+
hash[header] = req[header].strip
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
return "" if hash.count == 0
|
115
|
+
|
116
|
+
array = Array.new
|
117
|
+
hash.each_pair {|k,v| array << k + ":" + v }
|
118
|
+
array.sort.join("\n") << "\n"
|
119
|
+
end
|
120
|
+
|
121
|
+
# oss api 20140828.pdf - 4.2
|
122
|
+
# 1) 将 CanonicalizedResource 置成空字符串( “” );
|
123
|
+
# 2) 放入要访问的 OSS 资源:“ /BucketName/ObjectName ”(无 ObjectName 则不填)
|
124
|
+
# 3) 如果请求的资源包括子资源 (sub-resource) ,那么将所有的子资源按照字典序,从小到大排列并
|
125
|
+
# 以 ’&’ 为分隔符生成子资源字符串。在 CanonicalizedResource 字符串尾添加“?”和子资源字
|
126
|
+
# 符串。此时的 CanonicalizedResource 例子如: /BucketName/ObjectName?acl &uploadId=UploadId
|
127
|
+
# 4) 如果用户请求在查询字符串 (query string) 中指定了要重写 (override) 返回请求的 header,那么将这
|
128
|
+
# 些查询字符串及其请求值按照字典序,从小到大排列,以 ’&’ 为分隔符,按参数的字典序添加到
|
129
|
+
# CanonicalizedResource 中。此时的 CanonicalizedResource 例子:
|
130
|
+
# /BucketName/ObjectName?acl&response-content-type=ContentType & uploadId =UploadId
|
131
|
+
def canonicalized_resource()
|
132
|
+
return @path unless @bucket
|
133
|
+
return "/#{@bucket.name}#{@path}" if @queries.count == 0
|
134
|
+
|
135
|
+
array = Array.new
|
136
|
+
@queries.each_pair {|k,v| array << (if v then k+"="+v else k end)}
|
137
|
+
"/#{@bucket.name}#{@path}?#{array.sort.join('&')}"
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
|
+
end
|
data/lib/aliyunoss.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# dependency
|
2
|
+
require 'nokogiri'
|
3
|
+
require 'net/http'
|
4
|
+
require 'logger'
|
5
|
+
|
6
|
+
require 'aliyunoss/helper'
|
7
|
+
require 'aliyunoss/config'
|
8
|
+
require 'aliyunoss/extension'
|
9
|
+
require 'aliyunoss/http_response_extension'
|
10
|
+
require 'aliyunoss/oss_request'
|
11
|
+
require 'aliyunoss/api'
|
12
|
+
require 'aliyunoss/bucket'
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'aliyunoss'
|
3
|
+
|
4
|
+
describe Aliyun::Oss::API do
|
5
|
+
|
6
|
+
before :all do
|
7
|
+
Aliyun::Oss.configure_with('spec/aliyunoss/aliyun-config.yml')
|
8
|
+
# Aliyun::Oss.configure(:log_level=> 'debug')
|
9
|
+
bucket_name = 'aliyun-oss-gem-api-test'
|
10
|
+
response = Aliyun::Oss::API.put_bucket(bucket_name)
|
11
|
+
expect(response).to be_a(Net::HTTPOK)
|
12
|
+
end
|
13
|
+
|
14
|
+
before :each do
|
15
|
+
@api = Aliyun::Oss::API
|
16
|
+
@bucket = Aliyun::Oss::Bucket.new(name: 'aliyun-oss-gem-api-test', location: 'oss-cn-hangzhou')
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should get bucket list using GetService api' do
|
20
|
+
response = @api.list_bucket
|
21
|
+
expect(response).to be_a(Net::HTTPOK)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should disable bucket logging' do
|
25
|
+
expect(@api.delete_logging(@bucket)).to be_a(Net::HTTPNoContent)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should disable bucket website access' do
|
29
|
+
expect(@api.delete_website(@bucket)).to be_a(Net::HTTPNoContent)
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should list objects in bucket' do
|
33
|
+
expect(@api.list_object(@bucket)).to be_a(Net::HTTPOK)
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should get bucket acl' do
|
37
|
+
response = @api.get_bucket_acl(@bucket)
|
38
|
+
expect(response).to be_a(Net::HTTPOK)
|
39
|
+
xml = Nokogiri::XML(response.body).xpath('//Grant')
|
40
|
+
expect(xml.count).to be >= 1
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should get bucket location' do
|
44
|
+
response = @api.get_bucket_location(@bucket)
|
45
|
+
expect(response).to be_a(Net::HTTPOK)
|
46
|
+
node = Nokogiri::XML(response.body).xpath('//LocationConstraint')[0]
|
47
|
+
expect(node.content).to eq('oss-cn-hangzhou')
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should get bucket logging status' do
|
51
|
+
response = @api.get_bucket_logging(@bucket)
|
52
|
+
expect(response).to be_a(Net::HTTPOK)
|
53
|
+
expect(response.body).to include('BucketLoggingStatus')
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'should get bucket logging status' do
|
57
|
+
response = @api.get_bucket_website(@bucket)
|
58
|
+
expect(response).to be_a(Net::HTTPNotFound)
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'should correctly set bucket acl permission' do
|
62
|
+
expect(@api.set_bucket_acl(@bucket, 'public-read')).to be_a(Net::HTTPOK)
|
63
|
+
expect(@api.set_bucket_acl(@bucket, 'public-read-write')).to be_a(Net::HTTPOK)
|
64
|
+
expect(@api.set_bucket_acl(@bucket, 'private')).to be_a(Net::HTTPOK)
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'should enable and disable bucket logging func' do
|
68
|
+
expect(@api.disable_bucket_logging(@bucket)).to be_a(Net::HTTPOK)
|
69
|
+
expect(@api.enable_bucket_logging(@bucket, @bucket.name, 'logtest-')).to be_a(Net::HTTPOK)
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'should set bucket website access configuration' do
|
73
|
+
expect(@api.set_bucket_website(@bucket, 'index.html','error.html')).to be_a(Net::HTTPOK)
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'should upload file' do
|
77
|
+
files = ['test-1.png','test-2.png','test-3.png'].map {|f| File.join(__dir__, f)}
|
78
|
+
files.each do |f|
|
79
|
+
data = IO.read(f)
|
80
|
+
response = @api.put_object(@bucket, "/" + f[/test-\d\.png/], data, 'Content-Type'=>'image/png')
|
81
|
+
expect(response).to be_a(Net::HTTPOK)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'should copy object' do
|
86
|
+
sources = ['/test-1.png','/test-2.png','/test-3.png']
|
87
|
+
sources.each do |source_path|
|
88
|
+
response = @api.copy_object(@bucket, source_path, @bucket, "/copy-" + source_path[1,source_path.length-1])
|
89
|
+
expect(response).to be_a(Net::HTTPOK)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'should get object meta data' do
|
94
|
+
expect(@api.head_object(@bucket, '/test-1.png')).to be_a(Net::HTTPOK)
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'should get object from oss' do
|
98
|
+
response = @api.get_object(@bucket, '/copy-test-1.png')
|
99
|
+
file_name = File.join(__dir__, 'test-1.png')
|
100
|
+
expect(response['Content-Length']).to eq(File.size(file_name).to_s)
|
101
|
+
expect(response['Content-Type']).to eq('image/png')
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'should delete object' do
|
105
|
+
sources = ['/test-1.png','/test-2.png','/test-3.png']
|
106
|
+
sources.each do |path|
|
107
|
+
expect(@api.delete_object(@bucket,path)).to be_a(Net::HTTPNoContent)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'should delete multiple objects' do
|
112
|
+
response = @api.delete_multiple_objects(@bucket, ['copy-test-2.png','copy-test-3.png', 'copy-test-1.png'])
|
113
|
+
puts response.body
|
114
|
+
expect(response).to be_a(Net::HTTPOK)
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'should delete this bucket' do
|
118
|
+
response = @api.delete_bucket(@bucket)
|
119
|
+
expect(response).to be_a(Net::HTTPNoContent)
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'aliyunoss'
|
3
|
+
|
4
|
+
describe Aliyun::Oss::Bucket do
|
5
|
+
|
6
|
+
before :all do
|
7
|
+
Aliyun::Oss.configure_with('spec/aliyunoss/aliyun-config.yml')
|
8
|
+
end
|
9
|
+
|
10
|
+
before :each do
|
11
|
+
@bucket_name = 'aliyun-oss-gem-api-test'
|
12
|
+
@location = 'oss-cn-hangzhou'
|
13
|
+
@bucket = Aliyun::Oss::Bucket.all.select {|b| b.name == @bucket_name} .first
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should create a bucket' do
|
17
|
+
bucket = Aliyun::Oss::Bucket.create(@bucket_name, @location)
|
18
|
+
expect(bucket).to_not be_nil
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should list all buckets' do
|
22
|
+
buckets = Aliyun::Oss::Bucket.all
|
23
|
+
selected = buckets.select {|b| b.name == @bucket_name}
|
24
|
+
expect(selected.size).to eq(1)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should list files on server' do
|
28
|
+
expect(@bucket.list_files).to_not be_nil
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should upload data to server' do
|
32
|
+
files = ['test-1.png','test-2.png','test-3.png'].map {|f| File.join(__dir__, f)}
|
33
|
+
files.each do |f|
|
34
|
+
data = IO.read(f)
|
35
|
+
@bucket.upload(data, "/" + f[/test-\d\.png/], 'Content-Type'=>'image/png')
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should upload data to server in multipart way' do
|
40
|
+
path = '/multi-part-test.dat'
|
41
|
+
@bucket.multipart_upload_initiate(path)
|
42
|
+
|
43
|
+
10.times do
|
44
|
+
@bucket.multipart_upload( Random.new.bytes(1024 * rand(100..300)) )
|
45
|
+
end
|
46
|
+
|
47
|
+
@bucket.multipart_upload_complete
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should copy data in multipart way' do
|
51
|
+
pending 'I get Forbidden using x-oss-copy-source-range'
|
52
|
+
source_path = '/multi-part-test.dat'
|
53
|
+
source_object = @bucket.list_files.select {|f| '/' + f['key'] == source_path} .first
|
54
|
+
source_size = source_object['size'].to_i
|
55
|
+
|
56
|
+
target_path = '/multi-part-copy.dat'
|
57
|
+
@bucket.multipart_upload_initiate(target_path)
|
58
|
+
@bucket.multipart_copy_from(@bucket, source_path, 1024*100, "bytes=0-#{1024*100-1}")
|
59
|
+
@bucket.multipart_upload_complete
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'should download file from server' do
|
63
|
+
['/test-1.png','/test-2.png','/test-3.png'].each do |path|
|
64
|
+
remote_data = @bucket.download(path)
|
65
|
+
local_data = IO.read(File.join(__dir__, path))
|
66
|
+
md5 = OpenSSL::Digest::MD5
|
67
|
+
expect(md5.digest(remote_data)).to eq(md5.digest(local_data))
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'should delete file on server' do
|
72
|
+
['/test-1.png','/test-2.png','/test-3.png', '/multi-part-test.dat', '/multi-part-copy.dat'].each do |path|
|
73
|
+
@bucket.delete(path)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'should get and modify logging status' do
|
78
|
+
@bucket.enable_logging('aliyun-oss-gem-api-test', 'access_log')
|
79
|
+
sleep(2)
|
80
|
+
expect(@bucket.logging_status['target_bucket']).to eq('aliyun-oss-gem-api-test')
|
81
|
+
expect(@bucket.logging_status['target_prefix']).to eq('access_log')
|
82
|
+
@bucket.disable_logging
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'should get and modify website access status' do
|
86
|
+
@bucket.enable_website_access('index.html','error.html')
|
87
|
+
sleep(2)
|
88
|
+
expect(@bucket.website_access_status['index_page']).to eq('index.html')
|
89
|
+
expect(@bucket.website_access_status['error_page']).to eq('error.html')
|
90
|
+
@bucket.disable_website_access
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'should get and set access control list' do
|
94
|
+
@bucket.set_acl('public-read')
|
95
|
+
sleep(2)
|
96
|
+
expect(@bucket.get_acl).to eq('public-read')
|
97
|
+
@bucket.set_acl('private')
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'should delete specified bucket' do
|
101
|
+
@bucket.multipart_pending.each do |task|
|
102
|
+
@bucket.multipart_abort(task['path'], task['upload_id'])
|
103
|
+
end
|
104
|
+
|
105
|
+
@bucket.delete!
|
106
|
+
expect {Bucket.new(:name=> 'bucket_not_exist').delete!}.to raise_error
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'aliyunoss'
|
3
|
+
|
4
|
+
describe 'Aliyun::Oss Configuration' do
|
5
|
+
|
6
|
+
before :each do
|
7
|
+
config = Aliyun::Oss.config
|
8
|
+
config[:log_level] = 'info'
|
9
|
+
config[:host] = 'aliyuncs.com'
|
10
|
+
config[:access_key_id] = nil
|
11
|
+
config[:access_key_secret] = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should load default options' do
|
15
|
+
default_config = Aliyun::Oss.config
|
16
|
+
expect(default_config).to include(:log_level)
|
17
|
+
expect(default_config).to include(:host)
|
18
|
+
expect(default_config).to include(:access_key_id)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should accept configuration from #configure' do
|
22
|
+
url = "http://bucket_name.region.aliyuncs.com"
|
23
|
+
access_key = "access_key_from_aliyun"
|
24
|
+
Aliyun::Oss.configure(:log_level => 'debug', :host => url, :access_key_id => access_key, :not_used_para => "not used")
|
25
|
+
config = Aliyun::Oss.config
|
26
|
+
expect(config.keys).not_to include(:not_used_para)
|
27
|
+
expect(config[:host]).to eq(url)
|
28
|
+
expect(config[:access_key_id]).to eq(access_key)
|
29
|
+
expect(config[:log_level]).to eq('debug')
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should load yaml config file if specified' do
|
33
|
+
Aliyun::Oss.configure_with('spec/aliyunoss/aliyun-config.yml.sample')
|
34
|
+
config = Aliyun::Oss.config
|
35
|
+
expect(config[:host]).to eq('bucket_name.region.aliyuncs.com')
|
36
|
+
expect(config[:access_key_id]).to eq('access key _id from aliyun')
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should load default configuration if incorrect yaml file specified' do
|
40
|
+
Aliyun::Oss.configure_with('spec/aliyunoss/incorrect-config.yml')
|
41
|
+
config = Aliyun::Oss.config
|
42
|
+
expect(config[:host]).not_to eq('aliyun-yaml.com')
|
43
|
+
expect(config[:access_key_id]).not_to eq('1234567890')
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should load configuration from RAILS_ROOT/config/aliyun-oss.yml in Rails project'
|
47
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'aliyunoss'
|
3
|
+
|
4
|
+
describe Aliyun::Oss::API do
|
5
|
+
|
6
|
+
before :all do
|
7
|
+
Aliyun::Oss.configure_with('spec/aliyunoss/aliyun-config.yml')
|
8
|
+
Aliyun::Oss.configure(:log_level=> 'debug')
|
9
|
+
bucket_name = 'aliyun-oss-gem-api-test'
|
10
|
+
response = Aliyun::Oss::API.put_bucket(bucket_name)
|
11
|
+
expect(response).to be_a(Net::HTTPOK)
|
12
|
+
end
|
13
|
+
|
14
|
+
before :each do
|
15
|
+
@api = Aliyun::Oss::API
|
16
|
+
@bucket = Aliyun::Oss::Bucket.new(name: 'aliyun-oss-gem-api-test', location: 'oss-cn-hangzhou')
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should upload data in multipart way' do
|
20
|
+
path = '/multi-part-test.dat'
|
21
|
+
response = @api.multipart_upload_initiate(@bucket, path)
|
22
|
+
expect(response).to be_a(Net::HTTPOK)
|
23
|
+
|
24
|
+
upload_id = Nokogiri::XML(response.body).xpath('//UploadId')[0].content
|
25
|
+
expect(upload_id).to_not be_nil
|
26
|
+
|
27
|
+
part_list = {}
|
28
|
+
(1..10).each do |no|
|
29
|
+
data = Random.new.bytes(1024 * rand(100..300))
|
30
|
+
response = @api.multipart_upload_part(@bucket, path,upload_id, data, no)
|
31
|
+
expect(response).to be_a(Net::HTTPOK)
|
32
|
+
expect(response['ETag']).to_not be_nil
|
33
|
+
expect(response['ETag']).to be_a(String)
|
34
|
+
part_list[no] = response['ETag']
|
35
|
+
end
|
36
|
+
|
37
|
+
response = @api.multipart_upload_finished_parts(@bucket, path, upload_id)
|
38
|
+
expect(response).to be_a(Net::HTTPOK)
|
39
|
+
expect(response.body.include?('ListPartsResult')).to be true
|
40
|
+
|
41
|
+
response = @api.multipart_upload_complete(@bucket, path, upload_id, part_list)
|
42
|
+
expect(response).to be_a(Net::HTTPOK)
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'should aboart uploading' do
|
46
|
+
path = '/multi-part-test-aborted.dat'
|
47
|
+
response = @api.multipart_upload_initiate(@bucket, path)
|
48
|
+
expect(response).to be_a(Net::HTTPOK)
|
49
|
+
|
50
|
+
upload_id = Nokogiri::XML(response.body).xpath('//UploadId')[0].content
|
51
|
+
expect(upload_id).to_not be_nil
|
52
|
+
|
53
|
+
data = Random.new.bytes(1024 * rand(100..300))
|
54
|
+
|
55
|
+
response = @api.multipart_upload_part(@bucket, path, upload_id, data, 1)
|
56
|
+
expect(response).to be_a(Net::HTTPOK)
|
57
|
+
|
58
|
+
response = @api.multipart_upload_abort(@bucket, path, upload_id)
|
59
|
+
expect(response).to be_a(Net::HTTPNoContent)
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'should copy object from bucket in multipart way' do
|
63
|
+
path = '/copy-multi-part-test.dat'
|
64
|
+
response = @api.multipart_upload_initiate(@bucket, path)
|
65
|
+
expect(response).to be_a(Net::HTTPOK)
|
66
|
+
|
67
|
+
upload_id = Nokogiri::XML(response.body).xpath('//UploadId')[0].content
|
68
|
+
expect(upload_id).to_not be_nil
|
69
|
+
|
70
|
+
data = Random.new.bytes(1024 * rand(100..300))
|
71
|
+
|
72
|
+
response = @api.multipart_upload_from_copy(upload_id, @bucket, '/multi-part-test.dat',
|
73
|
+
@bucket, path, 1, 1024*500)
|
74
|
+
expect(response).to be_a(Net::HTTPOK)
|
75
|
+
|
76
|
+
response = @api.multipart_upload_abort(@bucket, path, upload_id)
|
77
|
+
expect(response).to be_a(Net::HTTPNoContent)
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'should delete uploaded file' do
|
81
|
+
expect(@api.delete_object(@bucket,'/multi-part-test.dat')).to be_a(Net::HTTPNoContent)
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'should list unfinished multipart upload task' do
|
85
|
+
response = @api.multipart_upload_unfinished_task(@bucket)
|
86
|
+
expect(response).to be_a(Net::HTTPOK)
|
87
|
+
|
88
|
+
# cancel all unfinished task
|
89
|
+
nodes = Nokogiri::XML(response.body).xpath('//Upload')
|
90
|
+
nodes.each do |node|
|
91
|
+
path = '/' + node.xpath('Key').first.content
|
92
|
+
id = node.xpath('UploadId').first.content
|
93
|
+
response = @api.multipart_upload_abort(@bucket, path, id)
|
94
|
+
expect(response).to be_a(Net::HTTPNoContent)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'should delete this bucket' do
|
99
|
+
response = Aliyun::Oss::API.delete_bucket(@bucket)
|
100
|
+
expect(response).to be_a(Net::HTTPNoContent)
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require 'rspec'
|
3
|
+
require 'aliyunoss'
|
4
|
+
|
5
|
+
describe Aliyun::Oss::OssRequest do
|
6
|
+
|
7
|
+
it 'should correctly calculate CanonicalizedOssHeader' do
|
8
|
+
Aliyun::Oss.configure(:access_key_id => '44CF9590006BF252F707',
|
9
|
+
:access_key_secret => 'OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV')
|
10
|
+
req = Net::HTTP::Get.new(URI("http://" + Aliyun::Oss.config[:host] + "/nelson"))
|
11
|
+
req["X-OSS-Meta-Author"] = "foo@bar.com"
|
12
|
+
req["X-OSS-Magic"] = "abracadabra"
|
13
|
+
req["Date"] = "Thu, 17 Nov 2005 18:49:58 GMT"
|
14
|
+
req["Content-Type"] = "text/html"
|
15
|
+
req["Content-MD5"] = "ODBGOERFMDMzQTczRUY3NUE3NzA5QzdFNUYzMDQxNEM="
|
16
|
+
result = Aliyun::Oss::OssRequest.new(nil, '/').
|
17
|
+
send(:canonicalized_oss_headers, req)
|
18
|
+
expect(result).to eq("x-oss-magic:abracadabra\nx-oss-meta-author:foo@bar.com\n")
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should correctly calculate CanonicalResource' do
|
22
|
+
bucket = Aliyun::Oss::Bucket.new(:name=>'BucketName',
|
23
|
+
:location=> 'oss-cn-hangzhou')
|
24
|
+
path = '/ObjectName'
|
25
|
+
queries = {"acl"=>nil, "uploadId"=>"UploadId",
|
26
|
+
"response-content-type"=>"ContentType" }
|
27
|
+
result = Aliyun::Oss::OssRequest.new(bucket, path, queries).
|
28
|
+
send(:canonicalized_resource)
|
29
|
+
expect(result).to eq("/BucketName/ObjectName?acl&response-content-type=ContentType&uploadId=UploadId")
|
30
|
+
|
31
|
+
result = Aliyun::Oss::OssRequest.new(bucket, path).
|
32
|
+
send(:canonicalized_resource)
|
33
|
+
expect(result).to eq("/BucketName/ObjectName")
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should correctly calculate signature in Authorization header' do
|
37
|
+
Aliyun::Oss.configure(:access_key_id => '44CF9590006BF252F707',
|
38
|
+
:access_key_secret => 'OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV')
|
39
|
+
bucket = Aliyun::Oss::Bucket.new(name: 'oss-example', location: 'oss-cn-hangzhou')
|
40
|
+
oss_req = Aliyun::Oss::OssRequest.new(bucket, '/nelson')
|
41
|
+
param = Net::HTTP::Put.new(oss_req.get_uri)
|
42
|
+
param["X-OSS-Meta-Author"] = "foo@bar.com"
|
43
|
+
param["X-OSS-Magic"] = "abracadabra"
|
44
|
+
param["Date"] = "Thu, 17 Nov 2005 18:49:58 GMT"
|
45
|
+
param["Content-Type"] = "text/html"
|
46
|
+
param["Content-MD5"] = "ODBGOERFMDMzQTczRUY3NUE3NzA5QzdFNUYzMDQxNEM="
|
47
|
+
result = oss_req.send(:signature, param)
|
48
|
+
expect(result).to eq("26NBxoKdsyly4EDv6inkoDft/yA=")
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
Binary file
|
Binary file
|
Binary file
|