Fix publishedAt value after following a new instance
[oweals/peertube.git] / server / tests / api / server / follows.ts
1 /* tslint:disable:no-unused-expression */
2
3 import * as chai from 'chai'
4 import 'mocha'
5 import { Video, VideoPrivacy } from '../../../../shared/models/videos'
6 import { VideoComment, VideoCommentThreadTree } from '../../../../shared/models/videos/video-comment.model'
7 import { completeVideoCheck } from '../../utils'
8
9 import {
10   flushAndRunMultipleServers, flushTests, getVideosList, killallServers, ServerInfo, setAccessTokensToServers, uploadVideo,
11   wait
12 } from '../../utils/index'
13 import { dateIsValid } from '../../utils/miscs/miscs'
14 import { follow, getFollowersListPaginationAndSort, getFollowingListPaginationAndSort, unfollow } from '../../utils/server/follows'
15 import { expectAccountFollows } from '../../utils/users/accounts'
16 import { userLogin } from '../../utils/users/login'
17 import { createUser } from '../../utils/users/users'
18 import {
19   addVideoCommentReply, addVideoCommentThread, getVideoCommentThreads,
20   getVideoThreadComments
21 } from '../../utils/videos/video-comments'
22 import { rateVideo } from '../../utils/videos/videos'
23
24 const expect = chai.expect
25
26 describe('Test follows', function () {
27   let servers: ServerInfo[] = []
28
29   before(async function () {
30     this.timeout(30000)
31
32     servers = await flushAndRunMultipleServers(3)
33
34     // Get the access tokens
35     await setAccessTokensToServers(servers)
36   })
37
38   it('Should not have followers', async function () {
39     for (const server of servers) {
40       const res = await getFollowersListPaginationAndSort(server.url, 0, 5, 'createdAt')
41       const follows = res.body.data
42
43       expect(res.body.total).to.equal(0)
44       expect(follows).to.be.an('array')
45       expect(follows.length).to.equal(0)
46     }
47   })
48
49   it('Should not have following', async function () {
50     for (const server of servers) {
51       const res = await getFollowingListPaginationAndSort(server.url, 0, 5, 'createdAt')
52       const follows = res.body.data
53
54       expect(res.body.total).to.equal(0)
55       expect(follows).to.be.an('array')
56       expect(follows.length).to.equal(0)
57     }
58   })
59
60   it('Should have server 1 following server 2 and 3', async function () {
61     this.timeout(10000)
62
63     await follow(servers[0].url, [ servers[1].url, servers[2].url ], servers[0].accessToken)
64
65     await wait(7000)
66   })
67
68   it('Should have 2 followings on server 1', async function () {
69     let res = await getFollowingListPaginationAndSort(servers[0].url, 0, 1, 'createdAt')
70     let follows = res.body.data
71
72     expect(res.body.total).to.equal(2)
73     expect(follows).to.be.an('array')
74     expect(follows.length).to.equal(1)
75
76     res = await getFollowingListPaginationAndSort(servers[0].url, 1, 1, 'createdAt')
77     follows = follows.concat(res.body.data)
78
79     const server2Follow = follows.find(f => f.following.host === 'localhost:9002')
80     const server3Follow = follows.find(f => f.following.host === 'localhost:9003')
81
82     expect(server2Follow).to.not.be.undefined
83     expect(server3Follow).to.not.be.undefined
84     expect(server2Follow.state).to.equal('accepted')
85     expect(server3Follow.state).to.equal('accepted')
86   })
87
88   it('Should have 0 followings on server 1 and 2', async function () {
89     for (const server of [ servers[1], servers[2] ]) {
90       const res = await getFollowingListPaginationAndSort(server.url, 0, 5, 'createdAt')
91       const follows = res.body.data
92
93       expect(res.body.total).to.equal(0)
94       expect(follows).to.be.an('array')
95       expect(follows.length).to.equal(0)
96     }
97   })
98
99   it('Should have 1 followers on server 2 and 3', async function () {
100     for (const server of [ servers[1], servers[2] ]) {
101       let res = await getFollowersListPaginationAndSort(server.url, 0, 1, 'createdAt')
102
103       let follows = res.body.data
104       expect(res.body.total).to.equal(1)
105       expect(follows).to.be.an('array')
106       expect(follows.length).to.equal(1)
107       expect(follows[0].follower.host).to.equal('localhost:9001')
108     }
109   })
110
111   it('Should have 0 followers on server 1', async function () {
112     const res = await getFollowersListPaginationAndSort(servers[0].url, 0, 5, 'createdAt')
113     const follows = res.body.data
114
115     expect(res.body.total).to.equal(0)
116     expect(follows).to.be.an('array')
117     expect(follows.length).to.equal(0)
118   })
119
120   it('Should have the correct follows counts', async function () {
121     await expectAccountFollows(servers[0].url, 'peertube@localhost:9001', 0, 2)
122     await expectAccountFollows(servers[0].url, 'peertube@localhost:9002', 1, 0)
123     await expectAccountFollows(servers[0].url, 'peertube@localhost:9003', 1, 0)
124
125     // Server 2 and 3 does not know server 1 follow another server (there was not a refresh)
126     await expectAccountFollows(servers[1].url, 'peertube@localhost:9001', 0, 1)
127     await expectAccountFollows(servers[1].url, 'peertube@localhost:9002', 1, 0)
128
129     await expectAccountFollows(servers[2].url, 'peertube@localhost:9001', 0, 1)
130     await expectAccountFollows(servers[2].url, 'peertube@localhost:9003', 1, 0)
131   })
132
133   it('Should unfollow server 3 on server 1', async function () {
134     this.timeout(5000)
135
136     await unfollow(servers[0].url, servers[0].accessToken, servers[2])
137
138     await wait(3000)
139   })
140
141   it('Should not follow server 3 on server 1 anymore', async function () {
142     const res = await getFollowingListPaginationAndSort(servers[0].url, 0, 2, 'createdAt')
143     let follows = res.body.data
144
145     expect(res.body.total).to.equal(1)
146     expect(follows).to.be.an('array')
147     expect(follows.length).to.equal(1)
148
149     expect(follows[0].following.host).to.equal('localhost:9002')
150   })
151
152   it('Should not have server 1 as follower on server 3 anymore', async function () {
153     const res = await getFollowersListPaginationAndSort(servers[2].url, 0, 1, 'createdAt')
154
155     let follows = res.body.data
156     expect(res.body.total).to.equal(0)
157     expect(follows).to.be.an('array')
158     expect(follows.length).to.equal(0)
159   })
160
161   it('Should have the correct follows counts 2', async function () {
162     await expectAccountFollows(servers[0].url, 'peertube@localhost:9001', 0, 1)
163     await expectAccountFollows(servers[0].url, 'peertube@localhost:9002', 1, 0)
164
165     await expectAccountFollows(servers[1].url, 'peertube@localhost:9001', 0, 1)
166     await expectAccountFollows(servers[1].url, 'peertube@localhost:9002', 1, 0)
167
168     await expectAccountFollows(servers[2].url, 'peertube@localhost:9001', 0, 0)
169     await expectAccountFollows(servers[2].url, 'peertube@localhost:9003', 0, 0)
170   })
171
172   it('Should upload a video on server 2 and 3 and propagate only the video of server 2', async function () {
173     this.timeout(10000)
174
175     await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'server2' })
176     await uploadVideo(servers[2].url, servers[2].accessToken, { name: 'server3' })
177
178     await wait(5000)
179
180     let res = await getVideosList(servers[0].url)
181     expect(res.body.total).to.equal(1)
182     expect(res.body.data[0].name).to.equal('server2')
183
184     res = await getVideosList(servers[1].url)
185     expect(res.body.total).to.equal(1)
186     expect(res.body.data[0].name).to.equal('server2')
187
188     res = await getVideosList(servers[2].url)
189     expect(res.body.total).to.equal(1)
190     expect(res.body.data[0].name).to.equal('server3')
191   })
192
193   describe('Should propagate data on a new following', async function () {
194     let video4: Video
195
196     before(async function () {
197       this.timeout(20000)
198
199       const video4Attributes = {
200         name: 'server3-4',
201         category: 2,
202         nsfw: true,
203         licence: 6,
204         tags: [ 'tag1', 'tag2', 'tag3' ]
205       }
206
207       await uploadVideo(servers[ 2 ].url, servers[ 2 ].accessToken, { name: 'server3-2' })
208       await uploadVideo(servers[ 2 ].url, servers[ 2 ].accessToken, { name: 'server3-3' })
209       await uploadVideo(servers[ 2 ].url, servers[ 2 ].accessToken, video4Attributes)
210       await uploadVideo(servers[ 2 ].url, servers[ 2 ].accessToken, { name: 'server3-5' })
211       await uploadVideo(servers[ 2 ].url, servers[ 2 ].accessToken, { name: 'server3-6' })
212
213       {
214         const user = { username: 'captain', password: 'password' }
215         await createUser(servers[ 2 ].url, servers[ 2 ].accessToken, user.username, user.password)
216         const userAccessToken = await userLogin(servers[ 2 ], user)
217
218         const resVideos = await getVideosList(servers[ 2 ].url)
219         video4 = resVideos.body.data.find(v => v.name === 'server3-4')
220
221         {
222           await rateVideo(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, 'like')
223           await rateVideo(servers[ 2 ].url, userAccessToken, video4.id, 'dislike')
224         }
225
226         {
227           const text = 'my super first comment'
228           const res = await addVideoCommentThread(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, text)
229           const threadId = res.body.comment.id
230
231           const text1 = 'my super answer to thread 1'
232           const childCommentRes = await addVideoCommentReply(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, threadId, text1)
233           const childCommentId = childCommentRes.body.comment.id
234
235           const text2 = 'my super answer to answer of thread 1'
236           await addVideoCommentReply(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, childCommentId, text2)
237
238           const text3 = 'my second answer to thread 1'
239           await addVideoCommentReply(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, threadId, text3)
240         }
241       }
242
243       await wait(5000)
244
245       // Server 1 follows server 3
246       await follow(servers[ 0 ].url, [ servers[ 2 ].url ], servers[ 0 ].accessToken)
247
248       await wait(7000)
249     })
250
251     it('Should have the correct follows counts 3', async function () {
252       await expectAccountFollows(servers[0].url, 'peertube@localhost:9001', 0, 2)
253       await expectAccountFollows(servers[0].url, 'peertube@localhost:9002', 1, 0)
254       await expectAccountFollows(servers[0].url, 'peertube@localhost:9003', 1, 0)
255
256       await expectAccountFollows(servers[1].url, 'peertube@localhost:9001', 0, 1)
257       await expectAccountFollows(servers[1].url, 'peertube@localhost:9002', 1, 0)
258
259       await expectAccountFollows(servers[2].url, 'peertube@localhost:9001', 0, 2)
260       await expectAccountFollows(servers[2].url, 'peertube@localhost:9003', 1, 0)
261     })
262
263     it('Should propagate videos', async function () {
264       const res = await getVideosList(servers[ 0 ].url)
265       expect(res.body.total).to.equal(7)
266
267       const video2 = res.body.data.find(v => v.name === 'server3-2')
268       video4 = res.body.data.find(v => v.name === 'server3-4')
269       const video6 = res.body.data.find(v => v.name === 'server3-6')
270
271       expect(video2).to.not.be.undefined
272       expect(video4).to.not.be.undefined
273       expect(video6).to.not.be.undefined
274
275       const isLocal = false
276       const checkAttributes = {
277         name: 'server3-4',
278         category: 2,
279         licence: 6,
280         language: 'zh',
281         nsfw: true,
282         description: 'my super description',
283         support: 'my super support text',
284         account: {
285           name: 'root',
286           host: 'localhost:9003'
287         },
288         isLocal,
289         commentsEnabled: true,
290         duration: 5,
291         tags: [ 'tag1', 'tag2', 'tag3' ],
292         privacy: VideoPrivacy.PUBLIC,
293         likes: 1,
294         dislikes: 1,
295         channel: {
296           name: 'Default root channel',
297           description: '',
298           isLocal
299         },
300         fixture: 'video_short.webm',
301         files: [
302           {
303             resolution: 720,
304             size: 218910
305           }
306         ]
307       }
308       await completeVideoCheck(servers[ 0 ].url, video4, checkAttributes)
309     })
310
311     it('Should propagate comments', async function () {
312       const res1 = await getVideoCommentThreads(servers[0].url, video4.id, 0, 5)
313
314       expect(res1.body.total).to.equal(1)
315       expect(res1.body.data).to.be.an('array')
316       expect(res1.body.data).to.have.lengthOf(1)
317
318       const comment: VideoComment = res1.body.data[0]
319       expect(comment.inReplyToCommentId).to.be.null
320       expect(comment.text).equal('my super first comment')
321       expect(comment.videoId).to.equal(video4.id)
322       expect(comment.id).to.equal(comment.threadId)
323       expect(comment.account.name).to.equal('root')
324       expect(comment.account.host).to.equal('localhost:9003')
325       expect(comment.totalReplies).to.equal(3)
326       expect(dateIsValid(comment.createdAt as string)).to.be.true
327       expect(dateIsValid(comment.updatedAt as string)).to.be.true
328
329       const threadId = comment.threadId
330
331       const res2 = await getVideoThreadComments(servers[0].url, video4.id, threadId)
332
333       const tree: VideoCommentThreadTree = res2.body
334       expect(tree.comment.text).equal('my super first comment')
335       expect(tree.children).to.have.lengthOf(2)
336
337       const firstChild = tree.children[0]
338       expect(firstChild.comment.text).to.equal('my super answer to thread 1')
339       expect(firstChild.children).to.have.lengthOf(1)
340
341       const childOfFirstChild = firstChild.children[0]
342       expect(childOfFirstChild.comment.text).to.equal('my super answer to answer of thread 1')
343       expect(childOfFirstChild.children).to.have.lengthOf(0)
344
345       const secondChild = tree.children[1]
346       expect(secondChild.comment.text).to.equal('my second answer to thread 1')
347       expect(secondChild.children).to.have.lengthOf(0)
348     })
349
350     it('Should unfollow server 3 on server 1 and does not list server 3 videos', async function () {
351       this.timeout(5000)
352
353       await unfollow(servers[0].url, servers[0].accessToken, servers[2])
354
355       await wait(3000)
356
357       let res = await getVideosList(servers[ 0 ].url)
358       expect(res.body.total).to.equal(1)
359     })
360
361   })
362
363   after(async function () {
364     killallServers(servers)
365
366     // Keep the logs if the test failed
367     if (this['ok']) {
368       await flushTests()
369     }
370   })
371 })