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