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