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