]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/tests/api/videos/single-server.ts
Resumable video uploads (#3933)
[github/Chocobozzz/PeerTube.git] / server / tests / api / videos / single-server.ts
CommitLineData
a1587156 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
0e1dc3e7 2
f6d6e7f8 3import 'mocha'
8e7f08b5 4import * as chai from 'chai'
0e1dc3e7 5import { keyBy } from 'lodash'
f6d6e7f8 6
0e1dc3e7 7import {
3cd0734f 8 checkVideoFilesWereRemoved,
7c3b7976 9 cleanupTests,
3cd0734f 10 completeVideoCheck,
7c3b7976 11 flushAndRunServer,
3cd0734f
C
12 getVideo,
13 getVideoCategories,
14 getVideoLanguages,
15 getVideoLicences,
16 getVideoPrivacies,
17 getVideosList,
18 getVideosListPagination,
19 getVideosListSort,
d525fc39 20 getVideosWithFilters,
3cd0734f
C
21 rateVideo,
22 removeVideo,
3cd0734f
C
23 ServerInfo,
24 setAccessTokensToServers,
25 testImage,
26 updateVideo,
27 uploadVideo,
28 viewVideo,
29 wait
94565d52 30} from '../../../../shared/extra-utils'
f6d6e7f8 31import { VideoPrivacy } from '../../../../shared/models/videos'
32import { HttpStatusCode } from '@shared/core-utils'
0e1dc3e7 33
8e7f08b5
C
34const expect = chai.expect
35
9a27cdc2 36describe('Test a single server', function () {
0e1dc3e7 37
f6d6e7f8 38 function runSuite (mode: 'legacy' | 'resumable') {
39 let server: ServerInfo = null
40 let videoId = -1
41 let videoId2 = -1
42 let videoUUID = ''
43 let videosListBase: any[] = null
33ff70ba 44
f6d6e7f8 45 const getCheckAttributes = () => ({
0e1dc3e7
C
46 name: 'my super name',
47 category: 2,
0e1dc3e7 48 licence: 6,
f6d6e7f8 49 language: 'zh',
50 nsfw: true,
51 description: 'my super description',
52 support: 'my super support text',
53 account: {
54 name: 'root',
55 host: 'localhost:' + server.port
56 },
57 isLocal: true,
58 duration: 5,
59 tags: [ 'tag1', 'tag2', 'tag3' ],
60 privacy: VideoPrivacy.PUBLIC,
61 commentsEnabled: true,
62 downloadEnabled: true,
63 channel: {
64 displayName: 'Main root channel',
65 name: 'root_channel',
66 description: '',
67 isLocal: true
68 },
69 fixture: 'video_short.webm',
70 files: [
71 {
72 resolution: 720,
73 size: 218910
74 }
75 ]
76 })
77
78 const updateCheckAttributes = () => ({
79 name: 'my super video updated',
80 category: 4,
81 licence: 2,
82 language: 'ar',
83 nsfw: false,
84 description: 'my super description updated',
85 support: 'my super support text updated',
86 account: {
87 name: 'root',
88 host: 'localhost:' + server.port
89 },
90 isLocal: true,
91 tags: [ 'tagup1', 'tagup2' ],
92 privacy: VideoPrivacy.PUBLIC,
93 duration: 5,
94 commentsEnabled: false,
95 downloadEnabled: false,
96 channel: {
97 name: 'root_channel',
98 displayName: 'Main root channel',
99 description: '',
100 isLocal: true
101 },
102 fixture: 'video_short3.webm',
103 files: [
104 {
105 resolution: 720,
106 size: 292677
107 }
108 ]
109 })
0e1dc3e7 110
f6d6e7f8 111 before(async function () {
112 this.timeout(30000)
0e1dc3e7 113
f6d6e7f8 114 server = await flushAndRunServer(1)
0e1dc3e7 115
f6d6e7f8 116 await setAccessTokensToServers([ server ])
117 })
0e1dc3e7 118
f6d6e7f8 119 it('Should list video categories', async function () {
120 const res = await getVideoCategories(server.url)
b5c0e955 121
f6d6e7f8 122 const categories = res.body
123 expect(Object.keys(categories)).to.have.length.above(10)
b5c0e955 124
f6d6e7f8 125 expect(categories[11]).to.equal('News & Politics')
126 })
b5c0e955 127
f6d6e7f8 128 it('Should list video licences', async function () {
129 const res = await getVideoLicences(server.url)
b5c0e955 130
f6d6e7f8 131 const licences = res.body
132 expect(Object.keys(licences)).to.have.length.above(5)
b5c0e955 133
f6d6e7f8 134 expect(licences[3]).to.equal('Attribution - No Derivatives')
135 })
1f3e9fec 136
f6d6e7f8 137 it('Should list video languages', async function () {
138 const res = await getVideoLanguages(server.url)
6b616860 139
f6d6e7f8 140 const languages = res.body
141 expect(Object.keys(languages)).to.have.length.above(5)
0e1dc3e7 142
f6d6e7f8 143 expect(languages['ru']).to.equal('Russian')
144 })
0e1dc3e7 145
f6d6e7f8 146 it('Should list video privacies', async function () {
147 const res = await getVideoPrivacies(server.url)
0e1dc3e7 148
f6d6e7f8 149 const privacies = res.body
150 expect(Object.keys(privacies)).to.have.length.at.least(3)
0e1dc3e7 151
f6d6e7f8 152 expect(privacies[3]).to.equal('Private')
153 })
0e1dc3e7 154
f6d6e7f8 155 it('Should not have videos', async function () {
156 const res = await getVideosList(server.url)
0e1dc3e7 157
f6d6e7f8 158 expect(res.body.total).to.equal(0)
159 expect(res.body.data).to.be.an('array')
160 expect(res.body.data.length).to.equal(0)
161 })
0e1dc3e7 162
f6d6e7f8 163 it('Should upload the video', async function () {
164 this.timeout(10000)
0e1dc3e7 165
0e1dc3e7 166 const videoAttributes = {
f6d6e7f8 167 name: 'my super name',
0e1dc3e7 168 category: 2,
0e1dc3e7 169 nsfw: true,
f6d6e7f8 170 licence: 6,
171 tags: [ 'tag1', 'tag2', 'tag3' ]
0e1dc3e7 172 }
f6d6e7f8 173 const res = await uploadVideo(server.url, server.accessToken, videoAttributes, HttpStatusCode.OK_200, mode)
174 expect(res.body.video).to.not.be.undefined
175 expect(res.body.video.id).to.equal(1)
176 expect(res.body.video.uuid).to.have.length.above(5)
0e1dc3e7 177
f6d6e7f8 178 videoId = res.body.video.id
179 videoUUID = res.body.video.uuid
180 })
0e1dc3e7 181
f6d6e7f8 182 it('Should get and seed the uploaded video', async function () {
183 this.timeout(5000)
0e1dc3e7 184
f6d6e7f8 185 const res = await getVideosList(server.url)
0e1dc3e7 186
f6d6e7f8 187 expect(res.body.total).to.equal(1)
188 expect(res.body.data).to.be.an('array')
189 expect(res.body.data.length).to.equal(1)
0e1dc3e7 190
f6d6e7f8 191 const video = res.body.data[0]
192 await completeVideoCheck(server.url, video, getCheckAttributes())
193 })
0e1dc3e7 194
f6d6e7f8 195 it('Should get the video by UUID', async function () {
196 this.timeout(5000)
0e1dc3e7 197
f6d6e7f8 198 const res = await getVideo(server.url, videoUUID)
0e1dc3e7 199
f6d6e7f8 200 const video = res.body
201 await completeVideoCheck(server.url, video, getCheckAttributes())
202 })
0e1dc3e7 203
f6d6e7f8 204 it('Should have the views updated', async function () {
205 this.timeout(20000)
0e1dc3e7 206
f6d6e7f8 207 await viewVideo(server.url, videoId)
208 await viewVideo(server.url, videoId)
209 await viewVideo(server.url, videoId)
0e1dc3e7 210
f6d6e7f8 211 await wait(1500)
0e1dc3e7 212
f6d6e7f8 213 await viewVideo(server.url, videoId)
214 await viewVideo(server.url, videoId)
fe987656 215
f6d6e7f8 216 await wait(1500)
fe987656 217
f6d6e7f8 218 await viewVideo(server.url, videoId)
219 await viewVideo(server.url, videoId)
0e1dc3e7 220
f6d6e7f8 221 // Wait the repeatable job
222 await wait(8000)
0b74c74a 223
f6d6e7f8 224 const res = await getVideo(server.url, videoId)
0b74c74a 225
f6d6e7f8 226 const video = res.body
227 expect(video.views).to.equal(3)
228 })
923d3d5a 229
f6d6e7f8 230 it('Should remove the video', async function () {
231 await removeVideo(server.url, server.accessToken, videoId)
923d3d5a 232
f6d6e7f8 233 await checkVideoFilesWereRemoved(videoUUID, 1)
234 })
3d4e112d 235
f6d6e7f8 236 it('Should not have videos', async function () {
237 const res = await getVideosList(server.url)
3d4e112d 238
f6d6e7f8 239 expect(res.body.total).to.equal(0)
240 expect(res.body.data).to.be.an('array')
241 expect(res.body.data).to.have.lengthOf(0)
242 })
0e1dc3e7 243
f6d6e7f8 244 it('Should upload 6 videos', async function () {
245 this.timeout(25000)
d525fc39 246
f6d6e7f8 247 const videos = new Set([
248 'video_short.mp4', 'video_short.ogv', 'video_short.webm',
249 'video_short1.webm', 'video_short2.webm', 'video_short3.webm'
250 ])
d525fc39 251
f6d6e7f8 252 for (const video of videos) {
253 const videoAttributes = {
254 name: video + ' name',
255 description: video + ' description',
256 category: 2,
257 licence: 1,
258 language: 'en',
259 nsfw: true,
260 tags: [ 'tag1', 'tag2', 'tag3' ],
261 fixture: video
262 }
0e1dc3e7 263
f6d6e7f8 264 await uploadVideo(server.url, server.accessToken, videoAttributes, HttpStatusCode.OK_200, mode)
265 }
266 })
267
268 it('Should have the correct durations', async function () {
269 const res = await getVideosList(server.url)
270
271 expect(res.body.total).to.equal(6)
272 const videos = res.body.data
273 expect(videos).to.be.an('array')
274 expect(videos).to.have.lengthOf(6)
275
276 const videosByName = keyBy<{ duration: number }>(videos, 'name')
277 expect(videosByName['video_short.mp4 name'].duration).to.equal(5)
278 expect(videosByName['video_short.ogv name'].duration).to.equal(5)
279 expect(videosByName['video_short.webm name'].duration).to.equal(5)
280 expect(videosByName['video_short1.webm name'].duration).to.equal(10)
281 expect(videosByName['video_short2.webm name'].duration).to.equal(5)
282 expect(videosByName['video_short3.webm name'].duration).to.equal(5)
283 })
284
285 it('Should have the correct thumbnails', async function () {
286 const res = await getVideosList(server.url)
287
288 const videos = res.body.data
289 // For the next test
290 videosListBase = videos
291
292 for (const video of videos) {
293 const videoName = video.name.replace(' name', '')
294 await testImage(server.url, videoName, video.thumbnailPath)
295 }
296 })
297
298 it('Should list only the two first videos', async function () {
299 const res = await getVideosListPagination(server.url, 0, 2, 'name')
300
301 const videos = res.body.data
302 expect(res.body.total).to.equal(6)
303 expect(videos.length).to.equal(2)
304 expect(videos[0].name).to.equal(videosListBase[0].name)
305 expect(videos[1].name).to.equal(videosListBase[1].name)
306 })
307
308 it('Should list only the next three videos', async function () {
309 const res = await getVideosListPagination(server.url, 2, 3, 'name')
310
311 const videos = res.body.data
312 expect(res.body.total).to.equal(6)
313 expect(videos.length).to.equal(3)
314 expect(videos[0].name).to.equal(videosListBase[2].name)
315 expect(videos[1].name).to.equal(videosListBase[3].name)
316 expect(videos[2].name).to.equal(videosListBase[4].name)
317 })
318
319 it('Should list the last video', async function () {
320 const res = await getVideosListPagination(server.url, 5, 6, 'name')
321
322 const videos = res.body.data
323 expect(res.body.total).to.equal(6)
324 expect(videos.length).to.equal(1)
325 expect(videos[0].name).to.equal(videosListBase[5].name)
326 })
327
328 it('Should not have the total field', async function () {
329 const res = await getVideosListPagination(server.url, 5, 6, 'name', true)
330
331 const videos = res.body.data
332 expect(res.body.total).to.not.exist
333 expect(videos.length).to.equal(1)
334 expect(videos[0].name).to.equal(videosListBase[5].name)
335 })
336
337 it('Should list and sort by name in descending order', async function () {
338 const res = await getVideosListSort(server.url, '-name')
339
340 const videos = res.body.data
341 expect(res.body.total).to.equal(6)
342 expect(videos.length).to.equal(6)
343 expect(videos[0].name).to.equal('video_short.webm name')
344 expect(videos[1].name).to.equal('video_short.ogv name')
345 expect(videos[2].name).to.equal('video_short.mp4 name')
346 expect(videos[3].name).to.equal('video_short3.webm name')
347 expect(videos[4].name).to.equal('video_short2.webm name')
348 expect(videos[5].name).to.equal('video_short1.webm name')
349
350 videoId = videos[3].uuid
351 videoId2 = videos[5].uuid
352 })
353
354 it('Should list and sort by trending in descending order', async function () {
355 const res = await getVideosListPagination(server.url, 0, 2, '-trending')
356
357 const videos = res.body.data
358 expect(res.body.total).to.equal(6)
359 expect(videos.length).to.equal(2)
360 })
361
362 it('Should list and sort by hotness in descending order', async function () {
363 const res = await getVideosListPagination(server.url, 0, 2, '-hot')
364
365 const videos = res.body.data
366 expect(res.body.total).to.equal(6)
367 expect(videos.length).to.equal(2)
368 })
369
370 it('Should list and sort by best in descending order', async function () {
371 const res = await getVideosListPagination(server.url, 0, 2, '-best')
372
373 const videos = res.body.data
374 expect(res.body.total).to.equal(6)
375 expect(videos.length).to.equal(2)
376 })
377
378 it('Should update a video', async function () {
379 const attributes = {
380 name: 'my super video updated',
381 category: 4,
382 licence: 2,
383 language: 'ar',
384 nsfw: false,
385 description: 'my super description updated',
386 commentsEnabled: false,
387 downloadEnabled: false,
388 tags: [ 'tagup1', 'tagup2' ]
389 }
390 await updateVideo(server.url, server.accessToken, videoId, attributes)
391 })
0e1dc3e7 392
f6d6e7f8 393 it('Should filter by tags and category', async function () {
394 const res1 = await getVideosWithFilters(server.url, { tagsAllOf: [ 'tagup1', 'tagup2' ], categoryOneOf: [ 4 ] })
395 expect(res1.body.total).to.equal(1)
396 expect(res1.body.data[0].name).to.equal('my super video updated')
0e1dc3e7 397
f6d6e7f8 398 const res2 = await getVideosWithFilters(server.url, { tagsAllOf: [ 'tagup1', 'tagup2' ], categoryOneOf: [ 3 ] })
399 expect(res2.body.total).to.equal(0)
400 })
0e1dc3e7 401
f6d6e7f8 402 it('Should have the video updated', async function () {
403 this.timeout(60000)
0e1dc3e7 404
f6d6e7f8 405 const res = await getVideo(server.url, videoId)
406 const video = res.body
0e1dc3e7 407
f6d6e7f8 408 await completeVideoCheck(server.url, video, updateCheckAttributes())
409 })
0e1dc3e7 410
f6d6e7f8 411 it('Should update only the tags of a video', async function () {
412 const attributes = {
413 tags: [ 'supertag', 'tag1', 'tag2' ]
414 }
415 await updateVideo(server.url, server.accessToken, videoId, attributes)
0e1dc3e7 416
f6d6e7f8 417 const res = await getVideo(server.url, videoId)
418 const video = res.body
0e1dc3e7 419
f6d6e7f8 420 await completeVideoCheck(server.url, video, Object.assign(updateCheckAttributes(), attributes))
421 })
0e1dc3e7 422
f6d6e7f8 423 it('Should update only the description of a video', async function () {
424 const attributes = {
425 description: 'hello everybody'
426 }
427 await updateVideo(server.url, server.accessToken, videoId, attributes)
0e1dc3e7 428
f6d6e7f8 429 const res = await getVideo(server.url, videoId)
430 const video = res.body
0e1dc3e7 431
f6d6e7f8 432 const expectedAttributes = Object.assign(updateCheckAttributes(), { tags: [ 'supertag', 'tag1', 'tag2' ] }, attributes)
433 await completeVideoCheck(server.url, video, expectedAttributes)
434 })
0e1dc3e7 435
f6d6e7f8 436 it('Should like a video', async function () {
437 await rateVideo(server.url, server.accessToken, videoId, 'like')
0e1dc3e7 438
f6d6e7f8 439 const res = await getVideo(server.url, videoId)
440 const video = res.body
0e1dc3e7 441
f6d6e7f8 442 expect(video.likes).to.equal(1)
443 expect(video.dislikes).to.equal(0)
444 })
2fd59d7d 445
f6d6e7f8 446 it('Should dislike the same video', async function () {
447 await rateVideo(server.url, server.accessToken, videoId, 'dislike')
448
449 const res = await getVideo(server.url, videoId)
450 const video = res.body
451
452 expect(video.likes).to.equal(0)
453 expect(video.dislikes).to.equal(1)
454 })
455
456 it('Should sort by originallyPublishedAt', async function () {
2fd59d7d
C
457 {
458 const now = new Date()
459 const attributes = { originallyPublishedAt: now.toISOString() }
460 await updateVideo(server.url, server.accessToken, videoId, attributes)
461
462 const res = await getVideosListSort(server.url, '-originallyPublishedAt')
463 const names = res.body.data.map(v => v.name)
464
465 expect(names[0]).to.equal('my super video updated')
466 expect(names[1]).to.equal('video_short2.webm name')
467 expect(names[2]).to.equal('video_short1.webm name')
468 expect(names[3]).to.equal('video_short.webm name')
469 expect(names[4]).to.equal('video_short.ogv name')
470 expect(names[5]).to.equal('video_short.mp4 name')
471 }
472
473 {
474 const now = new Date()
475 const attributes = { originallyPublishedAt: now.toISOString() }
476 await updateVideo(server.url, server.accessToken, videoId2, attributes)
477
478 const res = await getVideosListSort(server.url, '-originallyPublishedAt')
479 const names = res.body.data.map(v => v.name)
480
481 expect(names[0]).to.equal('video_short1.webm name')
482 expect(names[1]).to.equal('my super video updated')
483 expect(names[2]).to.equal('video_short2.webm name')
484 expect(names[3]).to.equal('video_short.webm name')
485 expect(names[4]).to.equal('video_short.ogv name')
486 expect(names[5]).to.equal('video_short.mp4 name')
487 }
f6d6e7f8 488 })
489
490 after(async function () {
491 await cleanupTests([ server ])
492 })
493 }
494
495 describe('Legacy upload', function () {
496 runSuite('legacy')
2fd59d7d
C
497 })
498
f6d6e7f8 499 describe('Resumable upload', function () {
500 runSuite('resumable')
0e1dc3e7
C
501 })
502})