1 /* tslint:disable:no-unused-expression */
3 import * as chai from 'chai'
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'
12 checkVideoFilesWereRemoved,
17 flushAndRunMultipleServers,
26 setAccessTokensToServers,
37 addVideoCommentThread,
39 getVideoCommentThreads,
40 getVideoThreadComments
41 } from '../../utils/videos/video-comments'
43 const expect = chai.expect
45 describe('Test multiple servers', function () {
46 let servers: ServerInfo[] = []
49 let videoChannelId: number
51 before(async function () {
54 servers = await flushAndRunMultipleServers(3)
56 // Get the access tokens
57 await setAccessTokensToServers(servers)
59 const videoChannel = {
61 description: 'super channel'
63 await addVideoChannel(servers[0].url, servers[0].accessToken, videoChannel)
64 const channelRes = await getVideoChannelsList(servers[0].url, 0, 1)
65 videoChannelId = channelRes.body.data[0].id
67 // Server 1 and server 2 follow each other
68 await doubleFollow(servers[0], servers[1])
69 // Server 1 and server 3 follow each other
70 await doubleFollow(servers[0], servers[2])
71 // Server 2 and server 3 follow each other
72 await doubleFollow(servers[1], servers[2])
75 it('Should not have videos for all servers', async function () {
76 for (const server of servers) {
77 const res = await getVideosList(server.url)
78 const videos = res.body.data
79 expect(videos).to.be.an('array')
80 expect(videos.length).to.equal(0)
84 describe('Should upload the video and propagate on each server', function () {
85 it('Should upload the video on server 1 and propagate on each server', async function () {
88 const videoAttributes = {
89 name: 'my super name for server 1',
94 description: 'my super description for server 1',
95 support: 'my super support text for server 1',
96 tags: [ 'tag1p1', 'tag2p1' ],
97 channelId: videoChannelId,
98 fixture: 'video_short1.webm'
100 await uploadVideo(servers[0].url, servers[0].accessToken, videoAttributes)
104 // All servers should have this video
105 for (const server of servers) {
106 const isLocal = server.url === 'http://localhost:9001'
107 const checkAttributes = {
108 name: 'my super name for server 1',
113 description: 'my super description for server 1',
114 support: 'my super support text for server 1',
117 host: 'localhost:9001'
121 tags: [ 'tag1p1', 'tag2p1' ],
122 privacy: VideoPrivacy.PUBLIC,
123 commentsEnabled: true,
126 description: 'super channel',
129 fixture: 'video_short1.webm',
138 const res = await getVideosList(server.url)
139 const videos = res.body.data
140 expect(videos).to.be.an('array')
141 expect(videos.length).to.equal(1)
142 const video = videos[0]
144 await completeVideoCheck(server.url, video, checkAttributes)
148 it('Should upload the video on server 2 and propagate on each server', async function () {
153 password: 'super_password'
155 await createUser(servers[1].url, servers[1].accessToken, user.username, user.password)
156 const userAccessToken = await userLogin(servers[1], user)
158 const videoAttributes = {
159 name: 'my super name for server 2',
164 description: 'my super description for server 2',
165 support: 'my super support text for server 2',
166 tags: [ 'tag1p2', 'tag2p2', 'tag3p2' ],
167 fixture: 'video_short2.webm',
168 thumbnailfile: 'thumbnail.jpg',
169 previewfile: 'preview.jpg'
171 await uploadVideo(servers[1].url, userAccessToken, videoAttributes)
176 // All servers should have this video
177 for (const server of servers) {
178 const isLocal = server.url === 'http://localhost:9002'
179 const checkAttributes = {
180 name: 'my super name for server 2',
185 description: 'my super description for server 2',
186 support: 'my super support text for server 2',
189 host: 'localhost:9002'
192 commentsEnabled: true,
194 tags: [ 'tag1p2', 'tag2p2', 'tag3p2' ],
195 privacy: VideoPrivacy.PUBLIC,
197 name: 'Default user1 channel',
198 description: 'super channel',
201 fixture: 'video_short2.webm',
220 thumbnailfile: 'thumbnail',
221 previewfile: 'preview'
224 const res = await getVideosList(server.url)
225 const videos = res.body.data
226 expect(videos).to.be.an('array')
227 expect(videos.length).to.equal(2)
228 const video = videos[1]
230 await completeVideoCheck(server.url, video, checkAttributes)
234 it('Should upload two videos on server 3 and propagate on each server', async function () {
237 const videoAttributes1 = {
238 name: 'my super name for server 3',
243 description: 'my super description for server 3',
244 support: 'my super support text for server 3',
246 fixture: 'video_short3.webm'
248 await uploadVideo(servers[2].url, servers[2].accessToken, videoAttributes1)
250 const videoAttributes2 = {
251 name: 'my super name for server 3-2',
256 description: 'my super description for server 3-2',
257 support: 'my super support text for server 3-2',
258 tags: [ 'tag2p3', 'tag3p3', 'tag4p3' ],
259 fixture: 'video_short.webm'
261 await uploadVideo(servers[2].url, servers[2].accessToken, videoAttributes2)
265 // All servers should have this video
266 for (const server of servers) {
267 const isLocal = server.url === 'http://localhost:9003'
268 const res = await getVideosList(server.url)
270 const videos = res.body.data
271 expect(videos).to.be.an('array')
272 expect(videos.length).to.equal(4)
274 // We not sure about the order of the two last uploads
277 if (videos[2].name === 'my super name for server 3') {
285 const checkAttributesVideo1 = {
286 name: 'my super name for server 3',
291 description: 'my super description for server 3',
292 support: 'my super support text for server 3',
295 host: 'localhost:9003'
299 commentsEnabled: true,
301 privacy: VideoPrivacy.PUBLIC,
303 name: 'Default root channel',
307 fixture: 'video_short3.webm',
315 await completeVideoCheck(server.url, video1, checkAttributesVideo1)
317 const checkAttributesVideo2 = {
318 name: 'my super name for server 3-2',
323 description: 'my super description for server 3-2',
324 support: 'my super support text for server 3-2',
327 host: 'localhost:9003'
329 commentsEnabled: true,
332 tags: [ 'tag2p3', 'tag3p3', 'tag4p3' ],
333 privacy: VideoPrivacy.PUBLIC,
335 name: 'Default root channel',
339 fixture: 'video_short.webm',
347 await completeVideoCheck(server.url, video2, checkAttributesVideo2)
352 describe('Should seed the uploaded video', function () {
353 it('Should add the file 1 by asking server 3', async function () {
356 const res = await getVideosList(servers[2].url)
358 const video = res.body.data[0]
359 toRemove.push(res.body.data[2])
360 toRemove.push(res.body.data[3])
362 const res2 = await getVideo(servers[2].url, video.id)
363 const videoDetails = res2.body
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('')
371 it('Should add the file 2 by asking server 1', async function () {
374 const res = await getVideosList(servers[0].url)
376 const video = res.body.data[1]
377 const res2 = await getVideo(servers[0].url, video.id)
378 const videoDetails = res2.body
380 const torrent = await webtorrentAdd(videoDetails.files[0].magnetUri, true)
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('')
386 it('Should add the file 3 by asking server 2', async function () {
389 const res = await getVideosList(servers[1].url)
391 const video = res.body.data[2]
392 const res2 = await getVideo(servers[1].url, video.id)
393 const videoDetails = res2.body
395 const torrent = await webtorrentAdd(videoDetails.files[0].magnetUri, true)
396 expect(torrent.files).to.be.an('array')
397 expect(torrent.files.length).to.equal(1)
398 expect(torrent.files[0].path).to.exist.and.to.not.equal('')
401 it('Should add the file 3-2 by asking server 1', async function () {
404 const res = await getVideosList(servers[0].url)
406 const video = res.body.data[3]
407 const res2 = await getVideo(servers[0].url, video.id)
408 const videoDetails = res2.body
410 const torrent = await webtorrentAdd(videoDetails.files[0].magnetUri)
411 expect(torrent.files).to.be.an('array')
412 expect(torrent.files.length).to.equal(1)
413 expect(torrent.files[0].path).to.exist.and.to.not.equal('')
416 it('Should add the file 2 in 360p by asking server 1', async function () {
419 const res = await getVideosList(servers[0].url)
421 const video = res.body.data.find(v => v.name === 'my super name for server 2')
422 const res2 = await getVideo(servers[0].url, video.id)
423 const videoDetails = res2.body
425 const file = videoDetails.files.find(f => f.resolution === 360)
426 expect(file).not.to.be.undefined
428 const torrent = await webtorrentAdd(file.magnetUri)
429 expect(torrent.files).to.be.an('array')
430 expect(torrent.files.length).to.equal(1)
431 expect(torrent.files[0].path).to.exist.and.to.not.equal('')
435 describe('Should update video views, likes and dislikes', function () {
436 let localVideosServer3 = []
437 let remoteVideosServer1 = []
438 let remoteVideosServer2 = []
439 let remoteVideosServer3 = []
441 before(async function () {
442 const res1 = await getVideosList(servers[0].url)
443 remoteVideosServer1 = res1.body.data.filter(video => video.isLocal === false).map(video => video.uuid)
445 const res2 = await getVideosList(servers[1].url)
446 remoteVideosServer2 = res2.body.data.filter(video => video.isLocal === false).map(video => video.uuid)
448 const res3 = await getVideosList(servers[2].url)
449 localVideosServer3 = res3.body.data.filter(video => video.isLocal === true).map(video => video.uuid)
450 remoteVideosServer3 = res3.body.data.filter(video => video.isLocal === false).map(video => video.uuid)
453 it('Should view multiple videos on owned servers', async function () {
456 const tasks: Promise<any>[] = []
457 await viewVideo(servers[2].url, localVideosServer3[0])
458 await viewVideo(servers[2].url, localVideosServer3[0])
459 await viewVideo(servers[2].url, localVideosServer3[0])
460 await viewVideo(servers[2].url, localVideosServer3[1])
462 await Promise.all(tasks)
465 await viewVideo(servers[2].url, localVideosServer3[0])
469 await viewVideo(servers[2].url, localVideosServer3[0])
473 for (const server of servers) {
474 const res = await getVideosList(server.url)
476 const videos = res.body.data
477 const video0 = videos.find(v => v.uuid === localVideosServer3[0])
478 const video1 = videos.find(v => v.uuid === localVideosServer3[1])
480 expect(video0.views).to.equal(3)
481 expect(video1.views).to.equal(1)
485 it('Should view multiple videos on each servers', async function () {
488 const tasks: Promise<any>[] = []
489 tasks.push(viewVideo(servers[0].url, remoteVideosServer1[0]))
490 tasks.push(viewVideo(servers[1].url, remoteVideosServer2[0]))
491 tasks.push(viewVideo(servers[1].url, remoteVideosServer2[0]))
492 tasks.push(viewVideo(servers[2].url, remoteVideosServer3[0]))
493 tasks.push(viewVideo(servers[2].url, remoteVideosServer3[1]))
494 tasks.push(viewVideo(servers[2].url, remoteVideosServer3[1]))
495 tasks.push(viewVideo(servers[2].url, remoteVideosServer3[1]))
496 tasks.push(viewVideo(servers[2].url, localVideosServer3[1]))
497 tasks.push(viewVideo(servers[2].url, localVideosServer3[1]))
498 tasks.push(viewVideo(servers[2].url, localVideosServer3[1]))
500 await Promise.all(tasks)
504 let baseVideos = null
506 for (const server of servers) {
507 const res = await getVideosList(server.url)
509 const videos = res.body.data
511 // Initialize base videos for future comparisons
512 if (baseVideos === null) {
517 for (const baseVideo of baseVideos) {
518 const sameVideo = videos.find(video => video.name === baseVideo.name)
519 expect(baseVideo.views).to.equal(sameVideo.views)
524 it('Should like and dislikes videos on different services', async function () {
527 await rateVideo(servers[0].url, servers[0].accessToken, remoteVideosServer1[0], 'like')
529 await rateVideo(servers[0].url, servers[0].accessToken, remoteVideosServer1[0], 'dislike')
531 await rateVideo(servers[0].url, servers[0].accessToken, remoteVideosServer1[0], 'like')
532 await rateVideo(servers[2].url, servers[2].accessToken, localVideosServer3[1], 'like')
534 await rateVideo(servers[2].url, servers[2].accessToken, localVideosServer3[1], 'dislike')
535 await rateVideo(servers[2].url, servers[2].accessToken, remoteVideosServer3[1], 'dislike')
537 await rateVideo(servers[2].url, servers[2].accessToken, remoteVideosServer3[0], 'like')
541 let baseVideos = null
542 for (const server of servers) {
543 const res = await getVideosList(server.url)
545 const videos = res.body.data
547 // Initialize base videos for future comparisons
548 if (baseVideos === null) {
553 for (const baseVideo of baseVideos) {
554 const sameVideo = videos.find(video => video.name === baseVideo.name)
555 expect(baseVideo.likes).to.equal(sameVideo.likes)
556 expect(baseVideo.dislikes).to.equal(sameVideo.dislikes)
562 describe('Should manipulate these videos', function () {
563 it('Should update the video 3 by asking server 3', async function () {
567 name: 'my super video updated',
572 description: 'my super description updated',
573 support: 'my super support text updated',
574 tags: [ 'tag_up_1', 'tag_up_2' ],
575 thumbnailfile: 'thumbnail.jpg',
576 previewfile: 'preview.jpg'
579 await updateVideo(servers[2].url, servers[2].accessToken, toRemove[0].id, attributes)
584 it('Should have the video 3 updated on each server', async function () {
587 for (const server of servers) {
588 const res = await getVideosList(server.url)
590 const videos = res.body.data
591 const videoUpdated = videos.find(video => video.name === 'my super video updated')
592 expect(!!videoUpdated).to.be.true
594 const isLocal = server.url === 'http://localhost:9003'
595 const checkAttributes = {
596 name: 'my super video updated',
601 description: 'my super description updated',
602 support: 'my super support text updated',
605 host: 'localhost:9003'
609 commentsEnabled: true,
610 tags: [ 'tag_up_1', 'tag_up_2' ],
611 privacy: VideoPrivacy.PUBLIC,
613 name: 'Default root channel',
617 fixture: 'video_short3.webm',
624 thumbnailfile: 'thumbnail',
625 previewfile: 'preview'
627 await completeVideoCheck(server.url, videoUpdated, checkAttributes)
631 it('Should remove the videos 3 and 3-2 by asking server 3', async function () {
634 await removeVideo(servers[2].url, servers[2].accessToken, toRemove[0].id)
635 await removeVideo(servers[2].url, servers[2].accessToken, toRemove[1].id)
640 it('Should not have files of videos 3 and 3-2 on each server', async function () {
641 for (const server of servers) {
642 await checkVideoFilesWereRemoved(toRemove[0].uuid, server.serverNumber)
643 await checkVideoFilesWereRemoved(toRemove[1].uuid, server.serverNumber)
647 it('Should have videos 1 and 3 on each server', async function () {
648 for (const server of servers) {
649 const res = await getVideosList(server.url)
651 const videos = res.body.data
652 expect(videos).to.be.an('array')
653 expect(videos.length).to.equal(2)
654 expect(videos[0].name).not.to.equal(videos[1].name)
655 expect(videos[0].name).not.to.equal(toRemove[0].name)
656 expect(videos[1].name).not.to.equal(toRemove[0].name)
657 expect(videos[0].name).not.to.equal(toRemove[1].name)
658 expect(videos[1].name).not.to.equal(toRemove[1].name)
660 videoUUID = videos.find(video => video.name === 'my super name for server 1').uuid
664 it('Should get the same video by UUID on each server', async function () {
666 for (const server of servers) {
667 const res = await getVideo(server.url, videoUUID)
669 const video = res.body
671 if (baseVideo === null) {
676 expect(baseVideo.name).to.equal(video.name)
677 expect(baseVideo.uuid).to.equal(video.uuid)
678 expect(baseVideo.category).to.equal(video.category)
679 expect(baseVideo.language).to.equal(video.language)
680 expect(baseVideo.licence).to.equal(video.licence)
681 expect(baseVideo.category).to.equal(video.category)
682 expect(baseVideo.nsfw).to.equal(video.nsfw)
683 expect(baseVideo.account.name).to.equal(video.account.name)
684 expect(baseVideo.account.displayName).to.equal(video.account.displayName)
685 expect(baseVideo.account.url).to.equal(video.account.url)
686 expect(baseVideo.account.host).to.equal(video.account.host)
687 expect(baseVideo.tags).to.deep.equal(video.tags)
691 it('Should get the preview from each server', async function () {
692 for (const server of servers) {
693 const res = await getVideo(server.url, videoUUID)
694 const video = res.body
696 await testImage(server.url, 'video_short1-preview.webm', video.previewPath)
701 describe('Should comment these videos', function () {
702 it('Should add comment (threads and replies)', async function () {
706 const text = 'my super first comment'
707 await addVideoCommentThread(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID, text)
711 const text = 'my super second comment'
712 await addVideoCommentThread(servers[ 2 ].url, servers[ 2 ].accessToken, videoUUID, text)
718 const res = await getVideoCommentThreads(servers[1].url, videoUUID, 0, 5)
719 const threadId = res.body.data.find(c => c.text === 'my super first comment').id
721 const text = 'my super answer to thread 1'
722 await addVideoCommentReply(servers[ 1 ].url, servers[ 1 ].accessToken, videoUUID, threadId, text)
728 const res1 = await getVideoCommentThreads(servers[2].url, videoUUID, 0, 5)
729 const threadId = res1.body.data.find(c => c.text === 'my super first comment').id
731 const res2 = await getVideoThreadComments(servers[2].url, videoUUID, threadId)
732 const childCommentId = res2.body.children[0].comment.id
734 const text3 = 'my second answer to thread 1'
735 await addVideoCommentReply(servers[ 2 ].url, servers[ 2 ].accessToken, videoUUID, threadId, text3)
737 const text2 = 'my super answer to answer of thread 1'
738 await addVideoCommentReply(servers[ 2 ].url, servers[ 2 ].accessToken, videoUUID, childCommentId, text2)
744 it('Should have these threads', async function () {
745 for (const server of servers) {
746 const res = await getVideoCommentThreads(server.url, videoUUID, 0, 5)
748 expect(res.body.total).to.equal(2)
749 expect(res.body.data).to.be.an('array')
750 expect(res.body.data).to.have.lengthOf(2)
753 const comment: VideoComment = res.body.data.find(c => c.text === 'my super first comment')
754 expect(comment).to.not.be.undefined
755 expect(comment.inReplyToCommentId).to.be.null
756 expect(comment.account.name).to.equal('root')
757 expect(comment.account.host).to.equal('localhost:9001')
758 expect(comment.totalReplies).to.equal(3)
759 expect(dateIsValid(comment.createdAt as string)).to.be.true
760 expect(dateIsValid(comment.updatedAt as string)).to.be.true
764 const comment: VideoComment = res.body.data.find(c => c.text === 'my super second comment')
765 expect(comment).to.not.be.undefined
766 expect(comment.inReplyToCommentId).to.be.null
767 expect(comment.account.name).to.equal('root')
768 expect(comment.account.host).to.equal('localhost:9003')
769 expect(comment.totalReplies).to.equal(0)
770 expect(dateIsValid(comment.createdAt as string)).to.be.true
771 expect(dateIsValid(comment.updatedAt as string)).to.be.true
776 it('Should have these comments', async function () {
777 for (const server of servers) {
778 const res1 = await getVideoCommentThreads(server.url, videoUUID, 0, 5)
779 const threadId = res1.body.data.find(c => c.text === 'my super first comment').id
781 const res2 = await getVideoThreadComments(server.url, videoUUID, threadId)
783 const tree: VideoCommentThreadTree = res2.body
784 expect(tree.comment.text).equal('my super first comment')
785 expect(tree.comment.account.name).equal('root')
786 expect(tree.comment.account.host).equal('localhost:9001')
787 expect(tree.children).to.have.lengthOf(2)
789 const firstChild = tree.children[0]
790 expect(firstChild.comment.text).to.equal('my super answer to thread 1')
791 expect(firstChild.comment.account.name).equal('root')
792 expect(firstChild.comment.account.host).equal('localhost:9002')
793 expect(firstChild.children).to.have.lengthOf(1)
795 const childOfFirstChild = firstChild.children[0]
796 expect(childOfFirstChild.comment.text).to.equal('my super answer to answer of thread 1')
797 expect(childOfFirstChild.comment.account.name).equal('root')
798 expect(childOfFirstChild.comment.account.host).equal('localhost:9003')
799 expect(childOfFirstChild.children).to.have.lengthOf(0)
801 const secondChild = tree.children[1]
802 expect(secondChild.comment.text).to.equal('my second answer to thread 1')
803 expect(secondChild.comment.account.name).equal('root')
804 expect(secondChild.comment.account.host).equal('localhost:9003')
805 expect(secondChild.children).to.have.lengthOf(0)
809 it('Should delete the thread comments', async function () {
812 const res1 = await getVideoCommentThreads(servers[0].url, videoUUID, 0, 5)
813 const threadId = res1.body.data.find(c => c.text === 'my super first comment').id
814 await deleteVideoComment(servers[0].url, servers[0].accessToken, videoUUID, threadId)
819 it('Should have the thread comments deleted on other servers too', async function () {
820 for (const server of servers) {
821 const res = await getVideoCommentThreads(server.url, videoUUID, 0, 5)
823 expect(res.body.total).to.equal(1)
824 expect(res.body.data).to.be.an('array')
825 expect(res.body.data).to.have.lengthOf(1)
828 const comment: VideoComment = res.body.data[0]
829 expect(comment).to.not.be.undefined
830 expect(comment.inReplyToCommentId).to.be.null
831 expect(comment.account.name).to.equal('root')
832 expect(comment.account.host).to.equal('localhost:9003')
833 expect(comment.totalReplies).to.equal(0)
834 expect(dateIsValid(comment.createdAt as string)).to.be.true
835 expect(dateIsValid(comment.updatedAt as string)).to.be.true
840 it('Should disable comments', async function () {
844 commentsEnabled: false
847 await updateVideo(servers[0].url, servers[0].accessToken, videoUUID, attributes)
851 for (const server of servers) {
852 const res = await getVideo(server.url, videoUUID)
853 expect(res.body.commentsEnabled).to.be.false
855 const text = 'my super forbidden comment'
856 await addVideoCommentThread(server.url, server.accessToken, videoUUID, text, 409)
861 describe('With minimum parameters', function () {
862 it('Should upload and propagate the video', async function () {
865 const path = '/api/v1/videos/upload'
867 const req = request(servers[1].url)
869 .set('Accept', 'application/json')
870 .set('Authorization', 'Bearer ' + servers[1].accessToken)
871 .field('name', 'minimum parameters')
872 .field('privacy', '1')
873 .field('nsfw', 'false')
874 .field('channelId', '1')
875 .field('commentsEnabled', 'true')
877 const filePath = join(__dirname, '..', '..', 'api', 'fixtures', 'video_short.webm')
879 await req.attach('videofile', filePath)
884 for (const server of servers) {
885 const res = await getVideosList(server.url)
886 const video = res.body.data.find(v => v.name === 'minimum parameters')
888 const isLocal = server.url === 'http://localhost:9002'
889 const checkAttributes = {
890 name: 'minimum parameters',
899 host: 'localhost:9002'
903 commentsEnabled: true,
905 privacy: VideoPrivacy.PUBLIC,
907 name: 'Default root channel',
911 fixture: 'video_short.webm',
931 await completeVideoCheck(server.url, video, checkAttributes)
936 after(async function () {
937 killallServers(servers)
939 // Keep the logs if the test failed