Add concept of video state, and add ability to wait transcoding before
[oweals/peertube.git] / server / tests / api / check-params / videos.ts
1 /* tslint:disable:no-unused-expression */
2
3 import * as chai from 'chai'
4 import { omit } from 'lodash'
5 import 'mocha'
6 import { join } from 'path'
7 import { VideoPrivacy } from '../../../../shared/models/videos/video-privacy.enum'
8 import {
9   createUser, flushTests, getMyUserInformation, getVideo, getVideosList, immutableAssign, killallServers, makeDeleteRequest,
10   makeGetRequest, makeUploadRequest, makePutBodyRequest, removeVideo, runServer, ServerInfo, setAccessTokensToServers, userLogin
11 } from '../../utils'
12 import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '../../utils/requests/check-api-params'
13 import { getAccountsList } from '../../utils/users/accounts'
14
15 const expect = chai.expect
16
17 describe('Test videos API validator', function () {
18   const path = '/api/v1/videos/'
19   let server: ServerInfo
20   let userAccessToken = ''
21   let accountName: string
22   let channelId: number
23   let channelUUID: string
24   let videoId
25
26   // ---------------------------------------------------------------
27
28   before(async function () {
29     this.timeout(30000)
30
31     await flushTests()
32
33     server = await runServer(1)
34
35     await setAccessTokensToServers([ server ])
36
37     const username = 'user1'
38     const password = 'my super password'
39     await createUser(server.url, server.accessToken, username, password)
40     userAccessToken = await userLogin(server, { username, password })
41
42     {
43       const res = await getMyUserInformation(server.url, server.accessToken)
44       channelId = res.body.videoChannels[ 0 ].id
45       channelUUID = res.body.videoChannels[ 0 ].uuid
46       accountName = res.body.account.name + '@' + res.body.account.host
47     }
48   })
49
50   describe('When listing a video', function () {
51     it('Should fail with a bad start pagination', async function () {
52       await checkBadStartPagination(server.url, path)
53     })
54
55     it('Should fail with a bad count pagination', async function () {
56       await checkBadCountPagination(server.url, path)
57     })
58
59     it('Should fail with an incorrect sort', async function () {
60       await checkBadSortPagination(server.url, path)
61     })
62
63     it('Should success with the correct parameters', async function () {
64       await makeGetRequest({ url: server.url, path, statusCodeExpected: 200 })
65     })
66   })
67
68   describe('When searching a video', function () {
69
70     it('Should fail with nothing', async function () {
71       await makeGetRequest({
72         url: server.url,
73         path: join(path, 'search'),
74         statusCodeExpected: 400
75       })
76     })
77
78     it('Should fail with a bad start pagination', async function () {
79       await checkBadStartPagination(server.url, join(path, 'search', 'test'))
80     })
81
82     it('Should fail with a bad count pagination', async function () {
83       await checkBadCountPagination(server.url, join(path, 'search', 'test'))
84     })
85
86     it('Should fail with an incorrect sort', async function () {
87       await checkBadSortPagination(server.url, join(path, 'search', 'test'))
88     })
89
90     it('Should success with the correct parameters', async function () {
91       await makeGetRequest({ url: server.url, path, statusCodeExpected: 200 })
92     })
93   })
94
95   describe('When listing my videos', function () {
96     const path = '/api/v1/users/me/videos'
97
98     it('Should fail with a bad start pagination', async function () {
99       await checkBadStartPagination(server.url, path, server.accessToken)
100     })
101
102     it('Should fail with a bad count pagination', async function () {
103       await checkBadCountPagination(server.url, path, server.accessToken)
104     })
105
106     it('Should fail with an incorrect sort', async function () {
107       await checkBadSortPagination(server.url, path, server.accessToken)
108     })
109
110     it('Should success with the correct parameters', async function () {
111       await makeGetRequest({ url: server.url, token: server.accessToken, path, statusCodeExpected: 200 })
112     })
113   })
114
115   describe('When listing account videos', function () {
116     let path: string
117
118     before(async function () {
119       path = '/api/v1/accounts/' + accountName + '/videos'
120     })
121
122     it('Should fail with a bad start pagination', async function () {
123       await checkBadStartPagination(server.url, path, server.accessToken)
124     })
125
126     it('Should fail with a bad count pagination', async function () {
127       await checkBadCountPagination(server.url, path, server.accessToken)
128     })
129
130     it('Should fail with an incorrect sort', async function () {
131       await checkBadSortPagination(server.url, path, server.accessToken)
132     })
133
134     it('Should success with the correct parameters', async function () {
135       await makeGetRequest({ url: server.url, path, statusCodeExpected: 200 })
136     })
137   })
138
139   describe('When listing video channel videos', function () {
140     let path: string
141
142     before(async function () {
143       path = '/api/v1/video-channels/' + channelUUID + '/videos'
144     })
145
146     it('Should fail with a bad start pagination', async function () {
147       await checkBadStartPagination(server.url, path, server.accessToken)
148     })
149
150     it('Should fail with a bad count pagination', async function () {
151       await checkBadCountPagination(server.url, path, server.accessToken)
152     })
153
154     it('Should fail with an incorrect sort', async function () {
155       await checkBadSortPagination(server.url, path, server.accessToken)
156     })
157
158     it('Should success with the correct parameters', async function () {
159       await makeGetRequest({ url: server.url, path, statusCodeExpected: 200 })
160     })
161   })
162
163   describe('When adding a video', function () {
164     let baseCorrectParams
165     const baseCorrectAttaches = {
166       'videofile': join(__dirname, '..', '..', 'fixtures', 'video_short.webm')
167     }
168
169     before(function () {
170       // Put in before to have channelId
171       baseCorrectParams = {
172         name: 'my super name',
173         category: 5,
174         licence: 1,
175         language: 'pt',
176         nsfw: false,
177         commentsEnabled: true,
178         waitTranscoding: true,
179         description: 'my super description',
180         support: 'my super support text',
181         tags: [ 'tag1', 'tag2' ],
182         privacy: VideoPrivacy.PUBLIC,
183         channelId: channelId
184       }
185     })
186
187     it('Should fail with nothing', async function () {
188       const fields = {}
189       const attaches = {}
190       await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
191     })
192
193     it('Should fail without name', async function () {
194       const fields = omit(baseCorrectParams, 'name')
195       const attaches = baseCorrectAttaches
196
197       await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
198     })
199
200     it('Should fail with a long name', async function () {
201       const fields = immutableAssign(baseCorrectParams, { name: 'super'.repeat(65) })
202       const attaches = baseCorrectAttaches
203
204       await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
205     })
206
207     it('Should fail with a bad category', async function () {
208       const fields = immutableAssign(baseCorrectParams, { category: 125 })
209       const attaches = baseCorrectAttaches
210
211       await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
212     })
213
214     it('Should fail with a bad licence', async function () {
215       const fields = immutableAssign(baseCorrectParams, { licence: 125 })
216       const attaches = baseCorrectAttaches
217
218       await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
219     })
220
221     it('Should fail with a bad language', async function () {
222       const fields = immutableAssign(baseCorrectParams, { language: 'a'.repeat(15) })
223       const attaches = baseCorrectAttaches
224
225       await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
226     })
227
228     it('Should fail with a long description', async function () {
229       const fields = immutableAssign(baseCorrectParams, { description: 'super'.repeat(2500) })
230       const attaches = baseCorrectAttaches
231
232       await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
233     })
234
235     it('Should fail with a long support text', async function () {
236       const fields = immutableAssign(baseCorrectParams, { support: 'super'.repeat(150) })
237       const attaches = baseCorrectAttaches
238
239       await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
240     })
241
242     it('Should fail without a channel', async function () {
243       const fields = omit(baseCorrectParams, 'channelId')
244       const attaches = baseCorrectAttaches
245
246       await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
247     })
248
249     it('Should fail with a bad channel', async function () {
250       const fields = immutableAssign(baseCorrectParams, { channelId: 545454 })
251       const attaches = baseCorrectAttaches
252
253       await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
254     })
255
256     it('Should fail with another user channel', async function () {
257       const user = {
258         username: 'fake',
259         password: 'fake_password'
260       }
261       await createUser(server.url, server.accessToken, user.username, user.password)
262
263       const accessTokenUser = await userLogin(server, user)
264       const res = await getMyUserInformation(server.url, accessTokenUser)
265       const customChannelId = res.body.videoChannels[0].id
266
267       const fields = immutableAssign(baseCorrectParams, { channelId: customChannelId })
268       const attaches = baseCorrectAttaches
269
270       await makeUploadRequest({ url: server.url, path: path + '/upload', token: userAccessToken, fields, attaches })
271     })
272
273     it('Should fail with too many tags', async function () {
274       const fields = immutableAssign(baseCorrectParams, { tags: [ 'tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6' ] })
275       const attaches = baseCorrectAttaches
276
277       await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
278     })
279
280     it('Should fail with a tag length too low', async function () {
281       const fields = immutableAssign(baseCorrectParams, { tags: [ 'tag1', 't' ] })
282       const attaches = baseCorrectAttaches
283
284       await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
285     })
286
287     it('Should fail with a tag length too big', async function () {
288       const fields = immutableAssign(baseCorrectParams, { tags: [ 'tag1', 'my_super_tag_too_long_long_long_long_long_long' ] })
289       const attaches = baseCorrectAttaches
290
291       await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
292     })
293
294     it('Should fail without an input file', async function () {
295       const fields = baseCorrectParams
296       const attaches = {}
297       await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
298     })
299
300     it('Should fail without an incorrect input file', async function () {
301       const fields = baseCorrectParams
302       const attaches = {
303         'videofile': join(__dirname, '..', '..', 'fixtures', 'video_short_fake.webm')
304       }
305       await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
306     })
307
308     it('Should fail with an incorrect thumbnail file', async function () {
309       const fields = baseCorrectParams
310       const attaches = {
311         'thumbnailfile': join(__dirname, '..', '..', 'fixtures', 'avatar.png'),
312         'videofile': join(__dirname, '..', '..', 'fixtures', 'video_short_fake.webm')
313       }
314
315       await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
316     })
317
318     it('Should fail with a big thumbnail file', async function () {
319       const fields = baseCorrectParams
320       const attaches = {
321         'thumbnailfile': join(__dirname, '..', '..', 'fixtures', 'avatar-big.png'),
322         'videofile': join(__dirname, '..', '..', 'fixtures', 'video_short_fake.webm')
323       }
324
325       await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
326     })
327
328     it('Should fail with an incorrect preview file', async function () {
329       const fields = baseCorrectParams
330       const attaches = {
331         'previewfile': join(__dirname, '..', '..', 'fixtures', 'avatar.png'),
332         'videofile': join(__dirname, '..', '..', 'fixtures', 'video_short_fake.webm')
333       }
334
335       await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
336     })
337
338     it('Should fail with a big preview file', async function () {
339       const fields = baseCorrectParams
340       const attaches = {
341         'previewfile': join(__dirname, '..', '..', 'fixtures', 'avatar-big.png'),
342         'videofile': join(__dirname, '..', '..', 'fixtures', 'video_short_fake.webm')
343       }
344
345       await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
346     })
347
348     it('Should succeed with the correct parameters', async function () {
349       this.timeout(10000)
350
351       const fields = baseCorrectParams
352
353       {
354         const attaches = baseCorrectAttaches
355         await makeUploadRequest({
356           url: server.url,
357           path: path + '/upload',
358           token: server.accessToken,
359           fields,
360           attaches,
361           statusCodeExpected: 200
362         })
363       }
364
365       {
366         const attaches = immutableAssign(baseCorrectAttaches, {
367           videofile: join(__dirname, '..', '..', 'fixtures', 'video_short.mp4')
368         })
369
370         await makeUploadRequest({
371           url: server.url,
372           path: path + '/upload',
373           token: server.accessToken,
374           fields,
375           attaches,
376           statusCodeExpected: 200
377         })
378       }
379
380       {
381         const attaches = immutableAssign(baseCorrectAttaches, {
382           videofile: join(__dirname, '..', '..', 'fixtures', 'video_short.ogv')
383         })
384
385         await makeUploadRequest({
386           url: server.url,
387           path: path + '/upload',
388           token: server.accessToken,
389           fields,
390           attaches,
391           statusCodeExpected: 200
392         })
393       }
394     })
395   })
396
397   describe('When updating a video', function () {
398     const baseCorrectParams = {
399       name: 'my super name',
400       category: 5,
401       licence: 2,
402       language: 'pt',
403       nsfw: false,
404       commentsEnabled: false,
405       description: 'my super description',
406       privacy: VideoPrivacy.PUBLIC,
407       tags: [ 'tag1', 'tag2' ]
408     }
409
410     before(async function () {
411       const res = await getVideosList(server.url)
412       videoId = res.body.data[0].uuid
413     })
414
415     it('Should fail with nothing', async function () {
416       const fields = {}
417       await makePutBodyRequest({ url: server.url, path, token: server.accessToken, fields })
418     })
419
420     it('Should fail without a valid uuid', async function () {
421       const fields = baseCorrectParams
422       await makePutBodyRequest({ url: server.url, path: path + 'blabla', token: server.accessToken, fields })
423     })
424
425     it('Should fail with an unknown id', async function () {
426       const fields = baseCorrectParams
427
428       await makePutBodyRequest({
429         url: server.url,
430         path: path + '4da6fde3-88f7-4d16-b119-108df5630b06',
431         token: server.accessToken,
432         fields,
433         statusCodeExpected: 404
434       })
435     })
436
437     it('Should fail with a long name', async function () {
438       const fields = immutableAssign(baseCorrectParams, { name: 'super'.repeat(65) })
439
440       await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields })
441     })
442
443     it('Should fail with a bad category', async function () {
444       const fields = immutableAssign(baseCorrectParams, { category: 125 })
445
446       await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields })
447     })
448
449     it('Should fail with a bad licence', async function () {
450       const fields = immutableAssign(baseCorrectParams, { licence: 125 })
451
452       await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields })
453     })
454
455     it('Should fail with a bad language', async function () {
456       const fields = immutableAssign(baseCorrectParams, { language: 'a'.repeat(15) })
457
458       await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields })
459     })
460
461     it('Should fail with a long description', async function () {
462       const fields = immutableAssign(baseCorrectParams, { description: 'super'.repeat(2500) })
463
464       await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields })
465     })
466
467     it('Should fail with a long support text', async function () {
468       const fields = immutableAssign(baseCorrectParams, { support: 'super'.repeat(150) })
469
470       await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields })
471     })
472
473     it('Should fail with a bad channel', async function () {
474       const fields = immutableAssign(baseCorrectParams, { channelId: 545454 })
475
476       await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields })
477     })
478
479     it('Should fail with too many tags', async function () {
480       const fields = immutableAssign(baseCorrectParams, { tags: [ 'tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6' ] })
481
482       await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields })
483     })
484
485     it('Should fail with a tag length too low', async function () {
486       const fields = immutableAssign(baseCorrectParams, { tags: [ 'tag1', 't' ] })
487
488       await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields })
489     })
490
491     it('Should fail with a tag length too big', async function () {
492       const fields = immutableAssign(baseCorrectParams, { tags: [ 'tag1', 'my_super_tag_too_long_long_long_long_long_long' ] })
493
494       await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields })
495     })
496
497     it('Should fail with an incorrect thumbnail file', async function () {
498       const fields = baseCorrectParams
499       const attaches = {
500         'thumbnailfile': join(__dirname, '..', '..', 'fixtures', 'avatar.png')
501       }
502
503       await makeUploadRequest({
504         url: server.url,
505         method: 'PUT',
506         path: path + videoId,
507         token: server.accessToken,
508         fields,
509         attaches
510       })
511     })
512
513     it('Should fail with a big thumbnail file', async function () {
514       const fields = baseCorrectParams
515       const attaches = {
516         'thumbnailfile': join(__dirname, '..', '..', 'fixtures', 'avatar-big.png')
517       }
518
519       await makeUploadRequest({
520         url: server.url,
521         method: 'PUT',
522         path: path + videoId,
523         token: server.accessToken,
524         fields,
525         attaches
526       })
527     })
528
529     it('Should fail with an incorrect preview file', async function () {
530       const fields = baseCorrectParams
531       const attaches = {
532         'previewfile': join(__dirname, '..', '..', 'fixtures', 'avatar.png')
533       }
534
535       await makeUploadRequest({
536         url: server.url,
537         method: 'PUT',
538         path: path + videoId,
539         token: server.accessToken,
540         fields,
541         attaches
542       })
543     })
544
545     it('Should fail with a big preview file', async function () {
546       const fields = baseCorrectParams
547       const attaches = {
548         'previewfile': join(__dirname, '..', '..', 'fixtures', 'avatar-big.png')
549       }
550
551       await makeUploadRequest({
552         url: server.url,
553         method: 'PUT',
554         path: path + videoId,
555         token: server.accessToken,
556         fields,
557         attaches
558       })
559     })
560
561     it('Should fail with a video of another user without the appropriate right', async function () {
562       const fields = baseCorrectParams
563
564       await makePutBodyRequest({ url: server.url, path: path + videoId, token: userAccessToken, fields, statusCodeExpected: 403 })
565     })
566
567     it('Should fail with a video of another server')
568
569     it('Should succeed with the correct parameters', async function () {
570       const fields = baseCorrectParams
571
572       await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields, statusCodeExpected: 204 })
573     })
574   })
575
576   describe('When getting a video', function () {
577     it('Should return the list of the videos with nothing', async function () {
578       const res = await makeGetRequest({
579         url: server.url,
580         path,
581         statusCodeExpected: 200
582       })
583
584       expect(res.body.data).to.be.an('array')
585       expect(res.body.data.length).to.equal(3)
586     })
587
588     it('Should fail without a correct uuid', async function () {
589       await getVideo(server.url, 'coucou', 400)
590     })
591
592     it('Should return 404 with an incorrect video', async function () {
593       await getVideo(server.url, '4da6fde3-88f7-4d16-b119-108df5630b06', 404)
594     })
595
596     it('Should succeed with the correct parameters', async function () {
597       await getVideo(server.url, videoId)
598     })
599   })
600
601   describe('When rating a video', function () {
602     let videoId
603
604     before(async function () {
605       const res = await getVideosList(server.url)
606       videoId = res.body.data[0].id
607     })
608
609     it('Should fail without a valid uuid', async function () {
610       const fields = {
611         rating: 'like'
612       }
613       await makePutBodyRequest({ url: server.url, path: path + 'blabla/rate', token: server.accessToken, fields })
614     })
615
616     it('Should fail with an unknown id', async function () {
617       const fields = {
618         rating: 'like'
619       }
620       await makePutBodyRequest({
621         url: server.url,
622         path: path + '4da6fde3-88f7-4d16-b119-108df5630b06/rate',
623         token: server.accessToken,
624         fields,
625         statusCodeExpected: 404
626       })
627     })
628
629     it('Should fail with a wrong rating', async function () {
630       const fields = {
631         rating: 'likes'
632       }
633       await makePutBodyRequest({ url: server.url, path: path + videoId + '/rate', token: server.accessToken, fields })
634     })
635
636     it('Should succeed with the correct parameters', async function () {
637       const fields = {
638         rating: 'like'
639       }
640       await makePutBodyRequest({
641         url: server.url,
642         path: path + videoId + '/rate',
643         token: server.accessToken,
644         fields,
645         statusCodeExpected: 204
646       })
647     })
648   })
649
650   describe('When removing a video', function () {
651     it('Should have 404 with nothing', async function () {
652       await makeDeleteRequest({
653         url: server.url,
654         path,
655         statusCodeExpected: 400
656       })
657     })
658
659     it('Should fail without a correct uuid', async function () {
660       await removeVideo(server.url, server.accessToken, 'hello', 400)
661     })
662
663     it('Should fail with a video which does not exist', async function () {
664       await removeVideo(server.url, server.accessToken, '4da6fde3-88f7-4d16-b119-108df5630b06', 404)
665     })
666
667     it('Should fail with a video of another user without the appropriate right', async function () {
668       await removeVideo(server.url, userAccessToken, videoId, 403)
669     })
670
671     it('Should fail with a video of another server')
672
673     it('Should succeed with the correct parameters', async function () {
674       await removeVideo(server.url, server.accessToken, videoId)
675     })
676   })
677
678   after(async function () {
679     killallServers([ server ])
680
681     // Keep the logs if the test failed
682     if (this['ok']) {
683       await flushTests()
684     }
685   })
686 })