baidu-sdk 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +15 -0
  5. data/.yardopts +1 -0
  6. data/Gemfile +17 -0
  7. data/Guardfile +6 -0
  8. data/HISTORY.md +2 -0
  9. data/LICENSE.txt +22 -0
  10. data/README.md +161 -0
  11. data/Rakefile +4 -0
  12. data/baidu-pcs.gemspec +24 -0
  13. data/lib/baidu/configure.rb +27 -0
  14. data/lib/baidu/core.rb +19 -0
  15. data/lib/baidu/errors/error.rb +22 -0
  16. data/lib/baidu/oauth.rb +11 -0
  17. data/lib/baidu/oauth/client.rb +66 -0
  18. data/lib/baidu/oauth/flow/base.rb +44 -0
  19. data/lib/baidu/oauth/flow/code.rb +69 -0
  20. data/lib/baidu/oauth/flow/device.rb +75 -0
  21. data/lib/baidu/pcs.rb +19 -0
  22. data/lib/baidu/pcs/client.rb +1090 -0
  23. data/lib/baidu/session.rb +36 -0
  24. data/lib/baidu/support/cacert.pem +37 -0
  25. data/lib/baidu/support/request.rb +127 -0
  26. data/lib/baidu/support/util.rb +67 -0
  27. data/lib/baidu/version.rb +5 -0
  28. data/spec/baidu/core_spec.rb +20 -0
  29. data/spec/baidu/oauth/client_spec.rb +199 -0
  30. data/spec/baidu/pcs/client_spec.rb +878 -0
  31. data/spec/baidu/session_spec.rb +27 -0
  32. data/spec/baidu/support/request_spec.rb +58 -0
  33. data/spec/baidu/support/util_spec.rb +48 -0
  34. data/spec/fixtures/add_task.json +1 -0
  35. data/spec/fixtures/cancel_task.json +3 -0
  36. data/spec/fixtures/copy.json +7 -0
  37. data/spec/fixtures/delete.json +3 -0
  38. data/spec/fixtures/diff.json +17 -0
  39. data/spec/fixtures/empty.json +1 -0
  40. data/spec/fixtures/get_token_code.json +8 -0
  41. data/spec/fixtures/get_token_device.json +8 -0
  42. data/spec/fixtures/list.json +11 -0
  43. data/spec/fixtures/list_task_0.json +1 -0
  44. data/spec/fixtures/list_task_1.json +1 -0
  45. data/spec/fixtures/listrecycle.json +23 -0
  46. data/spec/fixtures/logo.png +0 -0
  47. data/spec/fixtures/meta.json +11 -0
  48. data/spec/fixtures/mkdir.json +7 -0
  49. data/spec/fixtures/move.json +8 -0
  50. data/spec/fixtures/query_task_0.json +24 -0
  51. data/spec/fixtures/query_task_1.json +22 -0
  52. data/spec/fixtures/quota.json +5 -0
  53. data/spec/fixtures/rapidupload.json +10 -0
  54. data/spec/fixtures/refresh_token.json +8 -0
  55. data/spec/fixtures/restore.json +1 -0
  56. data/spec/fixtures/search.json +11 -0
  57. data/spec/fixtures/stream_list.json +16 -0
  58. data/spec/fixtures/streaming.m3u8 +5 -0
  59. data/spec/fixtures/upload.json +9 -0
  60. data/spec/fixtures/upload_block.json +4 -0
  61. data/spec/fixtures/user_and_device_code.json +8 -0
  62. data/spec/spec_helper.rb +66 -0
  63. metadata +169 -0
@@ -0,0 +1,878 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'spec_helper'
4
+ require 'baidu/pcs'
5
+
6
+ describe Baidu::PCS do
7
+ let(:target_file) { ft('logo.png') }
8
+
9
+ before :all do
10
+ Baidu.config do |c|
11
+ c.pcs_dir_name = 'Backups'
12
+ end
13
+ @client = Baidu::PCS::Client.new('ATOKEN')
14
+ end
15
+
16
+ describe '.initialize' do
17
+ it 'assgins access token and default site' do
18
+ expect(Baidu::PCS::SITE).to eq('https://pcs.baidu.com')
19
+ expect(Baidu::PCS::UPLOAD_SITE).to eq('https://c.pcs.baidu.com')
20
+ expect(Baidu::PCS::DOWNLOAD_SITE).to eq('https://d.pcs.baidu.com')
21
+ expect(Baidu::PCS::BASE_PATH).to eq('/rest/2.0/pcs')
22
+ expect(@client.instance_variable_get('@site')).to eq('https://pcs.baidu.com')
23
+ expect(@client.instance_variable_get('@access_token')).to eq('ATOKEN')
24
+ end
25
+
26
+ it 'assgins access token with session' do
27
+ session = Baidu::Session.new
28
+ session.access_token = 'ATOKEN_SESSION'
29
+ client = Baidu::PCS::Client.new(session)
30
+ expect(client.instance_variable_get(:@access_token)).to eq('ATOKEN_SESSION')
31
+ end
32
+
33
+ it 'raises argument error' do
34
+ expect { Baidu::PCS::Client.new(nil) }.to raise_error(ArgumentError, 'access_token must not be blank')
35
+ expect {
36
+ Baidu::PCS::Client.new('ATOKEN', nil)
37
+ }.to raise_error(ArgumentError, 'dir_name must not be blank')
38
+ end
39
+
40
+ it 'uses app name from method param' do
41
+ Baidu.pcs_dir_name = 'Backups'
42
+ c = Baidu::PCS::Client.new('ATOKEN', 'Backups2')
43
+ expect(c.instance_variable_get(:@dir_name)).to eq('Backups2')
44
+ end
45
+ end
46
+
47
+ describe '#quota' do
48
+ before do
49
+ stub_get(:pcs, '/quota', method: 'info', access_token: 'ATOKEN').to_return(status: 200, body: ft('quota.json'))
50
+ end
51
+
52
+ it 'requests quota api' do
53
+ @client.quota
54
+ a_get(:pcs, '/quota', method: 'info', access_token: 'ATOKEN').should have_been_made
55
+ end
56
+
57
+ it 'responses quota info' do
58
+ result = @client.quota
59
+ expect(result).to be_instance_of(Hash)
60
+ expect(result).to have_key(:quota)
61
+ expect(result).to have_key(:used)
62
+ end
63
+ end
64
+
65
+ describe '#upload' do
66
+ describe 'single file' do
67
+ let(:file) { ft('logo.png') }
68
+ let(:url) { /pcs.baidu.com\/rest\/2.0\/pcs\// }
69
+ let(:uploadquery) { { method: 'upload', access_token: 'ATOKEN', ondup: 'newcopy' } }
70
+
71
+ before do
72
+ IO.stub(:binread).and_return('')
73
+ stub_request(:post, url)
74
+ end
75
+
76
+ it 'validates method parmas' do
77
+ expect { @client.upload('/tmp/file.txt') }.to raise_error(ArgumentError, 'file must be an instance of File')
78
+ end
79
+
80
+ context 'without block_upload' do
81
+ it 'uploads 256MB file' do
82
+ file.stub(:size).and_return 256*1024*1024
83
+ @client.upload file, block_upload: false
84
+ a_request(:post, url).should have_been_made.times(1)
85
+ a_request(:post, url).with(query: hash_including({ method: 'upload' })).should have_been_made.times(1)
86
+ a_request(:post, url).with(query: hash_including({ type: 'tmpfile' })).should have_been_made.times(0)
87
+ a_request(:post, url).with(query: hash_including({ method: 'createsuperfile' })).should have_been_made.times(0)
88
+ end
89
+
90
+ it 'uploads 2GB file' do
91
+ file.stub(:size).and_return 2*1024*1024*1024
92
+ expect { @client.upload(file, block_upload: false) }.not_to raise_error
93
+ end
94
+
95
+ it 'uploads 2.1GB file' do
96
+ file.stub(:size).and_return 2.1*1024*1024*1024
97
+ expect { @client.upload(file, block_upload: false) }.to raise_error(IOError, 'file is too large (larger than 2G)')
98
+ end
99
+ end
100
+
101
+ context 'with block_upload' do
102
+ it 'uploads 7MB file' do
103
+ file.stub(:size).and_return 7*1024*1024
104
+ @client.upload file, block_upload: true
105
+ a_request(:post, url).should have_been_made.times(1)
106
+ a_request(:post, url).with(query: hash_including({ method: 'upload' })).should have_been_made.times(1)
107
+ a_request(:post, url).with(query: hash_including({ type: 'tmpfile' })).should_not have_been_made
108
+ a_request(:post, url).with(query: hash_including({ method: 'createsuperfile' })).should_not have_been_made
109
+ end
110
+
111
+ it 'uploads 8MB file' do
112
+ file.stub(:size).and_return 8*1024*1024
113
+ @client.upload file, block_upload: true
114
+ a_request(:post, url).should have_been_made.times(3)
115
+ a_request(:post, url).with(query: hash_including({ method: 'upload' })).should have_been_made.times(2)
116
+ a_request(:post, url).with(query: hash_including({ type: 'tmpfile' })).should have_been_made.times(2)
117
+ a_request(:post, url).with(query: hash_including({ method: 'createsuperfile' })).should have_been_made.times(1)
118
+ end
119
+
120
+ it 'uploads 22MB file' do
121
+ file.stub(:size).and_return 22*1024*1024
122
+ @client.upload file, block_upload: true
123
+ a_request(:post, url).should have_been_made.times(7)
124
+ a_request(:post, url).with(query: hash_including({ method: 'upload' })).should have_been_made.times(6)
125
+ a_request(:post, url).with(query: hash_including({ type: 'tmpfile' })).should have_been_made.times(6)
126
+ a_request(:post, url).with(query: hash_including({ method: 'createsuperfile' })).should have_been_made.times(1)
127
+ end
128
+
129
+ it 'is waiting for retry'
130
+ # it 'is waiting for retry' do
131
+ # allow(Kernel).to receive(:sleep)
132
+ # allow(file).to receive(:size).and_return(256*1024*1024)
133
+ # allow(@client).to receive(:upload_block).and_raise(ArgumentError)
134
+ # begin
135
+ # @client.upload file, retry_waitsec: 1, retry_times: 2
136
+ # rescue
137
+ # end
138
+ # expect(@client).to receive(:upload_block).exactly(2).times
139
+ # # expect(Kernel).to receive(:sleep).exactly(2).times
140
+ # end
141
+ end
142
+
143
+ it 'sets right request header' do
144
+ query = URI.encode_www_form( { path: '/apps/Backups/api测试/图片/标识.png' }.merge uploadquery )
145
+ stub_post(:pcs_upload, '/file?' + query).to_return(status: 200, body: ft('upload.json'))
146
+
147
+ @client.upload(target_file, path: 'api测试/图片/标识.png')
148
+ a_post(:pcs_upload, '/file?' + query).should have_been_made
149
+ end
150
+
151
+ it 'overwrite existing file' do
152
+ uploadquery[:ondup] = 'overwrite'
153
+ query = URI.encode_www_form( { path: '/apps/Backups/a/apitest.png' }.merge uploadquery )
154
+ stub_post(:pcs_upload, '/file?' + query).to_return(status: 200, body: ft('upload.json'))
155
+
156
+ @client.upload(target_file, path: 'a/apitest.png', overwrite: true)
157
+ a_post(:pcs_upload, '/file?' + query).should have_been_made
158
+ end
159
+
160
+ it 'raise exception when path length is too long' do
161
+ expect {
162
+ @client.upload(target_file, path: 'a'*1001) # name bytesize > 1000
163
+ }.to raise_error(ArgumentError, 'path length must not be greater than 1000')
164
+
165
+ query = URI.encode_www_form( { path: ('/apps/Backups/' + 'a'*1000) }.merge uploadquery )
166
+ stub_post(:pcs_upload, '/file?' + query)
167
+ expect { @client.upload(target_file, path: 'a'*1000) }.not_to raise_error
168
+ end
169
+ end
170
+ end
171
+
172
+ describe '#upload_block' do
173
+ let(:query) {
174
+ URI.encode_www_form({
175
+ method: 'upload',
176
+ access_token: 'ATOKEN',
177
+ type: 'tmpfile'
178
+ })
179
+ }
180
+
181
+ it 'sets blocked upload params type tmpfile' do
182
+ stub_post(:pcs_upload, '/file?' + query).to_return(status: 200, body: ft('upload_block.json'))
183
+ @client.upload_block(IO.read target_file, 10)
184
+ a_post(:pcs_upload, '/file?' + query).should have_been_made
185
+ end
186
+
187
+ end
188
+
189
+ describe '#create_super_file' do
190
+ let(:uploadquery) { {
191
+ method: 'createsuperfile',
192
+ access_token: 'ATOKEN',
193
+ ondup: 'newcopy'
194
+ } }
195
+
196
+ let(:block_list) { %w[abc def ghi] }
197
+
198
+ it 'overwrite existing file' do
199
+ uploadquery[:ondup] = 'overwrite'
200
+ query = URI.encode_www_form( { path: '/apps/Backups/a/apitest.png' }.merge uploadquery )
201
+ param = JSON.dump({ block_list: block_list })
202
+ stub_post(:pcs, '/file?' + query, param: param).to_return(status: 200, body: ft('upload.json'))
203
+
204
+ @client.create_super_file(block_list, 'a/apitest.png', true)
205
+ a_post(:pcs, '/file?' + query, param: param).should have_been_made
206
+ end
207
+
208
+ it 'finish blocked file upload' do
209
+ query = URI.encode_www_form({ path: ('/apps/Backups/upload_block/标识.png') }.merge uploadquery)
210
+ param = JSON.dump({ block_list: block_list })
211
+ stub_post(:pcs, '/file?' + query, param: param).to_return(status: 200, body: ft('upload.json'))
212
+ @client.create_super_file(block_list, 'upload_block/标识.png')
213
+ a_post(:pcs, '/file?' + query, param: param).should have_been_made
214
+ end
215
+
216
+ it 'raise exception when path length is too long' do
217
+ expect {
218
+ @client.create_super_file(block_list, 'a'*1001) # name bytesize > 1000
219
+ }.to raise_error(ArgumentError, 'path length must not be greater than 1000')
220
+
221
+ query = URI.encode_www_form({ path: ('/apps/Backups/' + 'a'*1000) }.merge uploadquery)
222
+ stub_post(:pcs, '/file?' + query)
223
+ expect { @client.create_super_file(block_list, 'a'*1000) }.not_to raise_error
224
+ end
225
+
226
+ it 'raise exception when path is blank' do
227
+ expect { @client.create_super_file(block_list, ' ') }.to raise_error(ArgumentError, 'path must not be blank')
228
+ expect { @client.create_super_file(block_list, nil) }.to raise_error(ArgumentError, 'path must not be blank')
229
+ end
230
+ end
231
+
232
+ describe '#download' do
233
+ let(:qparams) { { method: 'download', access_token: 'ATOKEN', path: '/apps/Backups/api测试/图片/标识.png'} }
234
+ let(:query) { URI.encode_www_form(qparams) }
235
+
236
+ it 'download file with raw body' do
237
+ stub_get(:pcs_download, '/file?' + query).to_return(status: 200, body: ft('logo.png'))
238
+ @client.download('api测试/图片/标识.png')
239
+ a_get(:pcs_download, '/file?' + query).should have_been_made
240
+ end
241
+
242
+ it 'download specified range(0-4) of file' do
243
+ stub_get(:pcs_download, '/file?' + query)
244
+ @client.download('api测试/图片/标识.png', begin: 0, end: 4)
245
+ a_request(:get, /d.pcs.baidu.com.+\/file\?/).
246
+ with(query: hash_including(qparams), headers: { Range: 'bytes=0-4' }).should have_been_made
247
+ end
248
+
249
+ it 'download specified range(0-100) of file' do
250
+ stub_get(:pcs_download, '/file?' + query)
251
+ @client.download('api测试/图片/标识.png', end: 100)
252
+ a_request(:get, /d.pcs.baidu.com.+\/file\?/).
253
+ with(query: hash_including(qparams), headers: { Range: 'bytes=0-100' }).should have_been_made
254
+ end
255
+
256
+ it 'download specified range(100-) of file' do
257
+ stub_get(:pcs_download, '/file?' + query)
258
+ @client.download('api测试/图片/标识.png', begin: 100)
259
+ a_request(:get, /d.pcs.baidu.com.+\/file\?/).
260
+ with(query: hash_including(qparams), headers: { Range: 'bytes=100-' }).should have_been_made
261
+ end
262
+
263
+ it 'download specified range(100-200) of file' do
264
+ stub_get(:pcs_download, '/file?' + query)
265
+ @client.download('api测试/图片/标识.png', begin: 100, end: 200)
266
+ a_request(:get, /d.pcs.baidu.com.+\/file\?/).
267
+ with(query: hash_including(qparams), headers: { Range: 'bytes=100-200' }).should have_been_made
268
+ end
269
+
270
+ it 'download file chunked' do
271
+ stub_get(:pcs_download, '/file?' + query).to_return(status: 200, body: ft('logo.png'))
272
+ content = ''
273
+ @client.download('api测试/图片/标识.png') do |chunk|
274
+ content << chunk
275
+ end
276
+ a_get(:pcs_download, '/file?' + query).should have_been_made
277
+ expect(content).not_to be_empty
278
+ end
279
+
280
+ it 'download specified range(100-200) of file chunked' do
281
+ stub_get(:pcs_download, '/file?' + query).to_return(status: 200, body: ft('logo.png'))
282
+ content = ''
283
+ @client.download('api测试/图片/标识.png', begin: 100, end: 200) do |chunk|
284
+ content << chunk
285
+ end
286
+ a_request(:get, /d.pcs.baidu.com.+\/file\?/).
287
+ with(query: hash_including(qparams), headers: { Range: 'bytes=100-200' }).should have_been_made
288
+ expect(content).not_to be_empty
289
+ end
290
+ end
291
+
292
+ describe '#mkdir' do
293
+ let(:query) {
294
+ URI.encode_www_form({
295
+ method: 'mkdir',
296
+ access_token: 'ATOKEN',
297
+ path: '/apps/Backups/apitest'
298
+ })
299
+ }
300
+
301
+ it 'makes dir' do
302
+ stub_post(:pcs, '/file?' + query).to_return(status: 200, body: ft('mkdir.json'))
303
+ @client.mkdir('apitest')
304
+ a_post(:pcs, '/file?' + query).should have_been_made
305
+ end
306
+ end
307
+
308
+ describe '#meta' do
309
+ describe 'when single file or dir' do
310
+ let(:query) {
311
+ URI.encode_www_form({
312
+ method: 'meta',
313
+ access_token: 'ATOKEN',
314
+ path: '/apps/Backups/apitest'
315
+ })
316
+ }
317
+
318
+ it 'raise exception when path is blank' do
319
+ expect { @client.meta('') }.to raise_error(ArgumentError, 'path must not be blank')
320
+ expect { @client.meta(' ') }.to raise_error(ArgumentError, 'path must not be blank')
321
+ expect { @client.meta(nil) }.to raise_error(ArgumentError, 'path must be kind of String or Array')
322
+ end
323
+
324
+ it 'gets meta infomation' do
325
+ stub_get(:pcs, '/file?' + query).to_return(status: 200, body: ft('meta.json'))
326
+ @client.meta('apitest')
327
+ a_get(:pcs, '/file?' + query).should have_been_made
328
+ end
329
+ end
330
+
331
+ describe 'when multiple files or dirs' do
332
+ let(:query) {
333
+ URI.encode_www_form({
334
+ method: 'meta',
335
+ access_token: 'ATOKEN',
336
+ param: JSON.dump({list: [ { path: '/apps/Backups/a/b' },
337
+ { path: '/apps/Backups/c' },
338
+ { path: '/apps/Backups/d/e/f' } ]
339
+ })
340
+ })
341
+ }
342
+ let(:paths) { %w[a/b c d/e/f] }
343
+
344
+ it 'raise exception when path is blank' do
345
+ expect { @client.meta([]) }.to raise_error(ArgumentError, 'path(s) must not be empty')
346
+ expect { @client.meta(nil) }.to raise_error(ArgumentError, 'path must be kind of String or Array')
347
+ expect { @client.meta(['']) }.to raise_error(ArgumentError, 'path must not be blank')
348
+ expect { @client.meta(['a'*1001]) }.to raise_error(ArgumentError, 'path length must not be greater than 1000')
349
+ end
350
+
351
+ it 'gets meta infomation' do
352
+ stub_get(:pcs, '/file?' + query).to_return(status: 200, body: ft('meta.json'))
353
+ @client.meta(paths)
354
+ a_get(:pcs, '/file?' + query).should have_been_made
355
+ end
356
+ end
357
+ end
358
+
359
+ describe '#list' do
360
+ let(:query) {
361
+ URI.encode_www_form({
362
+ method: 'list',
363
+ access_token: 'ATOKEN',
364
+ path: '/apps/Backups/apitest'
365
+ })
366
+ }
367
+
368
+ it 'requests with default params' do
369
+ stub = stub_get(:pcs, '/file?' + query + '&by=name&order=desc').to_return(status: 200, body: ft('list.json'))
370
+ @client.list('apitest')
371
+ stub.should have_been_requested
372
+ end
373
+
374
+ it 'requests with options' do
375
+ stub = stub_get(:pcs, '/file?' + query + '&order=asc&by=time&limit=2-10').to_return(status: 200, body: ft('list.json'))
376
+ @client.list('apitest', order: 'asc', by: 'time', limit: '2-10')
377
+ stub.should have_been_requested
378
+ end
379
+ end
380
+
381
+ describe '#move' do
382
+ describe 'when from and to are both single paths' do
383
+ let(:query) {
384
+ URI.encode_www_form({
385
+ method: 'move',
386
+ access_token: 'ATOKEN'
387
+ })
388
+ }
389
+
390
+ it 'moves apitest to apitestnew' do
391
+ stub_post(:pcs, '/file?' + query, { from: '/apps/Backups/apitest', to: '/apps/Backups/apitestnew' })
392
+ .to_return(status: 200, body: ft('move.json'))
393
+ @client.move('apitest', 'apitestnew')
394
+ a_post(:pcs, '/file?' + query, { from: '/apps/Backups/apitest', to: '/apps/Backups/apitestnew' })
395
+ .should have_been_made
396
+ end
397
+
398
+ it 'raise exception when from or to is invalid' do
399
+ expect{ @client.move('a', %w[b]) }.to raise_error(ArgumentError, 'from and to must have the same type')
400
+ expect{ @client.move(nil, '') }.to raise_error(ArgumentError, 'from and to must be kind of String or Array')
401
+ expect{ @client.move('', 'b') }.to raise_error(ArgumentError, 'path must not be blank')
402
+ expect{ @client.move('a', '') }.to raise_error(ArgumentError, 'path must not be blank')
403
+ end
404
+ end
405
+
406
+ describe 'when from and to are both multiple paths' do
407
+ let(:query) {
408
+ URI.encode_www_form({
409
+ method: 'move',
410
+ access_token: 'ATOKEN',
411
+ })
412
+ }
413
+ let(:param) {
414
+ JSON.dump({ list: [{from: '/apps/Backups/a', to: '/apps/Backups/b'},
415
+ {from: '/apps/Backups/a/b/c', to: '/apps/Backups/abc'}]
416
+ })
417
+ }
418
+
419
+ it 'moves multiple paths to other paths' do
420
+ stub_post(:pcs, '/file?' + query, { param: param }).to_return(status: 200, body: ft('move.json'))
421
+ @client.move(%w[a a/b/c], %w[b abc])
422
+ a_post(:pcs, '/file?' + query, { param: param })
423
+ end
424
+
425
+ it 'raise exception when from or to is invalid' do
426
+ expect{ @client.move([], %w[a]) }.to raise_error(ArgumentError, 'from or to must not be empty')
427
+ expect{ @client.move(%w[a], []) }.to raise_error(ArgumentError, 'from or to must not be empty')
428
+ expect{ @client.move(%w[a], ['']) }.to raise_error(ArgumentError, 'path must not be blank')
429
+ expect{ @client.move(nil, ['']) }.to raise_error(ArgumentError, 'from and to must be kind of String or Array')
430
+ expect{ @client.move([''], nil) }.to raise_error(ArgumentError, 'from and to must have the same type')
431
+ expect{ @client.move(%w[a], %w[ab cd]) }.to raise_error(ArgumentError, 'from and to must have the same size')
432
+ end
433
+ end
434
+ end
435
+
436
+ describe '#copy' do
437
+ describe 'when from and to are both single paths' do
438
+ let(:query) {
439
+ URI.encode_www_form({
440
+ method: 'copy',
441
+ access_token: 'ATOKEN'
442
+ })
443
+ }
444
+
445
+ it 'copys apitest to apitestnew' do
446
+ stub_post(:pcs, '/file?' + query, { from: '/apps/Backups/apitest', to: '/apps/Backups/apitestcopy' })
447
+ .to_return(status: 200, body: ft('copy.json'))
448
+ @client.copy('apitest', 'apitestcopy')
449
+ a_post(:pcs, '/file?' + query, { from: '/apps/Backups/apitest', to: '/apps/Backups/apitestcopy' })
450
+ .should have_been_made
451
+ end
452
+
453
+ it 'raise exception when from or to is invalid' do
454
+ expect{ @client.copy('a', %w[b]) }.to raise_error(ArgumentError, 'from and to must have the same type')
455
+ expect{ @client.copy(nil, '') }.to raise_error(ArgumentError, 'from and to must be kind of String or Array')
456
+ expect{ @client.copy('', 'b') }.to raise_error(ArgumentError, 'path must not be blank')
457
+ expect{ @client.copy('a', '') }.to raise_error(ArgumentError, 'path must not be blank')
458
+ end
459
+ end
460
+
461
+ describe 'when from and to are both multiple paths' do
462
+ let(:query) {
463
+ URI.encode_www_form({
464
+ method: 'copy',
465
+ access_token: 'ATOKEN',
466
+ })
467
+ }
468
+ let(:param) {
469
+ JSON.dump({ list: [{from: '/apps/Backups/a', to: '/apps/Backups/b'},
470
+ {from: '/apps/Backups/a/b/c', to: '/apps/Backups/abc'}]
471
+ })
472
+ }
473
+
474
+ it 'copys multiple paths to other paths' do
475
+ stub_post(:pcs, '/file?' + query, { param: param }).to_return(status: 200, body: ft('copy.json'))
476
+ @client.copy(%w[a a/b/c], %w[b abc])
477
+ a_post(:pcs, '/file?' + query, { param: param })
478
+ end
479
+
480
+ it 'raise exception when from or to is invalid' do
481
+ expect{ @client.copy([], %w[a]) }.to raise_error(ArgumentError, 'from or to must not be empty')
482
+ expect{ @client.copy(%w[a], []) }.to raise_error(ArgumentError, 'from or to must not be empty')
483
+ expect{ @client.copy(%w[a], ['']) }.to raise_error(ArgumentError, 'path must not be blank')
484
+ expect{ @client.copy(nil, ['']) }.to raise_error(ArgumentError, 'from and to must be kind of String or Array')
485
+ expect{ @client.copy([''], nil) }.to raise_error(ArgumentError, 'from and to must have the same type')
486
+ expect{ @client.copy(%w[a], %w[ab cd]) }.to raise_error(ArgumentError, 'from and to must have the same size')
487
+ end
488
+ end
489
+ end
490
+
491
+ describe '#delete' do
492
+ describe 'when single file or dir' do
493
+ let(:query) {
494
+ URI.encode_www_form({
495
+ method: 'delete',
496
+ access_token: 'ATOKEN',
497
+ path: '/apps/Backups/apitest'
498
+ })
499
+ }
500
+
501
+ it 'raise exception when path is blank' do
502
+ expect { @client.meta('') }.to raise_error(ArgumentError, 'path must not be blank')
503
+ expect { @client.meta(' ') }.to raise_error(ArgumentError, 'path must not be blank')
504
+ expect { @client.meta(nil) }.to raise_error(ArgumentError, 'path must be kind of String or Array')
505
+ end
506
+
507
+ it 'delete file or dir' do
508
+ stub_get(:pcs, '/file?' + query).to_return(status: 200, body: ft('delete.json'))
509
+ @client.delete('apitest')
510
+ a_get(:pcs, '/file?' + query).should have_been_made
511
+ end
512
+ end
513
+
514
+ describe 'when multiple files or dirs' do
515
+ let(:query) {
516
+ URI.encode_www_form({
517
+ method: 'delete',
518
+ access_token: 'ATOKEN',
519
+ param: JSON.dump({list: [ { path: '/apps/Backups/a/b' },
520
+ { path: '/apps/Backups/c' },
521
+ { path: '/apps/Backups/d/e/f' } ]
522
+ })
523
+ })
524
+ }
525
+ let(:paths) { %w[a/b c d/e/f] }
526
+
527
+ it 'raise exception when path is blank' do
528
+ expect { @client.delete([]) }.to raise_error(ArgumentError, 'path(s) must not be empty')
529
+ expect { @client.delete(nil) }.to raise_error(ArgumentError, 'path must be kind of String or Array')
530
+ expect { @client.delete(['']) }.to raise_error(ArgumentError, 'path must not be blank')
531
+ expect { @client.delete(['a'*1001]) }.to raise_error(ArgumentError, 'path length must not be greater than 1000')
532
+ end
533
+
534
+ it 'delete files or dirs' do
535
+ stub_get(:pcs, '/file?' + query).to_return(status: 200, body: ft('delete.json'))
536
+ @client.delete(paths)
537
+ a_get(:pcs, '/file?' + query).should have_been_made
538
+ end
539
+ end
540
+ end
541
+
542
+ describe '#search' do
543
+ let(:query) {
544
+ URI.encode_www_form({
545
+ method: 'search',
546
+ access_token: 'ATOKEN',
547
+ path: '/apps/Backups/apitest',
548
+ wd: 'keyword'
549
+ })
550
+ }
551
+ it 'search with default params' do
552
+ stub_get(:pcs, '/file?' + query + '&re=0').to_return(status:200, body: ft('search.json'))
553
+ @client.search('apitest', 'keyword')
554
+ a_get(:pcs, '/file?' + query + '&re=0').should have_been_made
555
+ end
556
+
557
+ it 'search recursively' do
558
+ stub_get(:pcs, '/file?' + query + '&re=1').to_return(status:200, body: ft('search.json'))
559
+ @client.search('apitest', 'keyword', true)
560
+ a_get(:pcs, '/file?' + query + '&re=1').should have_been_made
561
+ end
562
+
563
+ it 'raise exception when path is blank' do
564
+ expect { @client.search('', 'keyword') }.to raise_error(ArgumentError, 'path must not be blank')
565
+ end
566
+ end
567
+
568
+ describe '#thumbnail' do
569
+ let(:query) {
570
+ URI.encode_www_form({
571
+ method: 'generate',
572
+ access_token: 'ATOKEN',
573
+ path: '/apps/Backups/apitest/logo.png',
574
+ width: 120,
575
+ height: 40
576
+ })
577
+ }
578
+
579
+ it 'raise error when path is blank' do
580
+ expect { @client.thumbnail('', 100, 200) }.to raise_error(ArgumentError, 'path must not be blank')
581
+ end
582
+
583
+ it 'requests with default params' do
584
+ stub = stub_get(:pcs, '/thumbnail?' + query + '&quality=100').to_return(status: 200, body: ft('logo.png'))
585
+ @client.thumbnail('apitest/logo.png', 120, 40)
586
+ stub.should have_been_requested
587
+ end
588
+
589
+ it 'processes by block' do
590
+ stub = stub_get(:pcs, '/thumbnail?' + query + '&quality=100').to_return(status: 200, body: ft('logo.png'))
591
+ content = ''
592
+ @client.thumbnail('apitest/logo.png', 120, 40) do |c|
593
+ content << c
594
+ end
595
+ stub.should have_been_requested
596
+ expect(content).not_to be_empty
597
+ end
598
+ end
599
+
600
+ describe '#diff' do
601
+ let(:query) {
602
+ URI.encode_www_form({
603
+ method: 'diff',
604
+ access_token: 'ATOKEN'
605
+ })
606
+ }
607
+
608
+ it 'requests with default params' do
609
+ stub = stub_get(:pcs, '/file?' + query + '&cursor=null').to_return(status: 200, body: ft('diff.json'))
610
+ @client.diff
611
+ stub.should have_been_requested
612
+ end
613
+
614
+ it 'requests with cursor' do
615
+ stub = stub_get(:pcs, '/file?' + query + '&cursor=mynewcursor').to_return(status: 200, body: ft('diff.json'))
616
+ @client.diff('mynewcursor')
617
+ stub.should have_been_requested
618
+ end
619
+ end
620
+
621
+ describe '#streaming' do
622
+ let(:query) {
623
+ URI.encode_www_form({
624
+ method: 'streaming',
625
+ access_token: 'ATOKEN',
626
+ path: '/apps/Backups/hi.mp4',
627
+ type: 'M3U8_480_360'
628
+ })
629
+ }
630
+
631
+ it 'raise error when path is blank' do
632
+ expect { @client.streaming('', 'M3U8_480_360') }.to raise_error(ArgumentError, 'path must not be blank')
633
+ end
634
+
635
+ it 'requests streaming content' do
636
+ stub = stub_get(:pcs, '/file?' + query).to_return(status: 200, body: ft('streaming.m3u8'))
637
+ @client.streaming('hi.mp4', 'M3U8_480_360') do |c|
638
+ end
639
+ stub.should have_been_requested
640
+ end
641
+ end
642
+
643
+ describe '#stream_list' do
644
+ let(:query) {
645
+ URI.encode_www_form({
646
+ method: 'list',
647
+ access_token: 'ATOKEN',
648
+ type: 'video'
649
+ })
650
+ }
651
+
652
+ it 'requests with default parmas' do
653
+ stub = stub_get(:pcs, '/stream?' + query).to_return(status: 200, body: ft('stream_list.json'))
654
+ @client.stream_list('video')
655
+ stub.should have_been_requested
656
+ end
657
+
658
+ it 'requests stream list' do
659
+ stub = stub_get(:pcs, '/stream?' + query + '&start=10&limit=34&filter_path=/apps/Backups').to_return(status: 200, body: ft('stream_list.json'))
660
+ @client.stream_list('video', start: 10, limit: 34, filter_path: '/apps/Backups')
661
+ stub.should have_been_requested
662
+ end
663
+ end
664
+
665
+ describe '#rapid_upload' do
666
+ let(:query) {
667
+ URI.encode_www_form({
668
+ method: 'rapidupload',
669
+ access_token: 'ATOKEN',
670
+ path: '/apps/Backups/my_goo_gl.mkv',
671
+ :'content-length' => 74818037,
672
+ :'content-md5' => 'xxx',
673
+ :'slice-md5' => 'yyy',
674
+ :'content-crc32' => 'zzz'
675
+ })
676
+ }
677
+
678
+ it 'checks and edit path' do
679
+ stub = stub_post(:pcs, '/file?' + query + '&ondup=newcopy').to_return(status: 200, body: ft('rapidupload.json'))
680
+ expect { @client.rapid_upload('', 1, '2', '3', '4') }.to raise_error(ArgumentError, 'path must not be blank')
681
+ @client.rapid_upload('my|goo>gl.mkv', 74818037, 'xxx', 'yyy', 'zzz')
682
+ stub.should have_been_requested
683
+ end
684
+
685
+ it 'requests with default params' do
686
+ stub = stub_post(:pcs, '/file?' + query + '&ondup=newcopy').to_return(status: 200, body: ft('rapidupload.json'))
687
+ @client.rapid_upload('my?goo>gl.mkv', 74818037, 'xxx', 'yyy', 'zzz')
688
+ stub.should have_been_requested
689
+ end
690
+ end
691
+
692
+ describe '#add_task' do
693
+ let(:query) {
694
+ URI.encode_www_form({
695
+ method: 'add_task',
696
+ access_token: 'ATOKEN',
697
+ source_url: 'http://test.com/1.png',
698
+ timeout: 3600
699
+ })
700
+ }
701
+
702
+ it 'requests with default params' do
703
+ stub = stub_post(:pcs, '/services/cloud_dl?' + query + '&save_path=/apps/Backups/1.png').to_return(status: 200, body: ft('add_task.json'))
704
+ @client.add_task('http://test.com/1.png', save_path: '1.png')
705
+ stub.should have_been_requested
706
+ end
707
+
708
+ it 'requests with params' do
709
+ stub = stub_post(:pcs, '/services/cloud_dl?' + query + '&save_path=/apps/Backups/2.png&timeout=100&expires=200&rate_limit=300&callback=cb')
710
+ .to_return(status: 200, body: ft('add_task.json'))
711
+ @client.add_task('http://test.com/1.png', save_path: '2.png', timeout: 100, expires: 200, rate_limit: 300, callback: 'cb')
712
+ stub.should have_been_requested
713
+ end
714
+
715
+ it 'set save_path automatically' do
716
+ stub = stub_post(:pcs, '/services/cloud_dl?' + query + '&save_path=/apps/Backups/1.png').to_return(status: 200, body: ft('add_task.json'))
717
+ @client.add_task('http://test.com/1.png')
718
+ stub.should have_been_requested
719
+ end
720
+
721
+ it 'set save_path automatically' do
722
+ stub_request(:post, /https:\/\/pcs.baidu.com\/rest\/2.0\/pcs\/services\/cloud_dl/)
723
+ @client.add_task('http://test.com/')
724
+ q = 'save_path=/apps/Backups/' + Time.now.localtime.to_s[0..7]
725
+ WebMock.should have_requested(:post, /https:\/\/pcs.baidu.com\/rest\/2.0\/pcs\/services\/cloud_dl/).with { |req| req.uri.query.include? q }
726
+ end
727
+ end
728
+
729
+ describe '#query_task' do
730
+ let(:query) {
731
+ URI.encode_www_form({
732
+ method: 'query_task',
733
+ access_token: 'ATOKEN'
734
+ })
735
+ }
736
+
737
+ it 'requests with default params' do
738
+ stub = stub_post(:pcs, '/services/cloud_dl?' + query + '&task_ids=123')
739
+ .to_return(status: 200, body: ft('query_task_1.json'))
740
+ @client.query_task('123')
741
+ stub.should have_been_requested
742
+ end
743
+
744
+ it 'requests with params' do
745
+ stub = stub_post(:pcs, '/services/cloud_dl?' + query + '&task_ids=456,123&op_type=0&expires=10')
746
+ .to_return(status: 200, body: ft('query_task_0.json'))
747
+ @client.query_task([456, '123'], op_type: 0, expires: 10)
748
+ stub.should have_been_requested
749
+ end
750
+ end
751
+
752
+ describe '#list_task' do
753
+ let(:query) {
754
+ URI.encode_www_form({
755
+ method: 'list_task',
756
+ access_token: 'ATOKEN'
757
+ })
758
+ }
759
+
760
+ it 'requests with default params' do
761
+ stub = stub_post(:pcs, '/services/cloud_dl?' + query)
762
+ .to_return(status: 200, body: ft('list_task_1.json'))
763
+ @client.list_task
764
+ stub.should have_been_requested
765
+ end
766
+
767
+ it 'requests with params' do
768
+ stub = stub_post(:pcs, '/services/cloud_dl?' + query + '&start=10&limit=20&asc=1&need_task_info=0' \
769
+ '&status=2&create_time=NULL,1111&source_url=su&save_path=2.png&expires=30')
770
+ .to_return(status: 200, body: ft('list_task_0.json'))
771
+ @client.list_task(start: 10, limit: 20, asc: 1, need_task_info: 0, status: 2,
772
+ create_time: 'NULL,1111', source_url: 'su', save_path: '2.png', expires: 30)
773
+ stub.should have_been_requested
774
+ end
775
+ end
776
+
777
+ describe '#cancel_task' do
778
+ let(:query) {
779
+ URI.encode_www_form({
780
+ method: 'cancel_task',
781
+ access_token: 'ATOKEN',
782
+ task_id: '48393833'
783
+ })
784
+ }
785
+
786
+ it 'requests with default params' do
787
+ stub = stub_post(:pcs, '/services/cloud_dl?' + query).to_return(status: 200, body: ft('cancel_task.json'))
788
+ @client.cancel_task('48393833')
789
+ stub.should have_been_requested
790
+ end
791
+
792
+ it 'requests with params' do
793
+ stub = stub_post(:pcs, '/services/cloud_dl?' + query + '&expires=10').to_return(status: 200, body: ft('cancel_task.json'))
794
+ @client.cancel_task('48393833', 10)
795
+ stub.should have_been_requested
796
+ end
797
+ end
798
+
799
+ describe '#listrecycle' do
800
+ let(:query) {
801
+ URI.encode_www_form({
802
+ method: 'listrecycle',
803
+ access_token: 'ATOKEN'
804
+ })
805
+ }
806
+
807
+ it 'requests with default params' do
808
+ stub = stub_get(:pcs, '/file?' + query + '&start=0&limit=1000').to_return(status: 200, body: ft('listrecycle.json'))
809
+ @client.listrecycle
810
+ stub.should have_been_requested
811
+ end
812
+
813
+ it 'requests with params' do
814
+ stub = stub_get(:pcs, '/file?' + query + '&start=8&limit=30').to_return(status: 200, body: ft('listrecycle.json'))
815
+ @client.listrecycle(8, 30)
816
+ stub.should have_been_requested
817
+ end
818
+ end
819
+
820
+ describe '#restore' do
821
+ describe 'when single file or dir' do
822
+ let(:query) {
823
+ URI.encode_www_form({
824
+ method: 'restore',
825
+ access_token: 'ATOKEN',
826
+ fs_id: '8383838383'
827
+ })
828
+ }
829
+
830
+ it 'restore with fs_id' do
831
+ stub = stub_post(:pcs, '/file?' + query).to_return(status: 200, body: ft('restore.json'))
832
+ @client.restore('8383838383')
833
+ stub.should have_been_requested
834
+ end
835
+ end
836
+
837
+ describe 'when multiple files or dirs' do
838
+ let(:query) {
839
+ URI.encode_www_form({
840
+ method: 'restore',
841
+ access_token: 'ATOKEN',
842
+ param: JSON.dump({list: [ { fs_id: '333333' },
843
+ { fs_id: '444444' },
844
+ { fs_id: '555555' } ]
845
+ })
846
+ })
847
+ }
848
+ let(:fs_ids) { %w[333333 444444 555555] }
849
+
850
+ it 'restore with fs_id list' do
851
+ stub = stub_post(:pcs, '/file?' + query).to_return(status: 200, body: ft('restore.json'))
852
+ @client.restore(fs_ids)
853
+ stub.should have_been_requested
854
+ end
855
+ end
856
+
857
+ it 'restore with invalid fs_id(s)' do
858
+ expect { @client.restore({}) }.to raise_error(ArgumentError, 'fs_id(s) must be kind of String or Array')
859
+ expect { @client.restore(:invalid) }.to raise_error(ArgumentError, 'fs_id(s) must be kind of String or Array')
860
+ end
861
+ end
862
+
863
+ describe '#empty' do
864
+ let(:query) {
865
+ URI.encode_www_form({
866
+ method: 'delete',
867
+ access_token: 'ATOKEN',
868
+ type: 'recycle'
869
+ })
870
+ }
871
+
872
+ it 'empty recycle' do
873
+ stub = stub_post(:pcs, '/file?' + query).to_return(status: 200, body: ft('empty.json'))
874
+ @client.empty
875
+ stub.should have_been_requested
876
+ end
877
+ end
878
+ end