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