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