]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame_incremental - server/tests/api/check-params/video-playlists.ts
Add runner server tests
[github/Chocobozzz/PeerTube.git] / server / tests / api / check-params / video-playlists.ts
... / ...
CommitLineData
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared'
4import {
5 HttpStatusCode,
6 VideoPlaylistCreate,
7 VideoPlaylistCreateResult,
8 VideoPlaylistElementCreate,
9 VideoPlaylistElementUpdate,
10 VideoPlaylistPrivacy,
11 VideoPlaylistReorder,
12 VideoPlaylistType
13} from '@shared/models'
14import {
15 cleanupTests,
16 createSingleServer,
17 makeGetRequest,
18 PeerTubeServer,
19 PlaylistsCommand,
20 setAccessTokensToServers,
21 setDefaultVideoChannel
22} from '@shared/server-commands'
23
24describe('Test video playlists API validator', function () {
25 let server: PeerTubeServer
26 let userAccessToken: string
27
28 let playlist: VideoPlaylistCreateResult
29 let privatePlaylistUUID: string
30
31 let watchLaterPlaylistId: number
32 let videoId: number
33 let elementId: number
34
35 let command: PlaylistsCommand
36
37 // ---------------------------------------------------------------
38
39 before(async function () {
40 this.timeout(30000)
41
42 server = await createSingleServer(1)
43
44 await setAccessTokensToServers([ server ])
45 await setDefaultVideoChannel([ server ])
46
47 userAccessToken = await server.users.generateUserAndToken('user1')
48 videoId = (await server.videos.quickUpload({ name: 'video 1' })).id
49
50 command = server.playlists
51
52 {
53 const { data } = await command.listByAccount({
54 token: server.accessToken,
55 handle: 'root',
56 start: 0,
57 count: 5,
58 playlistType: VideoPlaylistType.WATCH_LATER
59 })
60 watchLaterPlaylistId = data[0].id
61 }
62
63 {
64 playlist = await command.create({
65 attributes: {
66 displayName: 'super playlist',
67 privacy: VideoPlaylistPrivacy.PUBLIC,
68 videoChannelId: server.store.channel.id
69 }
70 })
71 }
72
73 {
74 const created = await command.create({
75 attributes: {
76 displayName: 'private',
77 privacy: VideoPlaylistPrivacy.PRIVATE
78 }
79 })
80 privatePlaylistUUID = created.uuid
81 }
82 })
83
84 describe('When listing playlists', function () {
85 const globalPath = '/api/v1/video-playlists'
86 const accountPath = '/api/v1/accounts/root/video-playlists'
87 const videoChannelPath = '/api/v1/video-channels/root_channel/video-playlists'
88
89 it('Should fail with a bad start pagination', async function () {
90 await checkBadStartPagination(server.url, globalPath, server.accessToken)
91 await checkBadStartPagination(server.url, accountPath, server.accessToken)
92 await checkBadStartPagination(server.url, videoChannelPath, server.accessToken)
93 })
94
95 it('Should fail with a bad count pagination', async function () {
96 await checkBadCountPagination(server.url, globalPath, server.accessToken)
97 await checkBadCountPagination(server.url, accountPath, server.accessToken)
98 await checkBadCountPagination(server.url, videoChannelPath, server.accessToken)
99 })
100
101 it('Should fail with an incorrect sort', async function () {
102 await checkBadSortPagination(server.url, globalPath, server.accessToken)
103 await checkBadSortPagination(server.url, accountPath, server.accessToken)
104 await checkBadSortPagination(server.url, videoChannelPath, server.accessToken)
105 })
106
107 it('Should fail with a bad playlist type', async function () {
108 await makeGetRequest({ url: server.url, path: globalPath, query: { playlistType: 3 } })
109 await makeGetRequest({ url: server.url, path: accountPath, query: { playlistType: 3 } })
110 await makeGetRequest({ url: server.url, path: videoChannelPath, query: { playlistType: 3 } })
111 })
112
113 it('Should fail with a bad account parameter', async function () {
114 const accountPath = '/api/v1/accounts/root2/video-playlists'
115
116 await makeGetRequest({
117 url: server.url,
118 path: accountPath,
119 expectedStatus: HttpStatusCode.NOT_FOUND_404,
120 token: server.accessToken
121 })
122 })
123
124 it('Should fail with a bad video channel parameter', async function () {
125 const accountPath = '/api/v1/video-channels/bad_channel/video-playlists'
126
127 await makeGetRequest({
128 url: server.url,
129 path: accountPath,
130 expectedStatus: HttpStatusCode.NOT_FOUND_404,
131 token: server.accessToken
132 })
133 })
134
135 it('Should success with the correct parameters', async function () {
136 await makeGetRequest({ url: server.url, path: globalPath, expectedStatus: HttpStatusCode.OK_200, token: server.accessToken })
137 await makeGetRequest({ url: server.url, path: accountPath, expectedStatus: HttpStatusCode.OK_200, token: server.accessToken })
138 await makeGetRequest({
139 url: server.url,
140 path: videoChannelPath,
141 expectedStatus: HttpStatusCode.OK_200,
142 token: server.accessToken
143 })
144 })
145 })
146
147 describe('When listing videos of a playlist', function () {
148 const path = '/api/v1/video-playlists/'
149
150 it('Should fail with a bad start pagination', async function () {
151 await checkBadStartPagination(server.url, path + playlist.shortUUID + '/videos', server.accessToken)
152 })
153
154 it('Should fail with a bad count pagination', async function () {
155 await checkBadCountPagination(server.url, path + playlist.shortUUID + '/videos', server.accessToken)
156 })
157
158 it('Should success with the correct parameters', async function () {
159 await makeGetRequest({ url: server.url, path: path + playlist.shortUUID + '/videos', expectedStatus: HttpStatusCode.OK_200 })
160 })
161 })
162
163 describe('When getting a video playlist', function () {
164 it('Should fail with a bad id or uuid', async function () {
165 await command.get({ playlistId: 'toto', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
166 })
167
168 it('Should fail with an unknown playlist', async function () {
169 await command.get({ playlistId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
170 })
171
172 it('Should fail to get an unlisted playlist with the number id', async function () {
173 const playlist = await command.create({
174 attributes: {
175 displayName: 'super playlist',
176 videoChannelId: server.store.channel.id,
177 privacy: VideoPlaylistPrivacy.UNLISTED
178 }
179 })
180
181 await command.get({ playlistId: playlist.id, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
182 await command.get({ playlistId: playlist.uuid, expectedStatus: HttpStatusCode.OK_200 })
183 })
184
185 it('Should succeed with the correct params', async function () {
186 await command.get({ playlistId: playlist.uuid, expectedStatus: HttpStatusCode.OK_200 })
187 })
188 })
189
190 describe('When creating/updating a video playlist', function () {
191 const getBase = (
192 attributes?: Partial<VideoPlaylistCreate>,
193 wrapper?: Partial<Parameters<PlaylistsCommand['create']>[0]>
194 ) => {
195 return {
196 attributes: {
197 displayName: 'display name',
198 privacy: VideoPlaylistPrivacy.UNLISTED,
199 thumbnailfile: 'thumbnail.jpg',
200 videoChannelId: server.store.channel.id,
201
202 ...attributes
203 },
204
205 expectedStatus: HttpStatusCode.BAD_REQUEST_400,
206
207 ...wrapper
208 }
209 }
210 const getUpdate = (params: any, playlistId: number | string) => {
211 return { ...params, playlistId }
212 }
213
214 it('Should fail with an unauthenticated user', async function () {
215 const params = getBase({}, { token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
216
217 await command.create(params)
218 await command.update(getUpdate(params, playlist.shortUUID))
219 })
220
221 it('Should fail without displayName', async function () {
222 const params = getBase({ displayName: undefined })
223
224 await command.create(params)
225 })
226
227 it('Should fail with an incorrect display name', async function () {
228 const params = getBase({ displayName: 's'.repeat(300) })
229
230 await command.create(params)
231 await command.update(getUpdate(params, playlist.shortUUID))
232 })
233
234 it('Should fail with an incorrect description', async function () {
235 const params = getBase({ description: 't' })
236
237 await command.create(params)
238 await command.update(getUpdate(params, playlist.shortUUID))
239 })
240
241 it('Should fail with an incorrect privacy', async function () {
242 const params = getBase({ privacy: 45 as any })
243
244 await command.create(params)
245 await command.update(getUpdate(params, playlist.shortUUID))
246 })
247
248 it('Should fail with an unknown video channel id', async function () {
249 const params = getBase({ videoChannelId: 42 }, { expectedStatus: HttpStatusCode.NOT_FOUND_404 })
250
251 await command.create(params)
252 await command.update(getUpdate(params, playlist.shortUUID))
253 })
254
255 it('Should fail with an incorrect thumbnail file', async function () {
256 const params = getBase({ thumbnailfile: 'video_short.mp4' })
257
258 await command.create(params)
259 await command.update(getUpdate(params, playlist.shortUUID))
260 })
261
262 it('Should fail with a thumbnail file too big', async function () {
263 const params = getBase({ thumbnailfile: 'preview-big.png' })
264
265 await command.create(params)
266 await command.update(getUpdate(params, playlist.shortUUID))
267 })
268
269 it('Should fail to set "public" a playlist not assigned to a channel', async function () {
270 const params = getBase({ privacy: VideoPlaylistPrivacy.PUBLIC, videoChannelId: undefined })
271 const params2 = getBase({ privacy: VideoPlaylistPrivacy.PUBLIC, videoChannelId: 'null' as any })
272 const params3 = getBase({ privacy: undefined, videoChannelId: 'null' as any })
273
274 await command.create(params)
275 await command.create(params2)
276 await command.update(getUpdate(params, privatePlaylistUUID))
277 await command.update(getUpdate(params2, playlist.shortUUID))
278 await command.update(getUpdate(params3, playlist.shortUUID))
279 })
280
281 it('Should fail with an unknown playlist to update', async function () {
282 await command.update(getUpdate(
283 getBase({}, { expectedStatus: HttpStatusCode.NOT_FOUND_404 }),
284 42
285 ))
286 })
287
288 it('Should fail to update a playlist of another user', async function () {
289 await command.update(getUpdate(
290 getBase({}, { token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }),
291 playlist.shortUUID
292 ))
293 })
294
295 it('Should fail to update the watch later playlist', async function () {
296 await command.update(getUpdate(
297 getBase({}, { expectedStatus: HttpStatusCode.BAD_REQUEST_400 }),
298 watchLaterPlaylistId
299 ))
300 })
301
302 it('Should succeed with the correct params', async function () {
303 {
304 const params = getBase({}, { expectedStatus: HttpStatusCode.OK_200 })
305 await command.create(params)
306 }
307
308 {
309 const params = getBase({}, { expectedStatus: HttpStatusCode.NO_CONTENT_204 })
310 await command.update(getUpdate(params, playlist.shortUUID))
311 }
312 })
313 })
314
315 describe('When adding an element in a playlist', function () {
316 const getBase = (
317 attributes?: Partial<VideoPlaylistElementCreate>,
318 wrapper?: Partial<Parameters<PlaylistsCommand['addElement']>[0]>
319 ) => {
320 return {
321 attributes: {
322 videoId,
323 startTimestamp: 2,
324 stopTimestamp: 3,
325
326 ...attributes
327 },
328
329 expectedStatus: HttpStatusCode.BAD_REQUEST_400,
330 playlistId: playlist.id,
331
332 ...wrapper
333 }
334 }
335
336 it('Should fail with an unauthenticated user', async function () {
337 const params = getBase({}, { token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
338 await command.addElement(params)
339 })
340
341 it('Should fail with the playlist of another user', async function () {
342 const params = getBase({}, { token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
343 await command.addElement(params)
344 })
345
346 it('Should fail with an unknown or incorrect playlist id', async function () {
347 {
348 const params = getBase({}, { playlistId: 'toto' })
349 await command.addElement(params)
350 }
351
352 {
353 const params = getBase({}, { playlistId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
354 await command.addElement(params)
355 }
356 })
357
358 it('Should fail with an unknown or incorrect video id', async function () {
359 const params = getBase({ videoId: 42 }, { expectedStatus: HttpStatusCode.NOT_FOUND_404 })
360 await command.addElement(params)
361 })
362
363 it('Should fail with a bad start/stop timestamp', async function () {
364 {
365 const params = getBase({ startTimestamp: -42 })
366 await command.addElement(params)
367 }
368
369 {
370 const params = getBase({ stopTimestamp: 'toto' as any })
371 await command.addElement(params)
372 }
373 })
374
375 it('Succeed with the correct params', async function () {
376 const params = getBase({}, { expectedStatus: HttpStatusCode.OK_200 })
377 const created = await command.addElement(params)
378 elementId = created.id
379 })
380 })
381
382 describe('When updating an element in a playlist', function () {
383 const getBase = (
384 attributes?: Partial<VideoPlaylistElementUpdate>,
385 wrapper?: Partial<Parameters<PlaylistsCommand['updateElement']>[0]>
386 ) => {
387 return {
388 attributes: {
389 startTimestamp: 1,
390 stopTimestamp: 2,
391
392 ...attributes
393 },
394
395 elementId,
396 playlistId: playlist.id,
397 expectedStatus: HttpStatusCode.BAD_REQUEST_400,
398
399 ...wrapper
400 }
401 }
402
403 it('Should fail with an unauthenticated user', async function () {
404 const params = getBase({}, { token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
405 await command.updateElement(params)
406 })
407
408 it('Should fail with the playlist of another user', async function () {
409 const params = getBase({}, { token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
410 await command.updateElement(params)
411 })
412
413 it('Should fail with an unknown or incorrect playlist id', async function () {
414 {
415 const params = getBase({}, { playlistId: 'toto' })
416 await command.updateElement(params)
417 }
418
419 {
420 const params = getBase({}, { playlistId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
421 await command.updateElement(params)
422 }
423 })
424
425 it('Should fail with an unknown or incorrect playlistElement id', async function () {
426 {
427 const params = getBase({}, { elementId: 'toto' })
428 await command.updateElement(params)
429 }
430
431 {
432 const params = getBase({}, { elementId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
433 await command.updateElement(params)
434 }
435 })
436
437 it('Should fail with a bad start/stop timestamp', async function () {
438 {
439 const params = getBase({ startTimestamp: 'toto' as any })
440 await command.updateElement(params)
441 }
442
443 {
444 const params = getBase({ stopTimestamp: -42 })
445 await command.updateElement(params)
446 }
447 })
448
449 it('Should fail with an unknown element', async function () {
450 const params = getBase({}, { elementId: 888, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
451 await command.updateElement(params)
452 })
453
454 it('Succeed with the correct params', async function () {
455 const params = getBase({}, { expectedStatus: HttpStatusCode.NO_CONTENT_204 })
456 await command.updateElement(params)
457 })
458 })
459
460 describe('When reordering elements of a playlist', function () {
461 let videoId3: number
462 let videoId4: number
463
464 const getBase = (
465 attributes?: Partial<VideoPlaylistReorder>,
466 wrapper?: Partial<Parameters<PlaylistsCommand['reorderElements']>[0]>
467 ) => {
468 return {
469 attributes: {
470 startPosition: 1,
471 insertAfterPosition: 2,
472 reorderLength: 3,
473
474 ...attributes
475 },
476
477 playlistId: playlist.shortUUID,
478 expectedStatus: HttpStatusCode.BAD_REQUEST_400,
479
480 ...wrapper
481 }
482 }
483
484 before(async function () {
485 videoId3 = (await server.videos.quickUpload({ name: 'video 3' })).id
486 videoId4 = (await server.videos.quickUpload({ name: 'video 4' })).id
487
488 for (const id of [ videoId3, videoId4 ]) {
489 await command.addElement({ playlistId: playlist.shortUUID, attributes: { videoId: id } })
490 }
491 })
492
493 it('Should fail with an unauthenticated user', async function () {
494 const params = getBase({}, { token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
495 await command.reorderElements(params)
496 })
497
498 it('Should fail with the playlist of another user', async function () {
499 const params = getBase({}, { token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
500 await command.reorderElements(params)
501 })
502
503 it('Should fail with an invalid playlist', async function () {
504 {
505 const params = getBase({}, { playlistId: 'toto' })
506 await command.reorderElements(params)
507 }
508
509 {
510 const params = getBase({}, { playlistId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
511 await command.reorderElements(params)
512 }
513 })
514
515 it('Should fail with an invalid start position', async function () {
516 {
517 const params = getBase({ startPosition: -1 })
518 await command.reorderElements(params)
519 }
520
521 {
522 const params = getBase({ startPosition: 'toto' as any })
523 await command.reorderElements(params)
524 }
525
526 {
527 const params = getBase({ startPosition: 42 })
528 await command.reorderElements(params)
529 }
530 })
531
532 it('Should fail with an invalid insert after position', async function () {
533 {
534 const params = getBase({ insertAfterPosition: 'toto' as any })
535 await command.reorderElements(params)
536 }
537
538 {
539 const params = getBase({ insertAfterPosition: -2 })
540 await command.reorderElements(params)
541 }
542
543 {
544 const params = getBase({ insertAfterPosition: 42 })
545 await command.reorderElements(params)
546 }
547 })
548
549 it('Should fail with an invalid reorder length', async function () {
550 {
551 const params = getBase({ reorderLength: 'toto' as any })
552 await command.reorderElements(params)
553 }
554
555 {
556 const params = getBase({ reorderLength: -2 })
557 await command.reorderElements(params)
558 }
559
560 {
561 const params = getBase({ reorderLength: 42 })
562 await command.reorderElements(params)
563 }
564 })
565
566 it('Succeed with the correct params', async function () {
567 const params = getBase({}, { expectedStatus: HttpStatusCode.NO_CONTENT_204 })
568 await command.reorderElements(params)
569 })
570 })
571
572 describe('When checking exists in playlist endpoint', function () {
573 const path = '/api/v1/users/me/video-playlists/videos-exist'
574
575 it('Should fail with an unauthenticated user', async function () {
576 await makeGetRequest({
577 url: server.url,
578 path,
579 query: { videoIds: [ 1, 2 ] },
580 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
581 })
582 })
583
584 it('Should fail with invalid video ids', async function () {
585 await makeGetRequest({
586 url: server.url,
587 token: server.accessToken,
588 path,
589 query: { videoIds: 'toto' }
590 })
591
592 await makeGetRequest({
593 url: server.url,
594 token: server.accessToken,
595 path,
596 query: { videoIds: [ 'toto' ] }
597 })
598
599 await makeGetRequest({
600 url: server.url,
601 token: server.accessToken,
602 path,
603 query: { videoIds: [ 1, 'toto' ] }
604 })
605 })
606
607 it('Should succeed with the correct params', async function () {
608 await makeGetRequest({
609 url: server.url,
610 token: server.accessToken,
611 path,
612 query: { videoIds: [ 1, 2 ] },
613 expectedStatus: HttpStatusCode.OK_200
614 })
615 })
616 })
617
618 describe('When deleting an element in a playlist', function () {
619 const getBase = (wrapper: Partial<Parameters<PlaylistsCommand['removeElement']>[0]>) => {
620 return {
621 elementId,
622 playlistId: playlist.uuid,
623 expectedStatus: HttpStatusCode.BAD_REQUEST_400,
624
625 ...wrapper
626 }
627 }
628
629 it('Should fail with an unauthenticated user', async function () {
630 const params = getBase({ token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
631 await command.removeElement(params)
632 })
633
634 it('Should fail with the playlist of another user', async function () {
635 const params = getBase({ token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
636 await command.removeElement(params)
637 })
638
639 it('Should fail with an unknown or incorrect playlist id', async function () {
640 {
641 const params = getBase({ playlistId: 'toto' })
642 await command.removeElement(params)
643 }
644
645 {
646 const params = getBase({ playlistId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
647 await command.removeElement(params)
648 }
649 })
650
651 it('Should fail with an unknown or incorrect video id', async function () {
652 {
653 const params = getBase({ elementId: 'toto' as any })
654 await command.removeElement(params)
655 }
656
657 {
658 const params = getBase({ elementId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
659 await command.removeElement(params)
660 }
661 })
662
663 it('Should fail with an unknown element', async function () {
664 const params = getBase({ elementId: 888, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
665 await command.removeElement(params)
666 })
667
668 it('Succeed with the correct params', async function () {
669 const params = getBase({ expectedStatus: HttpStatusCode.NO_CONTENT_204 })
670 await command.removeElement(params)
671 })
672 })
673
674 describe('When deleting a playlist', function () {
675 it('Should fail with an unknown playlist', async function () {
676 await command.delete({ playlistId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
677 })
678
679 it('Should fail with a playlist of another user', async function () {
680 await command.delete({ token: userAccessToken, playlistId: playlist.uuid, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
681 })
682
683 it('Should fail with the watch later playlist', async function () {
684 await command.delete({ playlistId: watchLaterPlaylistId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
685 })
686
687 it('Should succeed with the correct params', async function () {
688 await command.delete({ playlistId: playlist.uuid })
689 })
690 })
691
692 after(async function () {
693 await cleanupTests([ server ])
694 })
695})