Fix misc tests
[oweals/peertube.git] / server / tests / api / server / handle-down.ts
1 /* tslint:disable:no-unused-expression */
2
3 import * as chai from 'chai'
4 import 'mocha'
5 import { JobState, Video } from '../../../../shared/models'
6 import { VideoPrivacy } from '../../../../shared/models/videos'
7 import { VideoCommentThreadTree } from '../../../../shared/models/videos/video-comment.model'
8
9 import {
10   cleanupTests,
11   completeVideoCheck,
12   flushAndRunMultipleServers,
13   getVideo,
14   getVideosList,
15   immutableAssign,
16   killallServers,
17   reRunServer,
18   ServerInfo,
19   setAccessTokensToServers,
20   unfollow,
21   updateVideo,
22   uploadVideo, uploadVideoAndGetId,
23   wait,
24   setActorFollowScores, closeAllSequelize
25 } from '../../../../shared/extra-utils'
26 import { follow, getFollowersListPaginationAndSort } from '../../../../shared/extra-utils/server/follows'
27 import { getJobsListPaginationAndSort, waitJobs } from '../../../../shared/extra-utils/server/jobs'
28 import {
29   addVideoCommentReply,
30   addVideoCommentThread,
31   getVideoCommentThreads,
32   getVideoThreadComments
33 } from '../../../../shared/extra-utils/videos/video-comments'
34
35 const expect = chai.expect
36
37 describe('Test handle downs', function () {
38   let servers: ServerInfo[] = []
39   let threadIdServer1: number
40   let threadIdServer2: number
41   let commentIdServer1: number
42   let commentIdServer2: number
43   let missedVideo1: Video
44   let missedVideo2: Video
45   let unlistedVideo: Video
46
47   let videoIdsServer1: number[] = []
48
49   const videoAttributes = {
50     name: 'my super name for server 1',
51     category: 5,
52     licence: 4,
53     language: 'ja',
54     nsfw: true,
55     privacy: VideoPrivacy.PUBLIC,
56     description: 'my super description for server 1',
57     support: 'my super support text for server 1',
58     tags: [ 'tag1p1', 'tag2p1' ],
59     fixture: 'video_short1.webm'
60   }
61
62   const unlistedVideoAttributes = immutableAssign(videoAttributes, {
63     privacy: VideoPrivacy.UNLISTED
64   })
65
66   let checkAttributes: any
67   let unlistedCheckAttributes: any
68
69   before(async function () {
70     this.timeout(30000)
71
72     servers = await flushAndRunMultipleServers(3)
73
74     checkAttributes = {
75       name: 'my super name for server 1',
76       category: 5,
77       licence: 4,
78       language: 'ja',
79       nsfw: true,
80       description: 'my super description for server 1',
81       support: 'my super support text for server 1',
82       account: {
83         name: 'root',
84         host: 'localhost:' + servers[0].port
85       },
86       isLocal: false,
87       duration: 10,
88       tags: [ 'tag1p1', 'tag2p1' ],
89       privacy: VideoPrivacy.PUBLIC,
90       commentsEnabled: true,
91       downloadEnabled: true,
92       channel: {
93         name: 'root_channel',
94         displayName: 'Main root channel',
95         description: '',
96         isLocal: false
97       },
98       fixture: 'video_short1.webm',
99       files: [
100         {
101           resolution: 720,
102           size: 572456
103         }
104       ]
105     }
106     unlistedCheckAttributes = immutableAssign(checkAttributes, {
107       privacy: VideoPrivacy.UNLISTED
108     })
109
110     // Get the access tokens
111     await setAccessTokensToServers(servers)
112   })
113
114   it('Should remove followers that are often down', async function () {
115     this.timeout(240000)
116
117     // Server 2 and 3 follow server 1
118     await follow(servers[1].url, [ servers[0].url ], servers[1].accessToken)
119     await follow(servers[2].url, [ servers[0].url ], servers[2].accessToken)
120
121     await waitJobs(servers)
122
123     // Upload a video to server 1
124     await uploadVideo(servers[0].url, servers[0].accessToken, videoAttributes)
125
126     await waitJobs(servers)
127
128     // And check all servers have this video
129     for (const server of servers) {
130       const res = await getVideosList(server.url)
131       expect(res.body.data).to.be.an('array')
132       expect(res.body.data).to.have.lengthOf(1)
133     }
134
135     // Kill server 2
136     killallServers([ servers[1] ])
137
138     // Remove server 2 follower
139     for (let i = 0; i < 10; i++) {
140       await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoAttributes)
141     }
142
143     await waitJobs(servers[0])
144
145     // Kill server 3
146     killallServers([ servers[2] ])
147
148     const resLastVideo1 = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoAttributes)
149     missedVideo1 = resLastVideo1.body.video
150
151     const resLastVideo2 = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoAttributes)
152     missedVideo2 = resLastVideo2.body.video
153
154     // Unlisted video
155     let resVideo = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, unlistedVideoAttributes)
156     unlistedVideo = resVideo.body.video
157
158     // Add comments to video 2
159     {
160       const text = 'thread 1'
161       let resComment = await addVideoCommentThread(servers[0].url, servers[0].accessToken, missedVideo2.uuid, text)
162       let comment = resComment.body.comment
163       threadIdServer1 = comment.id
164
165       resComment = await addVideoCommentReply(servers[0].url, servers[0].accessToken, missedVideo2.uuid, comment.id, 'comment 1-1')
166       comment = resComment.body.comment
167
168       resComment = await addVideoCommentReply(servers[0].url, servers[0].accessToken, missedVideo2.uuid, comment.id, 'comment 1-2')
169       commentIdServer1 = resComment.body.comment.id
170     }
171
172     await waitJobs(servers[0])
173     // Wait scheduler
174     await wait(11000)
175
176     // Only server 3 is still a follower of server 1
177     const res = await getFollowersListPaginationAndSort(servers[0].url, 0, 2, 'createdAt')
178     expect(res.body.data).to.be.an('array')
179     expect(res.body.data).to.have.lengthOf(1)
180     expect(res.body.data[0].follower.host).to.equal('localhost:' + servers[2].port)
181   })
182
183   it('Should not have pending/processing jobs anymore', async function () {
184     const states: JobState[] = [ 'waiting', 'active' ]
185
186     for (const state of states) {
187       const res = await getJobsListPaginationAndSort(servers[ 0 ].url, servers[ 0 ].accessToken, state,0, 50, '-createdAt')
188       expect(res.body.data).to.have.length(0)
189     }
190   })
191
192   it('Should re-follow server 1', async function () {
193     this.timeout(35000)
194
195     await reRunServer(servers[1])
196     await reRunServer(servers[2])
197
198     await unfollow(servers[1].url, servers[1].accessToken, servers[0])
199     await waitJobs(servers)
200
201     await follow(servers[1].url, [ servers[0].url ], servers[1].accessToken)
202
203     await waitJobs(servers)
204
205     const res = await getFollowersListPaginationAndSort(servers[0].url, 0, 2, 'createdAt')
206     expect(res.body.data).to.be.an('array')
207     expect(res.body.data).to.have.lengthOf(2)
208   })
209
210   it('Should send an update to server 3, and automatically fetch the video', async function () {
211     this.timeout(15000)
212
213     const res1 = await getVideosList(servers[2].url)
214     expect(res1.body.data).to.be.an('array')
215     expect(res1.body.data).to.have.lengthOf(11)
216
217     await updateVideo(servers[0].url, servers[0].accessToken, missedVideo1.uuid, { })
218     await updateVideo(servers[0].url, servers[0].accessToken, unlistedVideo.uuid, { })
219
220     await waitJobs(servers)
221
222     const res = await getVideosList(servers[2].url)
223     expect(res.body.data).to.be.an('array')
224     // 1 video is unlisted
225     expect(res.body.data).to.have.lengthOf(12)
226
227     // Check unlisted video
228     const resVideo = await getVideo(servers[2].url, unlistedVideo.uuid)
229     expect(resVideo.body).not.to.be.undefined
230
231     await completeVideoCheck(servers[2].url, resVideo.body, unlistedCheckAttributes)
232   })
233
234   it('Should send comments on a video to server 3, and automatically fetch the video', async function () {
235     this.timeout(25000)
236
237     await addVideoCommentReply(servers[0].url, servers[0].accessToken, missedVideo2.uuid, commentIdServer1, 'comment 1-3')
238
239     await waitJobs(servers)
240
241     const resVideo = await getVideo(servers[2].url, missedVideo2.uuid)
242     expect(resVideo.body).not.to.be.undefined
243
244     {
245       let resComment = await getVideoCommentThreads(servers[2].url, missedVideo2.uuid, 0, 5)
246       expect(resComment.body.data).to.be.an('array')
247       expect(resComment.body.data).to.have.lengthOf(1)
248
249       threadIdServer2 = resComment.body.data[0].id
250
251       resComment = await getVideoThreadComments(servers[2].url, missedVideo2.uuid, threadIdServer2)
252
253       const tree: VideoCommentThreadTree = resComment.body
254       expect(tree.comment.text).equal('thread 1')
255       expect(tree.children).to.have.lengthOf(1)
256
257       const firstChild = tree.children[0]
258       expect(firstChild.comment.text).to.equal('comment 1-1')
259       expect(firstChild.children).to.have.lengthOf(1)
260
261       const childOfFirstChild = firstChild.children[0]
262       expect(childOfFirstChild.comment.text).to.equal('comment 1-2')
263       expect(childOfFirstChild.children).to.have.lengthOf(1)
264
265       const childOfChildFirstChild = childOfFirstChild.children[0]
266       expect(childOfChildFirstChild.comment.text).to.equal('comment 1-3')
267       expect(childOfChildFirstChild.children).to.have.lengthOf(0)
268
269       commentIdServer2 = childOfChildFirstChild.comment.id
270     }
271   })
272
273   it('Should correctly reply to the comment', async function () {
274     this.timeout(15000)
275
276     await addVideoCommentReply(servers[2].url, servers[2].accessToken, missedVideo2.uuid, commentIdServer2, 'comment 1-4')
277
278     await waitJobs(servers)
279
280     {
281       const resComment = await getVideoThreadComments(servers[0].url, missedVideo2.uuid, threadIdServer1)
282
283       const tree: VideoCommentThreadTree = resComment.body
284       expect(tree.comment.text).equal('thread 1')
285       expect(tree.children).to.have.lengthOf(1)
286
287       const firstChild = tree.children[0]
288       expect(firstChild.comment.text).to.equal('comment 1-1')
289       expect(firstChild.children).to.have.lengthOf(1)
290
291       const childOfFirstChild = firstChild.children[0]
292       expect(childOfFirstChild.comment.text).to.equal('comment 1-2')
293       expect(childOfFirstChild.children).to.have.lengthOf(1)
294
295       const childOfChildFirstChild = childOfFirstChild.children[0]
296       expect(childOfChildFirstChild.comment.text).to.equal('comment 1-3')
297       expect(childOfChildFirstChild.children).to.have.lengthOf(1)
298
299       const childOfChildOfChildOfFirstChild = childOfChildFirstChild.children[0]
300       expect(childOfChildOfChildOfFirstChild.comment.text).to.equal('comment 1-4')
301       expect(childOfChildOfChildOfFirstChild.children).to.have.lengthOf(0)
302     }
303   })
304
305   it('Should upload many videos on server 1', async function () {
306     this.timeout(120000)
307
308     for (let i = 0; i < 10; i++) {
309       const uuid = (await uploadVideoAndGetId({ server: servers[ 0 ], videoName: 'video ' + i })).uuid
310       videoIdsServer1.push(uuid)
311     }
312
313     await waitJobs(servers)
314
315     for (const id of videoIdsServer1) {
316       await getVideo(servers[ 1 ].url, id)
317     }
318
319     await waitJobs(servers)
320     await setActorFollowScores(servers[1].internalServerNumber, 20)
321
322     // Wait video expiration
323     await wait(11000)
324
325     // Refresh video -> score + 10 = 30
326     await getVideo(servers[1].url, videoIdsServer1[0])
327
328     await waitJobs(servers)
329   })
330
331   it('Should remove followings that are down', async function () {
332     this.timeout(120000)
333
334     killallServers([ servers[0] ])
335
336     // Wait video expiration
337     await wait(11000)
338
339     for (let i = 0; i < 3; i++) {
340       await getVideo(servers[1].url, videoIdsServer1[i])
341       await wait(1000)
342       await waitJobs([ servers[1] ])
343     }
344
345     for (const id of videoIdsServer1) {
346       await getVideo(servers[1].url, id, 403)
347     }
348   })
349
350   after(async function () {
351     await closeAllSequelize([ servers[1] ])
352
353     await cleanupTests(servers)
354   })
355 })