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