]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/tests/api/server/handle-down.ts
Move test functions outside extra-utils
[github/Chocobozzz/PeerTube.git] / server / tests / api / server / handle-down.ts
CommitLineData
a1587156 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2ccaeeb3 2
2ccaeeb3 3import 'mocha'
c3d29f69 4import * as chai from 'chai'
c55e3d72
C
5import { completeVideoCheck } from '@server/tests/shared'
6import { wait } from '@shared/core-utils'
7import { HttpStatusCode, JobState, VideoCreateResult, VideoPrivacy } from '@shared/models'
2ccaeeb3 8import {
7c3b7976 9 cleanupTests,
12edc149 10 CommentsCommand,
254d3579 11 createMultipleServers,
94831479 12 killallServers,
254d3579 13 PeerTubeServer,
94831479 14 setAccessTokensToServers,
c3d29f69 15 waitJobs
bf54587a 16} from '@shared/server-commands'
2ccaeeb3
C
17
18const expect = chai.expect
19
20describe('Test handle downs', function () {
254d3579 21 let servers: PeerTubeServer[] = []
7bc29171
C
22 let threadIdServer1: number
23 let threadIdServer2: number
24 let commentIdServer1: number
25 let commentIdServer2: number
d23dd9fb
C
26 let missedVideo1: VideoCreateResult
27 let missedVideo2: VideoCreateResult
28 let unlistedVideo: VideoCreateResult
2ccaeeb3 29
d4a8e7a6 30 const videoIdsServer1: string[] = []
6b9c966f 31
2ccaeeb3
C
32 const videoAttributes = {
33 name: 'my super name for server 1',
34 category: 5,
35 licence: 4,
9d3ef9fe 36 language: 'ja',
2ccaeeb3 37 nsfw: true,
7bc29171 38 privacy: VideoPrivacy.PUBLIC,
2ccaeeb3 39 description: 'my super description for server 1',
2422c46b 40 support: 'my super support text for server 1',
2ccaeeb3
C
41 tags: [ 'tag1p1', 'tag2p1' ],
42 fixture: 'video_short1.webm'
43 }
44
6c5065a0 45 const unlistedVideoAttributes = { ...videoAttributes, privacy: VideoPrivacy.UNLISTED }
7bc29171 46
48f07b4a
C
47 let checkAttributes: any
48 let unlistedCheckAttributes: any
7bc29171 49
12edc149
C
50 let commentCommands: CommentsCommand[]
51
2ccaeeb3 52 before(async function () {
e212f887 53 this.timeout(30000)
2ccaeeb3 54
254d3579 55 servers = await createMultipleServers(3)
89d241a7 56 commentCommands = servers.map(s => s.comments)
2ccaeeb3 57
48f07b4a
C
58 checkAttributes = {
59 name: 'my super name for server 1',
60 category: 5,
61 licence: 4,
62 language: 'ja',
63 nsfw: true,
64 description: 'my super description for server 1',
65 support: 'my super support text for server 1',
66 account: {
67 name: 'root',
68 host: 'localhost:' + servers[0].port
69 },
70 isLocal: false,
71 duration: 10,
72 tags: [ 'tag1p1', 'tag2p1' ],
73 privacy: VideoPrivacy.PUBLIC,
74 commentsEnabled: true,
75 downloadEnabled: true,
76 channel: {
77 name: 'root_channel',
78 displayName: 'Main root channel',
79 description: '',
80 isLocal: false
81 },
82 fixture: 'video_short1.webm',
83 files: [
84 {
85 resolution: 720,
86 size: 572456
87 }
88 ]
89 }
6c5065a0 90 unlistedCheckAttributes = { ...checkAttributes, privacy: VideoPrivacy.UNLISTED }
48f07b4a 91
2ccaeeb3
C
92 // Get the access tokens
93 await setAccessTokensToServers(servers)
94 })
95
96 it('Should remove followers that are often down', async function () {
2284f202 97 this.timeout(240000)
2ccaeeb3 98
cc6373e6 99 // Server 2 and 3 follow server 1
4d029ef8
C
100 await servers[1].follows.follow({ hosts: [ servers[0].url ] })
101 await servers[2].follows.follow({ hosts: [ servers[0].url ] })
2ccaeeb3 102
3cd0734f 103 await waitJobs(servers)
2ccaeeb3 104
cc6373e6 105 // Upload a video to server 1
89d241a7 106 await servers[0].videos.upload({ attributes: videoAttributes })
2ccaeeb3 107
3cd0734f 108 await waitJobs(servers)
2ccaeeb3 109
cc6373e6 110 // And check all servers have this video
2ccaeeb3 111 for (const server of servers) {
89d241a7 112 const { data } = await server.videos.list()
d23dd9fb
C
113 expect(data).to.be.an('array')
114 expect(data).to.have.lengthOf(1)
2ccaeeb3
C
115 }
116
cc6373e6 117 // Kill server 2
9293139f 118 await killallServers([ servers[1] ])
2ccaeeb3
C
119
120 // Remove server 2 follower
121 for (let i = 0; i < 10; i++) {
89d241a7 122 await servers[0].videos.upload({ attributes: videoAttributes })
7bc29171
C
123 }
124
f67d1dca 125 await waitJobs([ servers[0], servers[2] ])
6502c3d4 126
cc6373e6 127 // Kill server 3
9293139f 128 await killallServers([ servers[2] ])
cc6373e6 129
89d241a7 130 missedVideo1 = await servers[0].videos.upload({ attributes: videoAttributes })
cc6373e6 131
89d241a7 132 missedVideo2 = await servers[0].videos.upload({ attributes: videoAttributes })
cc6373e6
C
133
134 // Unlisted video
89d241a7 135 unlistedVideo = await servers[0].videos.upload({ attributes: unlistedVideoAttributes })
6502c3d4 136
7bc29171
C
137 // Add comments to video 2
138 {
139 const text = 'thread 1'
12edc149 140 let comment = await commentCommands[0].createThread({ videoId: missedVideo2.uuid, text })
7bc29171
C
141 threadIdServer1 = comment.id
142
12edc149 143 comment = await commentCommands[0].addReply({ videoId: missedVideo2.uuid, toCommentId: comment.id, text: 'comment 1-1' })
7bc29171 144
12edc149
C
145 const created = await commentCommands[0].addReply({ videoId: missedVideo2.uuid, toCommentId: comment.id, text: 'comment 1-2' })
146 commentIdServer1 = created.id
2ccaeeb3
C
147 }
148
3cd0734f
C
149 await waitJobs(servers[0])
150 // Wait scheduler
9a4a9b6c 151 await wait(11000)
2ccaeeb3 152
cc6373e6 153 // Only server 3 is still a follower of server 1
89d241a7 154 const body = await servers[0].follows.getFollowers({ start: 0, count: 2, sort: 'createdAt' })
c3d29f69
C
155 expect(body.data).to.be.an('array')
156 expect(body.data).to.have.lengthOf(1)
157 expect(body.data[0].follower.host).to.equal('localhost:' + servers[2].port)
2ccaeeb3
C
158 })
159
160 it('Should not have pending/processing jobs anymore', async function () {
94831479 161 const states: JobState[] = [ 'waiting', 'active' ]
2ccaeeb3 162
94a5ff8a 163 for (const state of states) {
851675c5 164 const body = await servers[0].jobs.list({
1061c73f
C
165 state: state,
166 start: 0,
167 count: 50,
168 sort: '-createdAt'
169 })
9c6327f8 170 expect(body.data).to.have.length(0)
2ccaeeb3
C
171 }
172 })
173
cc6373e6 174 it('Should re-follow server 1', async function () {
87c0f718 175 this.timeout(70000)
7bc29171 176
254d3579
C
177 await servers[1].run()
178 await servers[2].run()
cc6373e6 179
89d241a7 180 await servers[1].follows.unfollow({ target: servers[0] })
cc6373e6 181 await waitJobs(servers)
2ccaeeb3 182
4d029ef8 183 await servers[1].follows.follow({ hosts: [ servers[0].url ] })
2ccaeeb3 184
3cd0734f 185 await waitJobs(servers)
2ccaeeb3 186
89d241a7 187 const body = await servers[0].follows.getFollowers({ start: 0, count: 2, sort: 'createdAt' })
c3d29f69
C
188 expect(body.data).to.be.an('array')
189 expect(body.data).to.have.lengthOf(2)
2ccaeeb3
C
190 })
191
8cf99873 192 it('Should send an update to server 3, and automatically fetch the video', async function () {
7bc29171 193 this.timeout(15000)
2ccaeeb3 194
d23dd9fb 195 {
89d241a7 196 const { data } = await servers[2].videos.list()
d23dd9fb
C
197 expect(data).to.be.an('array')
198 expect(data).to.have.lengthOf(11)
199 }
cc6373e6 200
89d241a7
C
201 await servers[0].videos.update({ id: missedVideo1.uuid })
202 await servers[0].videos.update({ id: unlistedVideo.uuid })
2ccaeeb3 203
3cd0734f 204 await waitJobs(servers)
2ccaeeb3 205
d23dd9fb 206 {
89d241a7 207 const { data } = await servers[2].videos.list()
d23dd9fb
C
208 expect(data).to.be.an('array')
209 // 1 video is unlisted
210 expect(data).to.have.lengthOf(12)
211 }
7bc29171 212
cc6373e6 213 // Check unlisted video
89d241a7 214 const video = await servers[2].videos.get({ id: unlistedVideo.uuid })
d23dd9fb 215 await completeVideoCheck(servers[2], video, unlistedCheckAttributes)
7bc29171
C
216 })
217
cc6373e6 218 it('Should send comments on a video to server 3, and automatically fetch the video', async function () {
7bc29171 219 this.timeout(25000)
2ccaeeb3 220
12edc149 221 await commentCommands[0].addReply({ videoId: missedVideo2.uuid, toCommentId: commentIdServer1, text: 'comment 1-3' })
7bc29171 222
3cd0734f 223 await waitJobs(servers)
7bc29171 224
89d241a7 225 await servers[2].videos.get({ id: missedVideo2.uuid })
7bc29171 226
7bc29171 227 {
89d241a7 228 const { data } = await servers[2].comments.listThreads({ videoId: missedVideo2.uuid })
12edc149
C
229 expect(data).to.be.an('array')
230 expect(data).to.have.lengthOf(1)
7bc29171 231
12edc149 232 threadIdServer2 = data[0].id
7bc29171 233
89d241a7 234 const tree = await servers[2].comments.getThread({ videoId: missedVideo2.uuid, threadId: threadIdServer2 })
7bc29171
C
235 expect(tree.comment.text).equal('thread 1')
236 expect(tree.children).to.have.lengthOf(1)
237
238 const firstChild = tree.children[0]
239 expect(firstChild.comment.text).to.equal('comment 1-1')
240 expect(firstChild.children).to.have.lengthOf(1)
241
242 const childOfFirstChild = firstChild.children[0]
243 expect(childOfFirstChild.comment.text).to.equal('comment 1-2')
244 expect(childOfFirstChild.children).to.have.lengthOf(1)
245
246 const childOfChildFirstChild = childOfFirstChild.children[0]
247 expect(childOfChildFirstChild.comment.text).to.equal('comment 1-3')
248 expect(childOfChildFirstChild.children).to.have.lengthOf(0)
249
250 commentIdServer2 = childOfChildFirstChild.comment.id
251 }
252 })
253
254 it('Should correctly reply to the comment', async function () {
255 this.timeout(15000)
256
89d241a7 257 await servers[2].comments.addReply({ videoId: missedVideo2.uuid, toCommentId: commentIdServer2, text: 'comment 1-4' })
7bc29171 258
3cd0734f 259 await waitJobs(servers)
7bc29171 260
12edc149 261 const tree = await commentCommands[0].getThread({ videoId: missedVideo2.uuid, threadId: threadIdServer1 })
7bc29171 262
12edc149
C
263 expect(tree.comment.text).equal('thread 1')
264 expect(tree.children).to.have.lengthOf(1)
7bc29171 265
12edc149
C
266 const firstChild = tree.children[0]
267 expect(firstChild.comment.text).to.equal('comment 1-1')
268 expect(firstChild.children).to.have.lengthOf(1)
7bc29171 269
12edc149
C
270 const childOfFirstChild = firstChild.children[0]
271 expect(childOfFirstChild.comment.text).to.equal('comment 1-2')
272 expect(childOfFirstChild.children).to.have.lengthOf(1)
7bc29171 273
12edc149
C
274 const childOfChildFirstChild = childOfFirstChild.children[0]
275 expect(childOfChildFirstChild.comment.text).to.equal('comment 1-3')
276 expect(childOfChildFirstChild.children).to.have.lengthOf(1)
7bc29171 277
12edc149
C
278 const childOfChildOfChildOfFirstChild = childOfChildFirstChild.children[0]
279 expect(childOfChildOfChildOfFirstChild.comment.text).to.equal('comment 1-4')
280 expect(childOfChildOfChildOfFirstChild.children).to.have.lengthOf(0)
2ccaeeb3
C
281 })
282
6b9c966f
C
283 it('Should upload many videos on server 1', async function () {
284 this.timeout(120000)
285
286 for (let i = 0; i < 10; i++) {
89d241a7 287 const uuid = (await servers[0].videos.quickUpload({ name: 'video ' + i })).uuid
6b9c966f
C
288 videoIdsServer1.push(uuid)
289 }
290
291 await waitJobs(servers)
292
293 for (const id of videoIdsServer1) {
89d241a7 294 await servers[1].videos.get({ id })
6b9c966f
C
295 }
296
297 await waitJobs(servers)
89d241a7 298 await servers[1].sql.setActorFollowScores(20)
6b9c966f
C
299
300 // Wait video expiration
301 await wait(11000)
302
303 // Refresh video -> score + 10 = 30
89d241a7 304 await servers[1].videos.get({ id: videoIdsServer1[0] })
6b9c966f
C
305
306 await waitJobs(servers)
307 })
308
309 it('Should remove followings that are down', async function () {
310 this.timeout(120000)
311
9293139f 312 await killallServers([ servers[0] ])
6b9c966f
C
313
314 // Wait video expiration
315 await wait(11000)
316
a3c997b3
C
317 for (let i = 0; i < 5; i++) {
318 try {
89d241a7 319 await servers[1].videos.get({ id: videoIdsServer1[i] })
a3c997b3
C
320 await waitJobs([ servers[1] ])
321 await wait(1500)
322 } catch {}
6b9c966f
C
323 }
324
325 for (const id of videoIdsServer1) {
89d241a7 326 await servers[1].videos.get({ id, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
6b9c966f
C
327 }
328 })
329
7c3b7976
C
330 after(async function () {
331 await cleanupTests(servers)
2ccaeeb3
C
332 })
333})