Add ability to filter per job type
[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({ url: servers[ 0 ].url, start: 0, count: 2, sort: '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({
188         url: servers[ 0 ].url,
189         accessToken: servers[ 0 ].accessToken,
190         state: state,
191         start: 0,
192         count: 50,
193         sort: '-createdAt'
194       })
195       expect(res.body.data).to.have.length(0)
196     }
197   })
198
199   it('Should re-follow server 1', async function () {
200     this.timeout(35000)
201
202     await reRunServer(servers[1])
203     await reRunServer(servers[2])
204
205     await unfollow(servers[1].url, servers[1].accessToken, servers[0])
206     await waitJobs(servers)
207
208     await follow(servers[1].url, [ servers[0].url ], servers[1].accessToken)
209
210     await waitJobs(servers)
211
212     const res = await getFollowersListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 2, sort: 'createdAt' })
213     expect(res.body.data).to.be.an('array')
214     expect(res.body.data).to.have.lengthOf(2)
215   })
216
217   it('Should send an update to server 3, and automatically fetch the video', async function () {
218     this.timeout(15000)
219
220     const res1 = await getVideosList(servers[2].url)
221     expect(res1.body.data).to.be.an('array')
222     expect(res1.body.data).to.have.lengthOf(11)
223
224     await updateVideo(servers[0].url, servers[0].accessToken, missedVideo1.uuid, { })
225     await updateVideo(servers[0].url, servers[0].accessToken, unlistedVideo.uuid, { })
226
227     await waitJobs(servers)
228
229     const res = await getVideosList(servers[2].url)
230     expect(res.body.data).to.be.an('array')
231     // 1 video is unlisted
232     expect(res.body.data).to.have.lengthOf(12)
233
234     // Check unlisted video
235     const resVideo = await getVideo(servers[2].url, unlistedVideo.uuid)
236     expect(resVideo.body).not.to.be.undefined
237
238     await completeVideoCheck(servers[2].url, resVideo.body, unlistedCheckAttributes)
239   })
240
241   it('Should send comments on a video to server 3, and automatically fetch the video', async function () {
242     this.timeout(25000)
243
244     await addVideoCommentReply(servers[0].url, servers[0].accessToken, missedVideo2.uuid, commentIdServer1, 'comment 1-3')
245
246     await waitJobs(servers)
247
248     const resVideo = await getVideo(servers[2].url, missedVideo2.uuid)
249     expect(resVideo.body).not.to.be.undefined
250
251     {
252       let resComment = await getVideoCommentThreads(servers[2].url, missedVideo2.uuid, 0, 5)
253       expect(resComment.body.data).to.be.an('array')
254       expect(resComment.body.data).to.have.lengthOf(1)
255
256       threadIdServer2 = resComment.body.data[0].id
257
258       resComment = await getVideoThreadComments(servers[2].url, missedVideo2.uuid, threadIdServer2)
259
260       const tree: VideoCommentThreadTree = resComment.body
261       expect(tree.comment.text).equal('thread 1')
262       expect(tree.children).to.have.lengthOf(1)
263
264       const firstChild = tree.children[0]
265       expect(firstChild.comment.text).to.equal('comment 1-1')
266       expect(firstChild.children).to.have.lengthOf(1)
267
268       const childOfFirstChild = firstChild.children[0]
269       expect(childOfFirstChild.comment.text).to.equal('comment 1-2')
270       expect(childOfFirstChild.children).to.have.lengthOf(1)
271
272       const childOfChildFirstChild = childOfFirstChild.children[0]
273       expect(childOfChildFirstChild.comment.text).to.equal('comment 1-3')
274       expect(childOfChildFirstChild.children).to.have.lengthOf(0)
275
276       commentIdServer2 = childOfChildFirstChild.comment.id
277     }
278   })
279
280   it('Should correctly reply to the comment', async function () {
281     this.timeout(15000)
282
283     await addVideoCommentReply(servers[2].url, servers[2].accessToken, missedVideo2.uuid, commentIdServer2, 'comment 1-4')
284
285     await waitJobs(servers)
286
287     {
288       const resComment = await getVideoThreadComments(servers[0].url, missedVideo2.uuid, threadIdServer1)
289
290       const tree: VideoCommentThreadTree = resComment.body
291       expect(tree.comment.text).equal('thread 1')
292       expect(tree.children).to.have.lengthOf(1)
293
294       const firstChild = tree.children[0]
295       expect(firstChild.comment.text).to.equal('comment 1-1')
296       expect(firstChild.children).to.have.lengthOf(1)
297
298       const childOfFirstChild = firstChild.children[0]
299       expect(childOfFirstChild.comment.text).to.equal('comment 1-2')
300       expect(childOfFirstChild.children).to.have.lengthOf(1)
301
302       const childOfChildFirstChild = childOfFirstChild.children[0]
303       expect(childOfChildFirstChild.comment.text).to.equal('comment 1-3')
304       expect(childOfChildFirstChild.children).to.have.lengthOf(1)
305
306       const childOfChildOfChildOfFirstChild = childOfChildFirstChild.children[0]
307       expect(childOfChildOfChildOfFirstChild.comment.text).to.equal('comment 1-4')
308       expect(childOfChildOfChildOfFirstChild.children).to.have.lengthOf(0)
309     }
310   })
311
312   it('Should upload many videos on server 1', async function () {
313     this.timeout(120000)
314
315     for (let i = 0; i < 10; i++) {
316       const uuid = (await uploadVideoAndGetId({ server: servers[ 0 ], videoName: 'video ' + i })).uuid
317       videoIdsServer1.push(uuid)
318     }
319
320     await waitJobs(servers)
321
322     for (const id of videoIdsServer1) {
323       await getVideo(servers[ 1 ].url, id)
324     }
325
326     await waitJobs(servers)
327     await setActorFollowScores(servers[1].internalServerNumber, 20)
328
329     // Wait video expiration
330     await wait(11000)
331
332     // Refresh video -> score + 10 = 30
333     await getVideo(servers[1].url, videoIdsServer1[0])
334
335     await waitJobs(servers)
336   })
337
338   it('Should remove followings that are down', async function () {
339     this.timeout(120000)
340
341     killallServers([ servers[0] ])
342
343     // Wait video expiration
344     await wait(11000)
345
346     for (let i = 0; i < 3; i++) {
347       await getVideo(servers[1].url, videoIdsServer1[i])
348       await wait(1000)
349       await waitJobs([ servers[1] ])
350     }
351
352     for (const id of videoIdsServer1) {
353       await getVideo(servers[1].url, id, 403)
354     }
355   })
356
357   after(async function () {
358     await closeAllSequelize([ servers[1] ])
359
360     await cleanupTests(servers)
361   })
362 })