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