cos 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +12 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +13 -2
  5. data/Gemfile +4 -1
  6. data/LICENSE +191 -0
  7. data/README.md +2014 -17
  8. data/Rakefile +23 -6
  9. data/bin/cos +325 -0
  10. data/bin/setup +1 -3
  11. data/cos.gemspec +24 -13
  12. data/lib/cos.rb +41 -4
  13. data/lib/cos/api.rb +289 -0
  14. data/lib/cos/bucket.rb +731 -0
  15. data/lib/cos/checkpoint.rb +62 -0
  16. data/lib/cos/client.rb +58 -0
  17. data/lib/cos/config.rb +102 -0
  18. data/lib/cos/dir.rb +301 -0
  19. data/lib/cos/download.rb +252 -0
  20. data/lib/cos/exception.rb +62 -0
  21. data/lib/cos/file.rb +152 -0
  22. data/lib/cos/http.rb +95 -0
  23. data/lib/cos/logging.rb +47 -0
  24. data/lib/cos/resource.rb +201 -0
  25. data/lib/cos/signature.rb +119 -0
  26. data/lib/cos/slice.rb +292 -0
  27. data/lib/cos/struct.rb +49 -0
  28. data/lib/cos/tree.rb +165 -0
  29. data/lib/cos/util.rb +82 -0
  30. data/lib/cos/version.rb +2 -2
  31. data/spec/cos/bucket_spec.rb +562 -0
  32. data/spec/cos/client_spec.rb +77 -0
  33. data/spec/cos/dir_spec.rb +195 -0
  34. data/spec/cos/download_spec.rb +105 -0
  35. data/spec/cos/http_spec.rb +70 -0
  36. data/spec/cos/signature_spec.rb +83 -0
  37. data/spec/cos/slice_spec.rb +302 -0
  38. data/spec/cos/struct_spec.rb +38 -0
  39. data/spec/cos/tree_spec.rb +322 -0
  40. data/spec/cos/util_spec.rb +106 -0
  41. data/test/download_test.rb +44 -0
  42. data/test/list_test.rb +43 -0
  43. data/test/upload_test.rb +48 -0
  44. metadata +132 -21
  45. data/.idea/.name +0 -1
  46. data/.idea/cos.iml +0 -49
  47. data/.idea/encodings.xml +0 -6
  48. data/.idea/misc.xml +0 -14
  49. data/.idea/modules.xml +0 -8
  50. data/.idea/workspace.xml +0 -465
  51. data/bin/console +0 -14
@@ -0,0 +1,77 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+ require 'fileutils'
5
+ require 'yaml'
6
+
7
+ module COS
8
+
9
+ describe Client do
10
+
11
+ before :all do
12
+ @config = {
13
+ app_id: '100000',
14
+ secret_id: 'secret_id',
15
+ secret_key: 'secret_key',
16
+ protocol: 'http',
17
+ default_bucket: 'bucket_name'
18
+ }
19
+ end
20
+
21
+ it 'get the signature access' do
22
+ expect(
23
+ Client.new(@config).signature.class
24
+ ).to be Signature
25
+ end
26
+
27
+ it 'get the bucket access' do
28
+ stub_request(:get, "http://web.file.myqcloud.com/files/v1/100000/bucket_name/?op=stat").
29
+ to_return(:status => 200, :body => { code: 0, message: 'ok', data: {}}.to_json)
30
+
31
+ expect(
32
+ Client.new(@config).bucket('bucket_name').bucket_name
33
+ ).to eq('bucket_name')
34
+ end
35
+
36
+ it 'bucket name must be set' do
37
+ expect do
38
+ client = Client.new({
39
+ app_id: '100000',
40
+ secret_id: 'secret_id',
41
+ secret_key: 'secret_key'
42
+ })
43
+ client.bucket
44
+ end.to raise_error(ClientError)
45
+ end
46
+
47
+ it 'Rails init client' do
48
+ Object.const_set('Rails', Class.new do
49
+ def self.root
50
+ ['/tmp/', '']
51
+ end
52
+ end)
53
+
54
+ FileUtils::mkdir_p('/tmp/log')
55
+ FileUtils::mkdir_p('/tmp/config')
56
+
57
+ yml = {
58
+ 'app_id' => '100000',
59
+ 'secret_id' => 'secret_id',
60
+ 'secret_key' => 'secret_key',
61
+ 'default_bucket' => 'bucket_name'
62
+ }
63
+
64
+ File.open('/tmp/config/cos.yml', 'w') do |f|
65
+ f.write(yml.to_yaml)
66
+ end
67
+
68
+ client = COS.client
69
+
70
+ expect(client.config.app_id).to eq('100000')
71
+
72
+ Object.const_set('Rails', nil)
73
+ end
74
+
75
+ end
76
+
77
+ end
@@ -0,0 +1,195 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ module COS
6
+
7
+ describe COSDir do
8
+
9
+ before :all do
10
+ stub_request(:get, "http://web.file.myqcloud.com/files/v1/100000/bucket_name/?op=stat").
11
+ to_return(:status => 200, :body => { code: 0, message: 'ok', data: {authority:'eWRPrivate'}}.to_json)
12
+
13
+ stub_request(:get, "http://web.file.myqcloud.com/files/v1/100000/bucket_name/test/?op=stat").
14
+ to_return(:status => 200, :body => {data:{name: 'test', ctime: @time, mtime: @time, biz_attr: ''}}.to_json)
15
+
16
+ @config = {
17
+ app_id: '100000',
18
+ secret_id: 'secret_id',
19
+ secret_key: 'secret_key',
20
+ protocol: 'http',
21
+ default_bucket: 'bucket_name'
22
+ }
23
+ @bucket = Client.new(@config).bucket('bucket_name')
24
+ @dir = @bucket.stat('test/')
25
+ end
26
+
27
+ it 'test upload all files to dir' do
28
+ @time = Time.now.to_i.to_s
29
+
30
+ local_path = "/tmp/cos_test/dir_#{Time.now.to_i}"
31
+ FileUtils::mkdir_p(local_path)
32
+
33
+ File.open("#{local_path}/test.txt", 'w') do |f|
34
+ (1..10).each do |i|
35
+ f.puts i.to_s.rjust(10, '0')
36
+ end
37
+ end
38
+
39
+ stub_request(:get, "http://web.file.myqcloud.com/files/v1/100000/bucket_name/test/?op=stat").
40
+ to_return(:status => 200, :body => {data:{name: 'd1', ctime: @time, mtime: @time, biz_attr: ''}}.to_json)
41
+
42
+ stub_request(:post, "http://web.file.myqcloud.com/files/v1/100000/bucket_name/test/test.txt")
43
+ .to_return(:status => 200, :body => {
44
+ code: 0, message: 'ok', data: {session: 'session', slice_size: 10000, offset: 0, access_url: 'access_url'}
45
+ }.to_json)
46
+
47
+ stub_request(:get, "http://web.file.myqcloud.com/files/v1/100000/bucket_name/test/test.txt?op=stat").
48
+ to_return(:status => 200, :body => {data:{name: 'test.txt', ctime: @time, mtime: @time, biz_attr: '', filesize: 100, filelen: 100, access_url: 'url'}}.to_json)
49
+
50
+ uploads = @dir.upload_all(local_path, skip_error: true)
51
+
52
+ expect(uploads[0].path).to eq('/test/test.txt')
53
+ end
54
+
55
+ it 'test download all files to local path' do
56
+ @time = Time.now.to_i.to_s
57
+
58
+ local_path = "/tmp/cos_test/dir2_#{Time.now.to_i}"
59
+ FileUtils::mkdir_p(local_path)
60
+
61
+ stub_request(:get, "http://web.file.myqcloud.com/files/v1/100000/bucket_name/test/?context=&num=20&op=list&order=0&pattern=eListFileOnly").
62
+ to_return(:status => 200, :body => {
63
+ code: 0,
64
+ message: 'ok',
65
+ data: {
66
+ has_more: false,
67
+ dircount: 1,
68
+ filecount: 1,
69
+ context: '',
70
+ infos: [
71
+ {name: 'file1.txt', ctime: @time, mtime: @time, sha: '1111', biz_attr: '', filesize: 100, filelen:100, access_url: 'url'},
72
+ ]
73
+ }
74
+ }.to_json, :headers => {})
75
+
76
+ stub_request(:get, %r{^(http?:\/\/)url\/\?sign=[^\s]+}).to_return(:status => 200, :body => "11111111111", :headers => {})
77
+
78
+ d = @dir.download_all(local_path)
79
+ expect(d).to eq(["#{local_path}/file1.txt"])
80
+ end
81
+
82
+ it 'test get dir hash tree' do
83
+
84
+ stub_request(:get, "http://web.file.myqcloud.com/files/v1/100000/bucket_name/test/?context=&num=1&op=list&order=0&pattern=eListBoth").
85
+ to_return(:status => 200, :body => { code: 0, message: 'ok', data: {
86
+ has_more: false,
87
+ context: '',
88
+ dircount: 2,
89
+ filecount: 0,
90
+ infos: [
91
+ {name: 'path1-1', ctime: Time.now.to_i.to_s, mtime: Time.now.to_i.to_s, biz_attr: ''},
92
+ {name: 'path1-2', ctime: Time.now.to_i.to_s, mtime: Time.now.to_i.to_s, biz_attr: ''},
93
+ ]
94
+ }}.to_json)
95
+
96
+ stub_request(:get, "http://web.file.myqcloud.com/files/v1/100000/bucket_name/test/?context=&num=20&op=list&order=0&pattern=eListDirOnly").
97
+ to_return(:status => 200, :body => { code: 0, message: 'ok', data: {
98
+ has_more: false,
99
+ context: '',
100
+ dircount: 2,
101
+ filecount: 1,
102
+ infos: [
103
+ {name: 'path1-1', ctime: Time.now.to_i.to_s, mtime: Time.now.to_i.to_s, biz_attr: ''},
104
+ {name: 'path1-2', ctime: Time.now.to_i.to_s, mtime: Time.now.to_i.to_s, biz_attr: ''},
105
+ ]
106
+ }}.to_json)
107
+
108
+ stub_request(:get, "http://web.file.myqcloud.com/files/v1/100000/bucket_name/test/path1-1/?context=&num=1&op=list&order=0&pattern=eListDirOnly").
109
+ to_return(:status => 200, :body => { code: 0, message: 'ok', data: {
110
+ has_more: false,
111
+ context: '',
112
+ dircount: 0,
113
+ filecount: 0,
114
+ infos: []
115
+ }}.to_json)
116
+
117
+ stub_request(:get, "http://web.file.myqcloud.com/files/v1/100000/bucket_name/test/path1-1/?context=&num=20&op=list&order=0&pattern=eListDirOnly").
118
+ to_return(:status => 200, :body => { code: 0, message: 'ok', data: {
119
+ has_more: false,
120
+ context: '',
121
+ dircount: 0,
122
+ filecount: 0,
123
+ infos: []
124
+ }}.to_json)
125
+
126
+ stub_request(:get, "http://web.file.myqcloud.com/files/v1/100000/bucket_name/test/path1-2/?context=&num=20&op=list&order=0&pattern=eListDirOnly").
127
+ to_return(:status => 200, :body => { code: 0, message: 'ok', data: {
128
+ has_more: false,
129
+ dircount: 0,
130
+ filecount: 0,
131
+ context: '',
132
+ infos: [
133
+ {name: 'path1-2-1', ctime: Time.now.to_i.to_s, mtime: Time.now.to_i.to_s, biz_attr: ''},
134
+ {name: 'path1-2-2', ctime: Time.now.to_i.to_s, mtime: Time.now.to_i.to_s, biz_attr: ''},
135
+ {name: 'f1', ctime: @time, mtime: @time, biz_attr: '', filesize: 100, filelen:100, access_url: 'url'},
136
+ ]
137
+ }}.to_json)
138
+
139
+ stub_request(:get, "http://web.file.myqcloud.com/files/v1/100000/bucket_name/test/path1-2/?context=&num=1&op=list&order=0&pattern=eListDirOnly").
140
+ to_return(:status => 200, :body => { code: 0, message: 'ok', data: {
141
+ has_more: false,
142
+ context: '',
143
+ dircount: 2,
144
+ filecount: 1,
145
+ infos: [
146
+ {name: 'path1-2-1', ctime: Time.now.to_i.to_s, mtime: Time.now.to_i.to_s, biz_attr: ''},
147
+ {name: 'path1-2-2', ctime: Time.now.to_i.to_s, mtime: Time.now.to_i.to_s, biz_attr: ''},
148
+ {name: 'f1', ctime: @time, mtime: @time, biz_attr: '', filesize: 100, filelen:100, access_url: 'url'},
149
+ ]
150
+ }}.to_json)
151
+
152
+ stub_request(:get, "http://web.file.myqcloud.com/files/v1/100000/bucket_name/test/path1-2/path1-2-1/?context=&num=1&op=list&order=0&pattern=eListDirOnly").
153
+ to_return(:status => 200, :body => { code: 0, message: 'ok', data: {
154
+ has_more: false,
155
+ context: '',
156
+ dircount: 0,
157
+ filecount: 0,
158
+ infos: []
159
+ }}.to_json)
160
+
161
+ stub_request(:get, "http://web.file.myqcloud.com/files/v1/100000/bucket_name/test/path1-2/path1-2-1/?context=&num=20&op=list&order=0&pattern=eListDirOnly").
162
+ to_return(:status => 200, :body => { code: 0, message: 'ok', data: {
163
+ has_more: false,
164
+ context: '',
165
+ dircount: 0,
166
+ filecount: 0,
167
+ infos: [
168
+ {name: 'f1', ctime: @time, mtime: @time, biz_attr: '', filesize: 100, filelen:100, access_url: 'url'},
169
+ ]
170
+ }}.to_json)
171
+
172
+ stub_request(:get, "http://web.file.myqcloud.com/files/v1/100000/bucket_name/test/path1-2/path1-2-2/?context=&num=1&op=list&order=0&pattern=eListDirOnly").
173
+ to_return(:status => 200, :body => { code: 0, message: 'ok', data: {
174
+ has_more: false,
175
+ dircount: 0,
176
+ filecount: 0,
177
+ context: '',
178
+ infos: []
179
+ }}.to_json)
180
+
181
+ stub_request(:get, "http://web.file.myqcloud.com/files/v1/100000/bucket_name/test/path1-2/path1-2-2/?context=&num=20&op=list&order=0&pattern=eListDirOnly").
182
+ to_return(:status => 200, :body => { code: 0, message: 'ok', data: {
183
+ has_more: false,
184
+ dircount: 0,
185
+ filecount: 0,
186
+ context: '',
187
+ infos: []
188
+ }}.to_json)
189
+
190
+ expect(@dir.hash_tree[:resource][:name]).to eq('test')
191
+ end
192
+
193
+ end
194
+
195
+ end
@@ -0,0 +1,105 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ module COS
6
+
7
+ describe Download do
8
+
9
+ before :all do
10
+ stub_request(:get, "http://web.file.myqcloud.com/files/v1/100000/bucket_name/?op=stat").
11
+ to_return(:status => 200, :body => { code: 0, message: 'ok', data: {}}.to_json)
12
+
13
+ @config = {
14
+ app_id: '100000',
15
+ secret_id: 'secret_id',
16
+ secret_key: 'secret_key',
17
+ protocol: 'http',
18
+ default_bucket: 'bucket_name'
19
+ }
20
+ COS.client(@config).bucket
21
+ end
22
+
23
+ it 'should download entire file' do
24
+ stub_request(:get, "http://web.file.myqcloud.com/files/v1/100000/bucket_name/d_path/file1?op=stat").
25
+ to_return(:status => 200, :body => { code: 0, message: 'ok', data: {name: 'f1', ctime: @time, mtime: @time, biz_attr: '', filesize: 100, filelen:100, access_url: 'url', sha: '123'}}.to_json)
26
+
27
+ stub_request(:get, %r{^(http?:\/\/)url\/\?sign=[^\s]+}).to_return(:status => 200, :body => "11111111111", :headers => {})
28
+
29
+ file = COS.client.bucket.stat('/d_path/file1')
30
+ local = file.download('/tmp/file11')
31
+
32
+ expect(File.read(local)).to eq('11111111111')
33
+ end
34
+
35
+ it 'should download entire file exist' do
36
+ stub_request(:get, "http://web.file.myqcloud.com/files/v1/100000/bucket_name/d_path/file1?op=stat").
37
+ to_return(:status => 200, :body => { code: 0, message: 'ok', data: {name: 'f1', ctime: @time, mtime: @time, biz_attr: '', filesize: 100, filelen:100, access_url: 'url', sha: '7D4EEBAB7CE33F2C5D6D8C6240CC8FE65EA14CD7'}}.to_json)
38
+
39
+ File.open('/tmp/file11', 'wb') do |f|
40
+ f.write('11111111111')
41
+ end
42
+ file = COS.client.bucket.stat('/d_path/file1')
43
+ local = file.download('/tmp/file11')
44
+
45
+ expect(File.read(local)).to eq('11111111111')
46
+ end
47
+
48
+ it 'should download slice file raise error' do
49
+ stub_request(:get, "http://web.file.myqcloud.com/files/v1/100000/bucket_name/d_path/file2?op=stat").
50
+ to_return(:status => 200, :body => { code: 0, message: 'ok', data: {name: 'f1', ctime: @time, mtime: @time, biz_attr: '', filesize: 100, filelen:100, access_url: 'url1', sha: '123'}}.to_json)
51
+
52
+ stub_request(:get, %r{^(http?:\/\/)url1\/\?sign=[^\s]+}).to_return(:status => 200, :body => "1", :headers => {})
53
+
54
+ file = COS.client.bucket.stat('/d_path/file2')
55
+
56
+ expect do
57
+ file.download('/tmp/file2', min_slice_size: 10)
58
+ end.to raise_error(DownloadError)
59
+
60
+ end
61
+
62
+ it 'should download slice file' do
63
+ stub_request(:get, "http://web.file.myqcloud.com/files/v1/100000/bucket_name/d_path/file3?op=stat").
64
+ to_return(:status => 200, :body => { code: 0, message: 'ok', data: {name: 'f1', ctime: @time, mtime: @time, biz_attr: '', filesize: 100, filelen:100, access_url: 'url3', sha: '356a192b7913b04c54574d18c28d46e6395428ab'}}.to_json)
65
+
66
+ stub_request(:get, %r{^(http?:\/\/)url3\/\?sign=[^\s]+}).to_return(:status => 200, :body => "1", :headers => {})
67
+
68
+ file = COS.client.bucket.stat('/d_path/file3')
69
+
70
+ prog = []
71
+ local = file.download('/tmp/file33', {min_slice_size: 10}) do |pr|
72
+ prog << pr
73
+ end
74
+
75
+ expect(File.read(local)).to eq('1')
76
+
77
+ expect(prog.size).to eq(4)
78
+
79
+ File.delete(local) if File.exist?(local)
80
+ end
81
+
82
+ it 'should download slice file and checkpoint file exist' do
83
+ stub_request(:get, "http://web.file.myqcloud.com/files/v1/100000/bucket_name/d_path/file3?op=stat").
84
+ to_return(:status => 200, :body => { code: 0, message: 'ok', data: {name: 'f1', ctime: @time, mtime: @time, biz_attr: '', filesize: 100, filelen:100, access_url: 'url3', sha: '4'}}.to_json)
85
+
86
+ stub_request(:get, %r{^(http?:\/\/)url3\/\?sign=[^\s]+}).to_return(:status => 200, :body => "1", :headers => {})
87
+
88
+ file = COS.client.bucket.stat('/d_path/file3')
89
+
90
+ # 创建cpt
91
+ cpt_file = '/tmp/file44.cpt'
92
+ File.open(cpt_file, 'w') do |f|
93
+ f << '{"session": "session", "sha1":"f1a4cca1a5b3e43a35fbad14a93bbfeec584f5de", "file_meta":{"sha1":"356a192b7913b04c54574d18c28d46e6395428ab"}, "parts":[{"number":1,"done":false,"range":[0,100]}], "slice_size":10000, "file_size":100, "offset":0}'
94
+ end
95
+
96
+ local = file.download('/tmp/file44', {min_slice_size: 10})
97
+
98
+ expect(File.read(local)).to eq('1')
99
+
100
+ File.delete(local) if File.exist?(local)
101
+ end
102
+
103
+ end
104
+
105
+ end
@@ -0,0 +1,70 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ module COS
6
+
7
+ describe HTTP do
8
+
9
+ before :all do
10
+ @config = {
11
+ app_id: '100000',
12
+ secret_id: 'secret_id',
13
+ secret_key: 'secret_key',
14
+ protocol: 'http',
15
+ default_bucket: 'bucket_name'
16
+ }
17
+ end
18
+
19
+ # 发送正确的http请求并包含鉴权header
20
+ it 'should set http Authorization with right url' do
21
+
22
+ @http = COS::HTTP.new(Config.new(@config))
23
+
24
+ stub_request(:get, 'http://web.file.myqcloud.com/files/v1/bucket_name/path/').
25
+ to_return(:status => 200, :body => {code: 0, message: 'ok'}.to_json, :headers => {})
26
+
27
+ @http.get('/bucket_name/path/', {}, 'sign')
28
+
29
+ expect(WebMock)
30
+ .to have_requested(:get, 'http://web.file.myqcloud.com/files/v1/bucket_name/path/')
31
+ .with{ |req| req.headers.has_key?('Authorization') }
32
+ end
33
+
34
+ # 正确抛出服务器错误返回
35
+ it 'should raise server exception when 400' do
36
+
37
+ @http = COS::HTTP.new(Config.new(@config))
38
+
39
+ stub_request(:get, 'http://web.file.myqcloud.com/files/v1/bucket_name/path/').
40
+ to_return(:status => 400, :body => {code: -19, message: 'some errors'}.to_json, :headers => {})
41
+
42
+ # ServerError
43
+ expect do
44
+ @http.get('/bucket_name/path/', {}, 'sign')
45
+ end.to raise_error(ServerError, 'some errors')
46
+
47
+ expect(WebMock)
48
+ .to have_requested(:get, 'http://web.file.myqcloud.com/files/v1/bucket_name/path/')
49
+ end
50
+
51
+ # 发送正确的post并解析data
52
+ it 'should send post and parse data' do
53
+
54
+ @http = COS::HTTP.new(Config.new(@config))
55
+
56
+ stub_request(:post, 'http://web.file.myqcloud.com/files/v1/bucket_name/path/file').
57
+ to_return(:status => 200, :body => {code: 0, message: 'ok', data: {count:10}}.to_json, :headers => {})
58
+
59
+ expect(
60
+ @http.post('/bucket_name/path/file', {}, 'sign', {biz_attr: 'test'})
61
+ ).to eq({count: 10})
62
+
63
+ expect(WebMock)
64
+ .to have_requested(:post, 'http://web.file.myqcloud.com/files/v1/bucket_name/path/file')
65
+
66
+ end
67
+
68
+ end
69
+
70
+ end