Add ability to add custom css/javascript
[oweals/peertube.git] / server / tests / api / videos / multiple-servers.ts
1 /* tslint:disable:no-unused-expression */
2
3 import * as chai from 'chai'
4 import 'mocha'
5 import { join } from 'path'
6 import * as request from 'supertest'
7 import { VideoPrivacy } from '../../../../shared/models/videos'
8 import { VideoComment, VideoCommentThreadTree } from '../../../../shared/models/videos/video-comment.model'
9
10 import {
11   addVideoChannel, checkVideoFilesWereRemoved, completeVideoCheck, createUser, dateIsValid, doubleFollow, flushAndRunMultipleServers,
12   flushTests, getVideo,
13   getVideoChannelsList, getVideosList, killallServers, rateVideo, removeVideo, ServerInfo, setAccessTokensToServers, testImage,
14   updateVideo, uploadVideo, userLogin, viewVideo, wait, webtorrentAdd
15 } from '../../utils'
16 import {
17   addVideoCommentReply, addVideoCommentThread, deleteVideoComment, getVideoCommentThreads,
18   getVideoThreadComments
19 } from '../../utils/videos/video-comments'
20
21 const expect = chai.expect
22
23 describe('Test multiple servers', function () {
24   let servers: ServerInfo[] = []
25   const toRemove = []
26   let videoUUID = ''
27   let videoChannelId: number
28
29   before(async function () {
30     this.timeout(120000)
31
32     servers = await flushAndRunMultipleServers(3)
33
34     // Get the access tokens
35     await setAccessTokensToServers(servers)
36
37     const videoChannel = {
38       name: 'my channel',
39       description: 'super channel'
40     }
41     await addVideoChannel(servers[0].url, servers[0].accessToken, videoChannel)
42     const channelRes = await getVideoChannelsList(servers[0].url, 0, 1)
43     videoChannelId = channelRes.body.data[0].id
44
45     // Server 1 and server 2 follow each other
46     await doubleFollow(servers[0], servers[1])
47     // Server 1 and server 3 follow each other
48     await doubleFollow(servers[0], servers[2])
49     // Server 2 and server 3 follow each other
50     await doubleFollow(servers[1], servers[2])
51   })
52
53   it('Should not have videos for all servers', async function () {
54     for (const server of servers) {
55       const res = await getVideosList(server.url)
56       const videos = res.body.data
57       expect(videos).to.be.an('array')
58       expect(videos.length).to.equal(0)
59     }
60   })
61
62   describe('Should upload the video and propagate on each server', function () {
63     it('Should upload the video on server 1 and propagate on each server', async function () {
64       this.timeout(25000)
65
66       const videoAttributes = {
67         name: 'my super name for server 1',
68         category: 5,
69         licence: 4,
70         language: 9,
71         nsfw: true,
72         description: 'my super description for server 1',
73         support: 'my super support text for server 1',
74         tags: [ 'tag1p1', 'tag2p1' ],
75         channelId: videoChannelId,
76         fixture: 'video_short1.webm'
77       }
78       await uploadVideo(servers[0].url, servers[0].accessToken, videoAttributes)
79
80       await wait(10000)
81
82       // All servers should have this video
83       for (const server of servers) {
84         const isLocal = server.url === 'http://localhost:9001'
85         const checkAttributes = {
86           name: 'my super name for server 1',
87           category: 5,
88           licence: 4,
89           language: 9,
90           nsfw: true,
91           description: 'my super description for server 1',
92           support: 'my super support text for server 1',
93           host: 'localhost:9001',
94           account: 'root',
95           isLocal,
96           duration: 10,
97           tags: [ 'tag1p1', 'tag2p1' ],
98           privacy: VideoPrivacy.PUBLIC,
99           commentsEnabled: true,
100           channel: {
101             name: 'my channel',
102             description: 'super channel',
103             isLocal
104           },
105           fixture: 'video_short1.webm',
106           files: [
107             {
108               resolution: 720,
109               size: 572456
110             }
111           ]
112         }
113
114         const res = await getVideosList(server.url)
115         const videos = res.body.data
116         expect(videos).to.be.an('array')
117         expect(videos.length).to.equal(1)
118         const video = videos[0]
119
120         await completeVideoCheck(server.url, video, checkAttributes)
121       }
122     })
123
124     it('Should upload the video on server 2 and propagate on each server', async function () {
125       this.timeout(50000)
126
127       const user = {
128         username: 'user1',
129         password: 'super_password'
130       }
131       await createUser(servers[1].url, servers[1].accessToken, user.username, user.password)
132       const userAccessToken = await userLogin(servers[1], user)
133
134       const videoAttributes = {
135         name: 'my super name for server 2',
136         category: 4,
137         licence: 3,
138         language: 11,
139         nsfw: true,
140         description: 'my super description for server 2',
141         support: 'my super support text for server 2',
142         tags: [ 'tag1p2', 'tag2p2', 'tag3p2' ],
143         fixture: 'video_short2.webm',
144         thumbnailfile: 'thumbnail.jpg',
145         previewfile: 'preview.jpg'
146       }
147       await uploadVideo(servers[1].url, userAccessToken, videoAttributes)
148
149       // Transcoding
150       await wait(30000)
151
152       // All servers should have this video
153       for (const server of servers) {
154         const isLocal = server.url === 'http://localhost:9002'
155         const checkAttributes = {
156           name: 'my super name for server 2',
157           category: 4,
158           licence: 3,
159           language: 11,
160           nsfw: true,
161           description: 'my super description for server 2',
162           support: 'my super support text for server 2',
163           host: 'localhost:9002',
164           account: 'user1',
165           isLocal,
166           commentsEnabled: true,
167           duration: 5,
168           tags: [ 'tag1p2', 'tag2p2', 'tag3p2' ],
169           privacy: VideoPrivacy.PUBLIC,
170           channel: {
171             name: 'Default user1 channel',
172             description: 'super channel',
173             isLocal
174           },
175           fixture: 'video_short2.webm',
176           files: [
177             {
178               resolution: 240,
179               size: 190000
180             },
181             {
182               resolution: 360,
183               size: 280000
184             },
185             {
186               resolution: 480,
187               size: 390000
188             },
189             {
190               resolution: 720,
191               size: 710000
192             }
193           ],
194           thumbnailfile: 'thumbnail',
195           previewfile: 'preview'
196         }
197
198         const res = await getVideosList(server.url)
199         const videos = res.body.data
200         expect(videos).to.be.an('array')
201         expect(videos.length).to.equal(2)
202         const video = videos[1]
203
204         await completeVideoCheck(server.url, video, checkAttributes)
205       }
206     })
207
208     it('Should upload two videos on server 3 and propagate on each server', async function () {
209       this.timeout(45000)
210
211       const videoAttributes1 = {
212         name: 'my super name for server 3',
213         category: 6,
214         licence: 5,
215         language: 11,
216         nsfw: true,
217         description: 'my super description for server 3',
218         support: 'my super support text for server 3',
219         tags: [ 'tag1p3' ],
220         fixture: 'video_short3.webm'
221       }
222       await uploadVideo(servers[2].url, servers[2].accessToken, videoAttributes1)
223
224       const videoAttributes2 = {
225         name: 'my super name for server 3-2',
226         category: 7,
227         licence: 6,
228         language: 12,
229         nsfw: false,
230         description: 'my super description for server 3-2',
231         support: 'my super support text for server 3-2',
232         tags: [ 'tag2p3', 'tag3p3', 'tag4p3' ],
233         fixture: 'video_short.webm'
234       }
235       await uploadVideo(servers[2].url, servers[2].accessToken, videoAttributes2)
236
237       await wait(10000)
238
239       // All servers should have this video
240       for (const server of servers) {
241         const isLocal = server.url === 'http://localhost:9003'
242         const res = await getVideosList(server.url)
243
244         const videos = res.body.data
245         expect(videos).to.be.an('array')
246         expect(videos.length).to.equal(4)
247
248         // We not sure about the order of the two last uploads
249         let video1 = null
250         let video2 = null
251         if (videos[2].name === 'my super name for server 3') {
252           video1 = videos[2]
253           video2 = videos[3]
254         } else {
255           video1 = videos[3]
256           video2 = videos[2]
257         }
258
259         const checkAttributesVideo1 = {
260           name: 'my super name for server 3',
261           category: 6,
262           licence: 5,
263           language: 11,
264           nsfw: true,
265           description: 'my super description for server 3',
266           support: 'my super support text for server 3',
267           host: 'localhost:9003',
268           account: 'root',
269           isLocal,
270           duration: 5,
271           commentsEnabled: true,
272           tags: [ 'tag1p3' ],
273           privacy: VideoPrivacy.PUBLIC,
274           channel: {
275             name: 'Default root channel',
276             description: '',
277             isLocal
278           },
279           fixture: 'video_short3.webm',
280           files: [
281             {
282               resolution: 720,
283               size: 292677
284             }
285           ]
286         }
287         await completeVideoCheck(server.url, video1, checkAttributesVideo1)
288
289         const checkAttributesVideo2 = {
290           name: 'my super name for server 3-2',
291           category: 7,
292           licence: 6,
293           language: 12,
294           nsfw: false,
295           description: 'my super description for server 3-2',
296           support: 'my super support text for server 3-2',
297           host: 'localhost:9003',
298           account: 'root',
299           commentsEnabled: true,
300           isLocal,
301           duration: 5,
302           tags: [ 'tag2p3', 'tag3p3', 'tag4p3' ],
303           privacy: VideoPrivacy.PUBLIC,
304           channel: {
305             name: 'Default root channel',
306             description: '',
307             isLocal
308           },
309           fixture: 'video_short.webm',
310           files: [
311             {
312               resolution: 720,
313               size: 218910
314             }
315           ]
316         }
317         await completeVideoCheck(server.url, video2, checkAttributesVideo2)
318       }
319     })
320   })
321
322   describe('Should seed the uploaded video', function () {
323     it('Should add the file 1 by asking server 3', async function () {
324       this.timeout(10000)
325
326       const res = await getVideosList(servers[2].url)
327
328       const video = res.body.data[0]
329       toRemove.push(res.body.data[2])
330       toRemove.push(res.body.data[3])
331
332       const res2 = await getVideo(servers[2].url, video.id)
333       const videoDetails = res2.body
334
335       const torrent = await webtorrentAdd(videoDetails.files[0].magnetUri, true)
336       expect(torrent.files).to.be.an('array')
337       expect(torrent.files.length).to.equal(1)
338       expect(torrent.files[0].path).to.exist.and.to.not.equal('')
339     })
340
341     it('Should add the file 2 by asking server 1', async function () {
342       this.timeout(10000)
343
344       const res = await getVideosList(servers[0].url)
345
346       const video = res.body.data[1]
347       const res2 = await getVideo(servers[0].url, video.id)
348       const videoDetails = res2.body
349
350       const torrent = await webtorrentAdd(videoDetails.files[0].magnetUri, true)
351       expect(torrent.files).to.be.an('array')
352       expect(torrent.files.length).to.equal(1)
353       expect(torrent.files[0].path).to.exist.and.to.not.equal('')
354     })
355
356     it('Should add the file 3 by asking server 2', async function () {
357       this.timeout(10000)
358
359       const res = await getVideosList(servers[1].url)
360
361       const video = res.body.data[2]
362       const res2 = await getVideo(servers[1].url, video.id)
363       const videoDetails = res2.body
364
365       const torrent = await webtorrentAdd(videoDetails.files[0].magnetUri, true)
366       expect(torrent.files).to.be.an('array')
367       expect(torrent.files.length).to.equal(1)
368       expect(torrent.files[0].path).to.exist.and.to.not.equal('')
369     })
370
371     it('Should add the file 3-2 by asking server 1', async function () {
372       this.timeout(10000)
373
374       const res = await getVideosList(servers[0].url)
375
376       const video = res.body.data[3]
377       const res2 = await getVideo(servers[0].url, video.id)
378       const videoDetails = res2.body
379
380       const torrent = await webtorrentAdd(videoDetails.files[0].magnetUri)
381       expect(torrent.files).to.be.an('array')
382       expect(torrent.files.length).to.equal(1)
383       expect(torrent.files[0].path).to.exist.and.to.not.equal('')
384     })
385
386     it('Should add the file 2 in 360p by asking server 1', async function () {
387       this.timeout(10000)
388
389       const res = await getVideosList(servers[0].url)
390
391       const video = res.body.data.find(v => v.name === 'my super name for server 2')
392       const res2 = await getVideo(servers[0].url, video.id)
393       const videoDetails = res2.body
394
395       const file = videoDetails.files.find(f => f.resolution === 360)
396       expect(file).not.to.be.undefined
397
398       const torrent = await webtorrentAdd(file.magnetUri)
399       expect(torrent.files).to.be.an('array')
400       expect(torrent.files.length).to.equal(1)
401       expect(torrent.files[0].path).to.exist.and.to.not.equal('')
402     })
403   })
404
405   describe('Should update video views, likes and dislikes', function () {
406     let localVideosServer3 = []
407     let remoteVideosServer1 = []
408     let remoteVideosServer2 = []
409     let remoteVideosServer3 = []
410
411     before(async function () {
412       const res1 = await getVideosList(servers[0].url)
413       remoteVideosServer1 = res1.body.data.filter(video => video.isLocal === false).map(video => video.uuid)
414
415       const res2 = await getVideosList(servers[1].url)
416       remoteVideosServer2 = res2.body.data.filter(video => video.isLocal === false).map(video => video.uuid)
417
418       const res3 = await getVideosList(servers[2].url)
419       localVideosServer3 = res3.body.data.filter(video => video.isLocal === true).map(video => video.uuid)
420       remoteVideosServer3 = res3.body.data.filter(video => video.isLocal === false).map(video => video.uuid)
421     })
422
423     it('Should view multiple videos on owned servers', async function () {
424       this.timeout(10000)
425
426       const tasks: Promise<any>[] = []
427       tasks.push(viewVideo(servers[2].url, localVideosServer3[0]))
428       tasks.push(viewVideo(servers[2].url, localVideosServer3[0]))
429       tasks.push(viewVideo(servers[2].url, localVideosServer3[0]))
430       tasks.push(viewVideo(servers[2].url, localVideosServer3[1]))
431
432       await Promise.all(tasks)
433
434       await wait(5000)
435
436       for (const server of servers) {
437         const res = await getVideosList(server.url)
438
439         const videos = res.body.data
440         const video0 = videos.find(v => v.uuid === localVideosServer3[0])
441         const video1 = videos.find(v => v.uuid === localVideosServer3[1])
442
443         expect(video0.views).to.equal(3)
444         expect(video1.views).to.equal(1)
445       }
446     })
447
448     it('Should view multiple videos on each servers', async function () {
449       this.timeout(15000)
450
451       const tasks: Promise<any>[] = []
452       tasks.push(viewVideo(servers[0].url, remoteVideosServer1[0]))
453       tasks.push(viewVideo(servers[1].url, remoteVideosServer2[0]))
454       tasks.push(viewVideo(servers[1].url, remoteVideosServer2[0]))
455       tasks.push(viewVideo(servers[2].url, remoteVideosServer3[0]))
456       tasks.push(viewVideo(servers[2].url, remoteVideosServer3[1]))
457       tasks.push(viewVideo(servers[2].url, remoteVideosServer3[1]))
458       tasks.push(viewVideo(servers[2].url, remoteVideosServer3[1]))
459       tasks.push(viewVideo(servers[2].url, localVideosServer3[1]))
460       tasks.push(viewVideo(servers[2].url, localVideosServer3[1]))
461       tasks.push(viewVideo(servers[2].url, localVideosServer3[1]))
462
463       await Promise.all(tasks)
464
465       await wait(10000)
466
467       let baseVideos = null
468
469       for (const server of servers) {
470         const res = await getVideosList(server.url)
471
472         const videos = res.body.data
473
474         // Initialize base videos for future comparisons
475         if (baseVideos === null) {
476           baseVideos = videos
477           continue
478         }
479
480         for (const baseVideo of baseVideos) {
481           const sameVideo = videos.find(video => video.name === baseVideo.name)
482           expect(baseVideo.views).to.equal(sameVideo.views)
483         }
484       }
485     })
486
487     it('Should like and dislikes videos on different services', async function () {
488       this.timeout(20000)
489
490       await rateVideo(servers[0].url, servers[0].accessToken, remoteVideosServer1[0], 'like')
491       await wait(200)
492       await rateVideo(servers[0].url, servers[0].accessToken, remoteVideosServer1[0], 'dislike')
493       await wait(200)
494       await rateVideo(servers[0].url, servers[0].accessToken, remoteVideosServer1[0], 'like')
495       await rateVideo(servers[2].url, servers[2].accessToken, localVideosServer3[1], 'like')
496       await wait(200)
497       await rateVideo(servers[2].url, servers[2].accessToken, localVideosServer3[1], 'dislike')
498       await rateVideo(servers[2].url, servers[2].accessToken, remoteVideosServer3[1], 'dislike')
499       await wait(200)
500       await rateVideo(servers[2].url, servers[2].accessToken, remoteVideosServer3[0], 'like')
501
502       await wait(10000)
503
504       let baseVideos = null
505       for (const server of servers) {
506         const res = await getVideosList(server.url)
507
508         const videos = res.body.data
509
510         // Initialize base videos for future comparisons
511         if (baseVideos === null) {
512           baseVideos = videos
513           continue
514         }
515
516         for (const baseVideo of baseVideos) {
517           const sameVideo = videos.find(video => video.name === baseVideo.name)
518           expect(baseVideo.likes).to.equal(sameVideo.likes)
519           expect(baseVideo.dislikes).to.equal(sameVideo.dislikes)
520         }
521       }
522     })
523   })
524
525   describe('Should manipulate these videos', function () {
526     it('Should update the video 3 by asking server 3', async function () {
527       this.timeout(10000)
528
529       const attributes = {
530         name: 'my super video updated',
531         category: 10,
532         licence: 7,
533         language: 13,
534         nsfw: true,
535         description: 'my super description updated',
536         support: 'my super support text updated',
537         tags: [ 'tag_up_1', 'tag_up_2' ],
538         thumbnailfile: 'thumbnail.jpg',
539         previewfile: 'preview.jpg'
540       }
541
542       await updateVideo(servers[2].url, servers[2].accessToken, toRemove[0].id, attributes)
543
544       await wait(5000)
545     })
546
547     it('Should have the video 3 updated on each server', async function () {
548       this.timeout(10000)
549
550       for (const server of servers) {
551         const res = await getVideosList(server.url)
552
553         const videos = res.body.data
554         const videoUpdated = videos.find(video => video.name === 'my super video updated')
555         expect(!!videoUpdated).to.be.true
556
557         const isLocal = server.url === 'http://localhost:9003'
558         const checkAttributes = {
559           name: 'my super video updated',
560           category: 10,
561           licence: 7,
562           language: 13,
563           nsfw: true,
564           description: 'my super description updated',
565           support: 'my super support text updated',
566           host: 'localhost:9003',
567           account: 'root',
568           isLocal,
569           duration: 5,
570           commentsEnabled: true,
571           tags: [ 'tag_up_1', 'tag_up_2' ],
572           privacy: VideoPrivacy.PUBLIC,
573           channel: {
574             name: 'Default root channel',
575             description: '',
576             isLocal
577           },
578           fixture: 'video_short3.webm',
579           files: [
580             {
581               resolution: 720,
582               size: 292677
583             }
584           ],
585           thumbnailfile: 'thumbnail',
586           previewfile: 'preview'
587         }
588         await completeVideoCheck(server.url, videoUpdated, checkAttributes)
589       }
590     })
591
592     it('Should remove the videos 3 and 3-2 by asking server 3', async function () {
593       this.timeout(10000)
594
595       await removeVideo(servers[2].url, servers[2].accessToken, toRemove[0].id)
596       await removeVideo(servers[2].url, servers[2].accessToken, toRemove[1].id)
597
598       await wait(5000)
599     })
600
601     it('Should not have files of videos 3 and 3-2 on each server', async function () {
602       for (const server of servers) {
603         await checkVideoFilesWereRemoved(toRemove[0].uuid, server.serverNumber)
604         await checkVideoFilesWereRemoved(toRemove[1].uuid, server.serverNumber)
605       }
606     })
607
608     it('Should have videos 1 and 3 on each server', async function () {
609       for (const server of servers) {
610         const res = await getVideosList(server.url)
611
612         const videos = res.body.data
613         expect(videos).to.be.an('array')
614         expect(videos.length).to.equal(2)
615         expect(videos[0].name).not.to.equal(videos[1].name)
616         expect(videos[0].name).not.to.equal(toRemove[0].name)
617         expect(videos[1].name).not.to.equal(toRemove[0].name)
618         expect(videos[0].name).not.to.equal(toRemove[1].name)
619         expect(videos[1].name).not.to.equal(toRemove[1].name)
620
621         videoUUID = videos.find(video => video.name === 'my super name for server 1').uuid
622       }
623     })
624
625     it('Should get the same video by UUID on each server', async function () {
626       let baseVideo = null
627       for (const server of servers) {
628         const res = await getVideo(server.url, videoUUID)
629
630         const video = res.body
631
632         if (baseVideo === null) {
633           baseVideo = video
634           continue
635         }
636
637         expect(baseVideo.name).to.equal(video.name)
638         expect(baseVideo.uuid).to.equal(video.uuid)
639         expect(baseVideo.category).to.equal(video.category)
640         expect(baseVideo.language).to.equal(video.language)
641         expect(baseVideo.licence).to.equal(video.licence)
642         expect(baseVideo.category).to.equal(video.category)
643         expect(baseVideo.nsfw).to.equal(video.nsfw)
644         expect(baseVideo.accountName).to.equal(video.accountName)
645         expect(baseVideo.tags).to.deep.equal(video.tags)
646       }
647     })
648
649     it('Should get the preview from each server', async function () {
650       for (const server of servers) {
651         const res = await getVideo(server.url, videoUUID)
652         const video = res.body
653
654         await testImage(server.url, 'video_short1-preview.webm', video.previewPath)
655       }
656     })
657   })
658
659   describe('Should comment these videos', function () {
660     it('Should add comment (threads and replies)', async function () {
661       this.timeout(25000)
662
663       {
664         const text = 'my super first comment'
665         await addVideoCommentThread(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID, text)
666       }
667
668       {
669         const text = 'my super second comment'
670         await addVideoCommentThread(servers[ 2 ].url, servers[ 2 ].accessToken, videoUUID, text)
671       }
672
673       await wait(5000)
674
675       {
676         const res = await getVideoCommentThreads(servers[1].url, videoUUID, 0, 5)
677         const threadId = res.body.data.find(c => c.text === 'my super first comment').id
678
679         const text = 'my super answer to thread 1'
680         await addVideoCommentReply(servers[ 1 ].url, servers[ 1 ].accessToken, videoUUID, threadId, text)
681       }
682
683       await wait(5000)
684
685       {
686         const res1 = await getVideoCommentThreads(servers[2].url, videoUUID, 0, 5)
687         const threadId = res1.body.data.find(c => c.text === 'my super first comment').id
688
689         const res2 = await getVideoThreadComments(servers[2].url, videoUUID, threadId)
690         const childCommentId = res2.body.children[0].comment.id
691
692         const text3 = 'my second answer to thread 1'
693         await addVideoCommentReply(servers[ 2 ].url, servers[ 2 ].accessToken, videoUUID, threadId, text3)
694
695         const text2 = 'my super answer to answer of thread 1'
696         await addVideoCommentReply(servers[ 2 ].url, servers[ 2 ].accessToken, videoUUID, childCommentId, text2)
697       }
698
699       await wait(5000)
700     })
701
702     it('Should have these threads', async function () {
703       for (const server of servers) {
704         const res = await getVideoCommentThreads(server.url, videoUUID, 0, 5)
705
706         expect(res.body.total).to.equal(2)
707         expect(res.body.data).to.be.an('array')
708         expect(res.body.data).to.have.lengthOf(2)
709
710         {
711           const comment: VideoComment = res.body.data.find(c => c.text === 'my super first comment')
712           expect(comment).to.not.be.undefined
713           expect(comment.inReplyToCommentId).to.be.null
714           expect(comment.account.name).to.equal('root')
715           expect(comment.account.host).to.equal('localhost:9001')
716           expect(comment.totalReplies).to.equal(3)
717           expect(dateIsValid(comment.createdAt as string)).to.be.true
718           expect(dateIsValid(comment.updatedAt as string)).to.be.true
719         }
720
721         {
722           const comment: VideoComment = res.body.data.find(c => c.text === 'my super second comment')
723           expect(comment).to.not.be.undefined
724           expect(comment.inReplyToCommentId).to.be.null
725           expect(comment.account.name).to.equal('root')
726           expect(comment.account.host).to.equal('localhost:9003')
727           expect(comment.totalReplies).to.equal(0)
728           expect(dateIsValid(comment.createdAt as string)).to.be.true
729           expect(dateIsValid(comment.updatedAt as string)).to.be.true
730         }
731       }
732     })
733
734     it('Should have these comments', async function () {
735       for (const server of servers) {
736         const res1 = await getVideoCommentThreads(server.url, videoUUID, 0, 5)
737         const threadId = res1.body.data.find(c => c.text === 'my super first comment').id
738
739         const res2 = await getVideoThreadComments(server.url, videoUUID, threadId)
740
741         const tree: VideoCommentThreadTree = res2.body
742         expect(tree.comment.text).equal('my super first comment')
743         expect(tree.comment.account.name).equal('root')
744         expect(tree.comment.account.host).equal('localhost:9001')
745         expect(tree.children).to.have.lengthOf(2)
746
747         const firstChild = tree.children[0]
748         expect(firstChild.comment.text).to.equal('my super answer to thread 1')
749         expect(firstChild.comment.account.name).equal('root')
750         expect(firstChild.comment.account.host).equal('localhost:9002')
751         expect(firstChild.children).to.have.lengthOf(1)
752
753         const childOfFirstChild = firstChild.children[0]
754         expect(childOfFirstChild.comment.text).to.equal('my super answer to answer of thread 1')
755         expect(childOfFirstChild.comment.account.name).equal('root')
756         expect(childOfFirstChild.comment.account.host).equal('localhost:9003')
757         expect(childOfFirstChild.children).to.have.lengthOf(0)
758
759         const secondChild = tree.children[1]
760         expect(secondChild.comment.text).to.equal('my second answer to thread 1')
761         expect(secondChild.comment.account.name).equal('root')
762         expect(secondChild.comment.account.host).equal('localhost:9003')
763         expect(secondChild.children).to.have.lengthOf(0)
764       }
765     })
766
767     it('Should delete the thread comments', async function () {
768       this.timeout(10000)
769
770       const res1 = await getVideoCommentThreads(servers[0].url, videoUUID, 0, 5)
771       const threadId = res1.body.data.find(c => c.text === 'my super first comment').id
772       await deleteVideoComment(servers[0].url, servers[0].accessToken, videoUUID, threadId)
773
774       await wait(5000)
775     })
776
777     it('Should have the thread comments deleted on other servers too', async function () {
778       for (const server of servers) {
779         const res = await getVideoCommentThreads(server.url, videoUUID, 0, 5)
780
781         expect(res.body.total).to.equal(1)
782         expect(res.body.data).to.be.an('array')
783         expect(res.body.data).to.have.lengthOf(1)
784
785         {
786           const comment: VideoComment = res.body.data[0]
787           expect(comment).to.not.be.undefined
788           expect(comment.inReplyToCommentId).to.be.null
789           expect(comment.account.name).to.equal('root')
790           expect(comment.account.host).to.equal('localhost:9003')
791           expect(comment.totalReplies).to.equal(0)
792           expect(dateIsValid(comment.createdAt as string)).to.be.true
793           expect(dateIsValid(comment.updatedAt as string)).to.be.true
794         }
795       }
796     })
797
798     it('Should disable comments', async function () {
799       this.timeout(20000)
800
801       const attributes = {
802         commentsEnabled: false
803       }
804
805       await updateVideo(servers[0].url, servers[0].accessToken, videoUUID, attributes)
806
807       await wait(5000)
808
809       for (const server of servers) {
810         const res = await getVideo(server.url, videoUUID)
811         expect(res.body.commentsEnabled).to.be.false
812
813         const text = 'my super forbidden comment'
814         await addVideoCommentThread(server.url, server.accessToken, videoUUID, text, 409)
815       }
816     })
817   })
818
819   describe('With minimum parameters', function () {
820     it('Should upload and propagate the video', async function () {
821       this.timeout(50000)
822
823       const path = '/api/v1/videos/upload'
824
825       const req = request(servers[1].url)
826         .post(path)
827         .set('Accept', 'application/json')
828         .set('Authorization', 'Bearer ' + servers[1].accessToken)
829         .field('name', 'minimum parameters')
830         .field('privacy', '1')
831         .field('nsfw', 'false')
832         .field('channelId', '1')
833         .field('commentsEnabled', 'true')
834
835       const filePath = join(__dirname, '..', '..', 'api', 'fixtures', 'video_short.webm')
836
837       await req.attach('videofile', filePath)
838         .expect(200)
839
840       await wait(25000)
841
842       for (const server of servers) {
843         const res = await getVideosList(server.url)
844         const video = res.body.data.find(v => v.name === 'minimum parameters')
845
846         const isLocal = server.url === 'http://localhost:9002'
847         const checkAttributes = {
848           name: 'minimum parameters',
849           category: null,
850           licence: null,
851           language: null,
852           nsfw: false,
853           description: null,
854           support: null,
855           host: 'localhost:9002',
856           account: 'root',
857           isLocal,
858           duration: 5,
859           commentsEnabled: true,
860           tags: [ ],
861           privacy: VideoPrivacy.PUBLIC,
862           channel: {
863             name: 'Default root channel',
864             description: '',
865             isLocal
866           },
867           fixture: 'video_short.webm',
868           files: [
869             {
870               resolution: 720,
871               size: 40315
872             },
873             {
874               resolution: 480,
875               size: 22808
876             },
877             {
878               resolution: 360,
879               size: 18617
880             },
881             {
882               resolution: 240,
883               size: 15217
884             }
885           ]
886         }
887         await completeVideoCheck(server.url, video, checkAttributes)
888       }
889     })
890   })
891
892   after(async function () {
893     killallServers(servers)
894
895     // Keep the logs if the test failed
896     if (this['ok']) {
897       await flushTests()
898     }
899   })
900 })