1 /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
3 import { expect } from 'chai'
4 import { completeVideoCheck } from '@server/tests/shared'
5 import { wait } from '@shared/core-utils'
6 import { HttpStatusCode, JobState, VideoCreateResult, VideoPrivacy } from '@shared/models'
10 createMultipleServers,
13 setAccessTokensToServers,
15 } from '@shared/server-commands'
17 describe('Test handle downs', function () {
18 let servers: PeerTubeServer[] = []
19 let threadIdServer1: number
20 let threadIdServer2: number
21 let commentIdServer1: number
22 let commentIdServer2: number
23 let missedVideo1: VideoCreateResult
24 let missedVideo2: VideoCreateResult
25 let unlistedVideo: VideoCreateResult
27 const videoIdsServer1: string[] = []
29 const videoAttributes = {
30 name: 'my super name for server 1',
35 privacy: VideoPrivacy.PUBLIC,
36 description: 'my super description for server 1',
37 support: 'my super support text for server 1',
38 tags: [ 'tag1p1', 'tag2p1' ],
39 fixture: 'video_short1.webm'
42 const unlistedVideoAttributes = { ...videoAttributes, privacy: VideoPrivacy.UNLISTED }
44 let checkAttributes: any
45 let unlistedCheckAttributes: any
47 let commentCommands: CommentsCommand[]
49 before(async function () {
52 servers = await createMultipleServers(3)
53 commentCommands = servers.map(s => s.comments)
56 name: 'my super name for server 1',
61 description: 'my super description for server 1',
62 support: 'my super support text for server 1',
69 tags: [ 'tag1p1', 'tag2p1' ],
70 privacy: VideoPrivacy.PUBLIC,
71 commentsEnabled: true,
72 downloadEnabled: true,
75 displayName: 'Main root channel',
79 fixture: 'video_short1.webm',
87 unlistedCheckAttributes = { ...checkAttributes, privacy: VideoPrivacy.UNLISTED }
89 // Get the access tokens
90 await setAccessTokensToServers(servers)
93 it('Should remove followers that are often down', async function () {
96 // Server 2 and 3 follow server 1
97 await servers[1].follows.follow({ hosts: [ servers[0].url ] })
98 await servers[2].follows.follow({ hosts: [ servers[0].url ] })
100 await waitJobs(servers)
102 // Upload a video to server 1
103 await servers[0].videos.upload({ attributes: videoAttributes })
105 await waitJobs(servers)
107 // And check all servers have this video
108 for (const server of servers) {
109 const { data } = await server.videos.list()
110 expect(data).to.be.an('array')
111 expect(data).to.have.lengthOf(1)
115 await killallServers([ servers[1] ])
117 // Remove server 2 follower
118 for (let i = 0; i < 10; i++) {
119 await servers[0].videos.upload({ attributes: videoAttributes })
122 await waitJobs([ servers[0], servers[2] ])
125 await killallServers([ servers[2] ])
127 missedVideo1 = await servers[0].videos.upload({ attributes: videoAttributes })
129 missedVideo2 = await servers[0].videos.upload({ attributes: videoAttributes })
132 unlistedVideo = await servers[0].videos.upload({ attributes: unlistedVideoAttributes })
134 // Add comments to video 2
136 const text = 'thread 1'
137 let comment = await commentCommands[0].createThread({ videoId: missedVideo2.uuid, text })
138 threadIdServer1 = comment.id
140 comment = await commentCommands[0].addReply({ videoId: missedVideo2.uuid, toCommentId: comment.id, text: 'comment 1-1' })
142 const created = await commentCommands[0].addReply({ videoId: missedVideo2.uuid, toCommentId: comment.id, text: 'comment 1-2' })
143 commentIdServer1 = created.id
146 await waitJobs(servers[0])
150 // Only server 3 is still a follower of server 1
151 const body = await servers[0].follows.getFollowers({ start: 0, count: 2, sort: 'createdAt' })
152 expect(body.data).to.be.an('array')
153 expect(body.data).to.have.lengthOf(1)
154 expect(body.data[0].follower.host).to.equal(servers[2].host)
157 it('Should not have pending/processing jobs anymore', async function () {
158 const states: JobState[] = [ 'waiting', 'active' ]
160 for (const state of states) {
161 const body = await servers[0].jobs.list({
167 expect(body.data).to.have.length(0)
171 it('Should re-follow server 1', async function () {
174 await servers[1].run()
175 await servers[2].run()
177 await servers[1].follows.unfollow({ target: servers[0] })
178 await waitJobs(servers)
180 await servers[1].follows.follow({ hosts: [ servers[0].url ] })
182 await waitJobs(servers)
184 const body = await servers[0].follows.getFollowers({ start: 0, count: 2, sort: 'createdAt' })
185 expect(body.data).to.be.an('array')
186 expect(body.data).to.have.lengthOf(2)
189 it('Should send an update to server 3, and automatically fetch the video', async function () {
193 const { data } = await servers[2].videos.list()
194 expect(data).to.be.an('array')
195 expect(data).to.have.lengthOf(11)
198 await servers[0].videos.update({ id: missedVideo1.uuid })
199 await servers[0].videos.update({ id: unlistedVideo.uuid })
201 await waitJobs(servers)
204 const { data } = await servers[2].videos.list()
205 expect(data).to.be.an('array')
206 // 1 video is unlisted
207 expect(data).to.have.lengthOf(12)
210 // Check unlisted video
211 const video = await servers[2].videos.get({ id: unlistedVideo.uuid })
212 await completeVideoCheck(servers[2], video, unlistedCheckAttributes)
215 it('Should send comments on a video to server 3, and automatically fetch the video', async function () {
218 await commentCommands[0].addReply({ videoId: missedVideo2.uuid, toCommentId: commentIdServer1, text: 'comment 1-3' })
220 await waitJobs(servers)
222 await servers[2].videos.get({ id: missedVideo2.uuid })
225 const { data } = await servers[2].comments.listThreads({ videoId: missedVideo2.uuid })
226 expect(data).to.be.an('array')
227 expect(data).to.have.lengthOf(1)
229 threadIdServer2 = data[0].id
231 const tree = await servers[2].comments.getThread({ videoId: missedVideo2.uuid, threadId: threadIdServer2 })
232 expect(tree.comment.text).equal('thread 1')
233 expect(tree.children).to.have.lengthOf(1)
235 const firstChild = tree.children[0]
236 expect(firstChild.comment.text).to.equal('comment 1-1')
237 expect(firstChild.children).to.have.lengthOf(1)
239 const childOfFirstChild = firstChild.children[0]
240 expect(childOfFirstChild.comment.text).to.equal('comment 1-2')
241 expect(childOfFirstChild.children).to.have.lengthOf(1)
243 const childOfChildFirstChild = childOfFirstChild.children[0]
244 expect(childOfChildFirstChild.comment.text).to.equal('comment 1-3')
245 expect(childOfChildFirstChild.children).to.have.lengthOf(0)
247 commentIdServer2 = childOfChildFirstChild.comment.id
251 it('Should correctly reply to the comment', async function () {
254 await servers[2].comments.addReply({ videoId: missedVideo2.uuid, toCommentId: commentIdServer2, text: 'comment 1-4' })
256 await waitJobs(servers)
258 const tree = await commentCommands[0].getThread({ videoId: missedVideo2.uuid, threadId: threadIdServer1 })
260 expect(tree.comment.text).equal('thread 1')
261 expect(tree.children).to.have.lengthOf(1)
263 const firstChild = tree.children[0]
264 expect(firstChild.comment.text).to.equal('comment 1-1')
265 expect(firstChild.children).to.have.lengthOf(1)
267 const childOfFirstChild = firstChild.children[0]
268 expect(childOfFirstChild.comment.text).to.equal('comment 1-2')
269 expect(childOfFirstChild.children).to.have.lengthOf(1)
271 const childOfChildFirstChild = childOfFirstChild.children[0]
272 expect(childOfChildFirstChild.comment.text).to.equal('comment 1-3')
273 expect(childOfChildFirstChild.children).to.have.lengthOf(1)
275 const childOfChildOfChildOfFirstChild = childOfChildFirstChild.children[0]
276 expect(childOfChildOfChildOfFirstChild.comment.text).to.equal('comment 1-4')
277 expect(childOfChildOfChildOfFirstChild.children).to.have.lengthOf(0)
280 it('Should upload many videos on server 1', async function () {
283 for (let i = 0; i < 10; i++) {
284 const uuid = (await servers[0].videos.quickUpload({ name: 'video ' + i })).uuid
285 videoIdsServer1.push(uuid)
288 await waitJobs(servers)
290 for (const id of videoIdsServer1) {
291 await servers[1].videos.get({ id })
294 await waitJobs(servers)
295 await servers[1].sql.setActorFollowScores(20)
297 // Wait video expiration
300 // Refresh video -> score + 10 = 30
301 await servers[1].videos.get({ id: videoIdsServer1[0] })
303 await waitJobs(servers)
306 it('Should remove followings that are down', async function () {
309 await killallServers([ servers[0] ])
311 // Wait video expiration
314 for (let i = 0; i < 5; i++) {
316 await servers[1].videos.get({ id: videoIdsServer1[i] })
317 await waitJobs([ servers[1] ])
322 for (const id of videoIdsServer1) {
323 await servers[1].videos.get({ id, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
327 after(async function () {
328 await cleanupTests(servers)