aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/tests/api
diff options
context:
space:
mode:
Diffstat (limited to 'server/tests/api')
-rw-r--r--server/tests/api/check-params/bulk.ts88
-rw-r--r--server/tests/api/check-params/config.ts6
-rw-r--r--server/tests/api/check-params/index.ts1
-rw-r--r--server/tests/api/server/bulk.ts198
-rw-r--r--server/tests/api/server/config.ts16
-rw-r--r--server/tests/api/users/blocklist.ts178
-rw-r--r--server/tests/api/videos/multiple-servers.ts9
7 files changed, 465 insertions, 31 deletions
diff --git a/server/tests/api/check-params/bulk.ts b/server/tests/api/check-params/bulk.ts
new file mode 100644
index 000000000..432858b33
--- /dev/null
+++ b/server/tests/api/check-params/bulk.ts
@@ -0,0 +1,88 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import 'mocha'
4import {
5 cleanupTests,
6 createUser,
7 flushAndRunServer,
8 ServerInfo,
9 setAccessTokensToServers,
10 userLogin
11} from '../../../../shared/extra-utils'
12import { makePostBodyRequest } from '../../../../shared/extra-utils/requests/requests'
13
14describe('Test bulk API validators', function () {
15 let server: ServerInfo
16 let userAccessToken: string
17
18 // ---------------------------------------------------------------
19
20 before(async function () {
21 this.timeout(120000)
22
23 server = await flushAndRunServer(1)
24 await setAccessTokensToServers([ server ])
25
26 const user = { username: 'user1', password: 'password' }
27 await createUser({ url: server.url, accessToken: server.accessToken, username: user.username, password: user.password })
28
29 userAccessToken = await userLogin(server, user)
30 })
31
32 describe('When removing comments of', function () {
33 const path = '/api/v1/bulk/remove-comments-of'
34
35 it('Should fail with an unauthenticated user', async function () {
36 await makePostBodyRequest({
37 url: server.url,
38 path,
39 fields: { accountName: 'user1', scope: 'my-videos' },
40 statusCodeExpected: 401
41 })
42 })
43
44 it('Should fail with an unknown account', async function () {
45 await makePostBodyRequest({
46 url: server.url,
47 token: server.accessToken,
48 path,
49 fields: { accountName: 'user2', scope: 'my-videos' },
50 statusCodeExpected: 404
51 })
52 })
53
54 it('Should fail with an invalid scope', async function () {
55 await makePostBodyRequest({
56 url: server.url,
57 token: server.accessToken,
58 path,
59 fields: { accountName: 'user1', scope: 'my-videoss' },
60 statusCodeExpected: 400
61 })
62 })
63
64 it('Should fail to delete comments of the instance without the appropriate rights', async function () {
65 await makePostBodyRequest({
66 url: server.url,
67 token: userAccessToken,
68 path,
69 fields: { accountName: 'user1', scope: 'instance' },
70 statusCodeExpected: 403
71 })
72 })
73
74 it('Should succeed with the correct params', async function () {
75 await makePostBodyRequest({
76 url: server.url,
77 token: server.accessToken,
78 path,
79 fields: { accountName: 'user1', scope: 'instance' },
80 statusCodeExpected: 204
81 })
82 })
83 })
84
85 after(async function () {
86 await cleanupTests([ server ])
87 })
88})
diff --git a/server/tests/api/check-params/config.ts b/server/tests/api/check-params/config.ts
index f1a79806b..7c96fa762 100644
--- a/server/tests/api/check-params/config.ts
+++ b/server/tests/api/check-params/config.ts
@@ -133,6 +133,12 @@ describe('Test config API validators', function () {
133 indexUrl: 'https://index.example.com' 133 indexUrl: 'https://index.example.com'
134 } 134 }
135 } 135 }
136 },
137 broadcastMessage: {
138 enabled: true,
139 dismissable: true,
140 message: 'super message',
141 level: 'warning'
136 } 142 }
137 } 143 }
138 144
diff --git a/server/tests/api/check-params/index.ts b/server/tests/api/check-params/index.ts
index ef152f55c..93ffd98b1 100644
--- a/server/tests/api/check-params/index.ts
+++ b/server/tests/api/check-params/index.ts
@@ -1,5 +1,6 @@
1import './accounts' 1import './accounts'
2import './blocklist' 2import './blocklist'
3import './bulk'
3import './config' 4import './config'
4import './contact-form' 5import './contact-form'
5import './debug' 6import './debug'
diff --git a/server/tests/api/server/bulk.ts b/server/tests/api/server/bulk.ts
new file mode 100644
index 000000000..63321d4bb
--- /dev/null
+++ b/server/tests/api/server/bulk.ts
@@ -0,0 +1,198 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import 'mocha'
4import * as chai from 'chai'
5import { VideoComment } from '@shared/models/videos/video-comment.model'
6import {
7 addVideoCommentThread,
8 bulkRemoveCommentsOf,
9 cleanupTests,
10 createUser,
11 flushAndRunMultipleServers,
12 getVideoCommentThreads,
13 getVideosList,
14 ServerInfo,
15 setAccessTokensToServers,
16 uploadVideo,
17 userLogin,
18 waitJobs,
19 addVideoCommentReply
20} from '../../../../shared/extra-utils/index'
21import { doubleFollow } from '../../../../shared/extra-utils/server/follows'
22import { Video } from '@shared/models'
23
24const expect = chai.expect
25
26describe('Test bulk actions', function () {
27 const commentsUser3: { videoId: number, commentId: number }[] = []
28
29 let servers: ServerInfo[] = []
30 let user1AccessToken: string
31 let user2AccessToken: string
32 let user3AccessToken: string
33
34 before(async function () {
35 this.timeout(30000)
36
37 servers = await flushAndRunMultipleServers(2)
38
39 // Get the access tokens
40 await setAccessTokensToServers(servers)
41
42 {
43 const user = { username: 'user1', password: 'password' }
44 await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: user.username, password: user.password })
45
46 user1AccessToken = await userLogin(servers[0], user)
47 }
48
49 {
50 const user = { username: 'user2', password: 'password' }
51 await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: user.username, password: user.password })
52
53 user2AccessToken = await userLogin(servers[0], user)
54 }
55
56 {
57 const user = { username: 'user3', password: 'password' }
58 await createUser({ url: servers[1].url, accessToken: servers[1].accessToken, username: user.username, password: user.password })
59
60 user3AccessToken = await userLogin(servers[1], user)
61 }
62
63 await doubleFollow(servers[0], servers[1])
64 })
65
66 describe('Bulk remove comments', function () {
67 async function checkInstanceCommentsRemoved () {
68 {
69 const res = await getVideosList(servers[0].url)
70 const videos = res.body.data as Video[]
71
72 // Server 1 should not have these comments anymore
73 for (const video of videos) {
74 const resThreads = await getVideoCommentThreads(servers[0].url, video.id, 0, 10)
75 const comments = resThreads.body.data as VideoComment[]
76 const comment = comments.find(c => c.text === 'comment by user 3')
77
78 expect(comment).to.not.exist
79 }
80 }
81
82 {
83 const res = await getVideosList(servers[1].url)
84 const videos = res.body.data as Video[]
85
86 // Server 1 should not have these comments on videos of server 1
87 for (const video of videos) {
88 const resThreads = await getVideoCommentThreads(servers[1].url, video.id, 0, 10)
89 const comments = resThreads.body.data as VideoComment[]
90 const comment = comments.find(c => c.text === 'comment by user 3')
91
92 if (video.account.host === 'localhost:' + servers[0].port) {
93 expect(comment).to.not.exist
94 } else {
95 expect(comment).to.exist
96 }
97 }
98 }
99 }
100
101 before(async function () {
102 this.timeout(60000)
103
104 await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video 1 server 1' })
105 await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video 2 server 1' })
106 await uploadVideo(servers[0].url, user1AccessToken, { name: 'video 3 server 1' })
107
108 await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video 1 server 2' })
109
110 await waitJobs(servers)
111
112 {
113 const res = await getVideosList(servers[0].url)
114 for (const video of res.body.data) {
115 await addVideoCommentThread(servers[0].url, servers[0].accessToken, video.id, 'comment by root server 1')
116 await addVideoCommentThread(servers[0].url, user1AccessToken, video.id, 'comment by user 1')
117 await addVideoCommentThread(servers[0].url, user2AccessToken, video.id, 'comment by user 2')
118 }
119 }
120
121 {
122 const res = await getVideosList(servers[1].url)
123 for (const video of res.body.data) {
124 await addVideoCommentThread(servers[1].url, servers[1].accessToken, video.id, 'comment by root server 2')
125
126 const res = await addVideoCommentThread(servers[1].url, user3AccessToken, video.id, 'comment by user 3')
127 commentsUser3.push({ videoId: video.id, commentId: res.body.comment.id })
128 }
129 }
130
131 await waitJobs(servers)
132 })
133
134 it('Should delete comments of an account on my videos', async function () {
135 this.timeout(60000)
136
137 await bulkRemoveCommentsOf({
138 url: servers[0].url,
139 token: user1AccessToken,
140 attributes: {
141 accountName: 'user2',
142 scope: 'my-videos'
143 }
144 })
145
146 await waitJobs(servers)
147
148 for (const server of servers) {
149 const res = await getVideosList(server.url)
150
151 for (const video of res.body.data) {
152 const resThreads = await getVideoCommentThreads(server.url, video.id, 0, 10)
153 const comments = resThreads.body.data as VideoComment[]
154 const comment = comments.find(c => c.text === 'comment by user 2')
155
156 if (video.name === 'video 3 server 1') {
157 expect(comment).to.not.exist
158 } else {
159 expect(comment).to.exist
160 }
161 }
162 }
163 })
164
165 it('Should delete comments of an account on the instance', async function () {
166 this.timeout(60000)
167
168 await bulkRemoveCommentsOf({
169 url: servers[0].url,
170 token: servers[0].accessToken,
171 attributes: {
172 accountName: 'user3@localhost:' + servers[1].port,
173 scope: 'instance'
174 }
175 })
176
177 await waitJobs(servers)
178
179 await checkInstanceCommentsRemoved()
180 })
181
182 it('Should not re create the comment on video update', async function () {
183 this.timeout(60000)
184
185 for (const obj of commentsUser3) {
186 await addVideoCommentReply(servers[1].url, user3AccessToken, obj.videoId, obj.commentId, 'comment by user 3 bis')
187 }
188
189 await waitJobs(servers)
190
191 await checkInstanceCommentsRemoved()
192 })
193 })
194
195 after(async function () {
196 await cleanupTests(servers)
197 })
198})
diff --git a/server/tests/api/server/config.ts b/server/tests/api/server/config.ts
index 8580835d6..d18a93082 100644
--- a/server/tests/api/server/config.ts
+++ b/server/tests/api/server/config.ts
@@ -87,6 +87,11 @@ function checkInitialConfig (server: ServerInfo, data: CustomConfig) {
87 expect(data.followings.instance.autoFollowBack.enabled).to.be.false 87 expect(data.followings.instance.autoFollowBack.enabled).to.be.false
88 expect(data.followings.instance.autoFollowIndex.enabled).to.be.false 88 expect(data.followings.instance.autoFollowIndex.enabled).to.be.false
89 expect(data.followings.instance.autoFollowIndex.indexUrl).to.equal('') 89 expect(data.followings.instance.autoFollowIndex.indexUrl).to.equal('')
90
91 expect(data.broadcastMessage.enabled).to.be.false
92 expect(data.broadcastMessage.level).to.equal('info')
93 expect(data.broadcastMessage.message).to.equal('')
94 expect(data.broadcastMessage.dismissable).to.be.false
90} 95}
91 96
92function checkUpdatedConfig (data: CustomConfig) { 97function checkUpdatedConfig (data: CustomConfig) {
@@ -155,6 +160,11 @@ function checkUpdatedConfig (data: CustomConfig) {
155 expect(data.followings.instance.autoFollowBack.enabled).to.be.true 160 expect(data.followings.instance.autoFollowBack.enabled).to.be.true
156 expect(data.followings.instance.autoFollowIndex.enabled).to.be.true 161 expect(data.followings.instance.autoFollowIndex.enabled).to.be.true
157 expect(data.followings.instance.autoFollowIndex.indexUrl).to.equal('https://updated.example.com') 162 expect(data.followings.instance.autoFollowIndex.indexUrl).to.equal('https://updated.example.com')
163
164 expect(data.broadcastMessage.enabled).to.be.true
165 expect(data.broadcastMessage.level).to.equal('error')
166 expect(data.broadcastMessage.message).to.equal('super bad message')
167 expect(data.broadcastMessage.dismissable).to.be.true
158} 168}
159 169
160describe('Test config', function () { 170describe('Test config', function () {
@@ -324,6 +334,12 @@ describe('Test config', function () {
324 indexUrl: 'https://updated.example.com' 334 indexUrl: 'https://updated.example.com'
325 } 335 }
326 } 336 }
337 },
338 broadcastMessage: {
339 enabled: true,
340 level: 'error',
341 message: 'super bad message',
342 dismissable: true
327 } 343 }
328 } 344 }
329 await updateCustomConfig(server.url, server.accessToken, newCustomConfig) 345 await updateCustomConfig(server.url, server.accessToken, newCustomConfig)
diff --git a/server/tests/api/users/blocklist.ts b/server/tests/api/users/blocklist.ts
index 21b9ae4f8..8c9107a50 100644
--- a/server/tests/api/users/blocklist.ts
+++ b/server/tests/api/users/blocklist.ts
@@ -2,7 +2,7 @@
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
5import { AccountBlock, ServerBlock, Video } from '../../../../shared/index' 5import { AccountBlock, ServerBlock, Video, UserNotification, UserNotificationType } from '../../../../shared/index'
6import { 6import {
7 cleanupTests, 7 cleanupTests,
8 createUser, 8 createUser,
@@ -11,7 +11,9 @@ import {
11 flushAndRunMultipleServers, 11 flushAndRunMultipleServers,
12 ServerInfo, 12 ServerInfo,
13 uploadVideo, 13 uploadVideo,
14 userLogin 14 userLogin,
15 follow,
16 unfollow
15} from '../../../../shared/extra-utils/index' 17} from '../../../../shared/extra-utils/index'
16import { setAccessTokensToServers } from '../../../../shared/extra-utils/users/login' 18import { setAccessTokensToServers } from '../../../../shared/extra-utils/users/login'
17import { getVideosList, getVideosListWithToken } from '../../../../shared/extra-utils/videos/videos' 19import { getVideosList, getVideosListWithToken } from '../../../../shared/extra-utils/videos/videos'
@@ -19,7 +21,8 @@ import {
19 addVideoCommentReply, 21 addVideoCommentReply,
20 addVideoCommentThread, 22 addVideoCommentThread,
21 getVideoCommentThreads, 23 getVideoCommentThreads,
22 getVideoThreadComments 24 getVideoThreadComments,
25 findCommentId
23} from '../../../../shared/extra-utils/videos/video-comments' 26} from '../../../../shared/extra-utils/videos/video-comments'
24import { waitJobs } from '../../../../shared/extra-utils/server/jobs' 27import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
25import { VideoComment, VideoCommentThreadTree } from '../../../../shared/models/videos/video-comment.model' 28import { VideoComment, VideoCommentThreadTree } from '../../../../shared/models/videos/video-comment.model'
@@ -45,13 +48,13 @@ async function checkAllVideos (url: string, token: string) {
45 { 48 {
46 const res = await getVideosListWithToken(url, token) 49 const res = await getVideosListWithToken(url, token)
47 50
48 expect(res.body.data).to.have.lengthOf(4) 51 expect(res.body.data).to.have.lengthOf(5)
49 } 52 }
50 53
51 { 54 {
52 const res = await getVideosList(url) 55 const res = await getVideosList(url)
53 56
54 expect(res.body.data).to.have.lengthOf(4) 57 expect(res.body.data).to.have.lengthOf(5)
55 } 58 }
56} 59}
57 60
@@ -76,13 +79,15 @@ async function checkCommentNotification (
76 check: 'presence' | 'absence' 79 check: 'presence' | 'absence'
77) { 80) {
78 const resComment = await addVideoCommentThread(comment.server.url, comment.token, comment.videoUUID, comment.text) 81 const resComment = await addVideoCommentThread(comment.server.url, comment.token, comment.videoUUID, comment.text)
79 const threadId = resComment.body.comment.id 82 const created = resComment.body.comment as VideoComment
83 const threadId = created.id
84 const createdAt = created.createdAt
80 85
81 await waitJobs([ mainServer, comment.server ]) 86 await waitJobs([ mainServer, comment.server ])
82 87
83 const res = await getUserNotifications(mainServer.url, mainServer.accessToken, 0, 30) 88 const res = await getUserNotifications(mainServer.url, mainServer.accessToken, 0, 30)
84 const commentNotifications = res.body.data 89 const commentNotifications = (res.body.data as UserNotification[])
85 .filter(n => n.comment && n.comment.id === threadId) 90 .filter(n => n.comment && n.comment.video.uuid === comment.videoUUID && n.createdAt >= createdAt)
86 91
87 if (check === 'presence') expect(commentNotifications).to.have.lengthOf(1) 92 if (check === 'presence') expect(commentNotifications).to.have.lengthOf(1)
88 else expect(commentNotifications).to.have.lengthOf(0) 93 else expect(commentNotifications).to.have.lengthOf(0)
@@ -96,6 +101,7 @@ describe('Test blocklist', function () {
96 let servers: ServerInfo[] 101 let servers: ServerInfo[]
97 let videoUUID1: string 102 let videoUUID1: string
98 let videoUUID2: string 103 let videoUUID2: string
104 let videoUUID3: string
99 let userToken1: string 105 let userToken1: string
100 let userModeratorToken: string 106 let userModeratorToken: string
101 let userToken2: string 107 let userToken2: string
@@ -103,7 +109,7 @@ describe('Test blocklist', function () {
103 before(async function () { 109 before(async function () {
104 this.timeout(60000) 110 this.timeout(60000)
105 111
106 servers = await flushAndRunMultipleServers(2) 112 servers = await flushAndRunMultipleServers(3)
107 await setAccessTokensToServers(servers) 113 await setAccessTokensToServers(servers)
108 114
109 { 115 {
@@ -139,7 +145,13 @@ describe('Test blocklist', function () {
139 videoUUID2 = res.body.video.uuid 145 videoUUID2 = res.body.video.uuid
140 } 146 }
141 147
148 {
149 const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video 2 server 1' })
150 videoUUID3 = res.body.video.uuid
151 }
152
142 await doubleFollow(servers[0], servers[1]) 153 await doubleFollow(servers[0], servers[1])
154 await doubleFollow(servers[0], servers[2])
143 155
144 { 156 {
145 const resComment = await addVideoCommentThread(servers[0].url, servers[0].accessToken, videoUUID1, 'comment root 1') 157 const resComment = await addVideoCommentThread(servers[0].url, servers[0].accessToken, videoUUID1, 'comment root 1')
@@ -174,7 +186,7 @@ describe('Test blocklist', function () {
174 const res = await getVideosListWithToken(servers[0].url, servers[0].accessToken) 186 const res = await getVideosListWithToken(servers[0].url, servers[0].accessToken)
175 187
176 const videos: Video[] = res.body.data 188 const videos: Video[] = res.body.data
177 expect(videos).to.have.lengthOf(3) 189 expect(videos).to.have.lengthOf(4)
178 190
179 const v = videos.find(v => v.name === 'video user 2') 191 const v = videos.find(v => v.name === 'video user 2')
180 expect(v).to.be.undefined 192 expect(v).to.be.undefined
@@ -188,14 +200,14 @@ describe('Test blocklist', function () {
188 const res = await getVideosListWithToken(servers[0].url, servers[0].accessToken) 200 const res = await getVideosListWithToken(servers[0].url, servers[0].accessToken)
189 201
190 const videos: Video[] = res.body.data 202 const videos: Video[] = res.body.data
191 expect(videos).to.have.lengthOf(2) 203 expect(videos).to.have.lengthOf(3)
192 204
193 const v = videos.find(v => v.name === 'video user 1') 205 const v = videos.find(v => v.name === 'video user 1')
194 expect(v).to.be.undefined 206 expect(v).to.be.undefined
195 }) 207 })
196 208
197 it('Should hide its comments', async function () { 209 it('Should hide its comments', async function () {
198 const resThreads = await getVideoCommentThreads(servers[0].url, videoUUID1, 0, 5, '-createdAt', servers[0].accessToken) 210 const resThreads = await getVideoCommentThreads(servers[0].url, videoUUID1, 0, 25, '-createdAt', servers[0].accessToken)
199 211
200 const threads: VideoComment[] = resThreads.body.data 212 const threads: VideoComment[] = resThreads.body.data
201 expect(threads).to.have.lengthOf(1) 213 expect(threads).to.have.lengthOf(1)
@@ -235,10 +247,6 @@ describe('Test blocklist', function () {
235 return checkAllVideos(servers[0].url, userToken1) 247 return checkAllVideos(servers[0].url, userToken1)
236 }) 248 })
237 249
238 it('Should list all the comments with another user', async function () {
239 return checkAllComments(servers[0].url, userToken1, videoUUID1)
240 })
241
242 it('Should list blocked accounts', async function () { 250 it('Should list blocked accounts', async function () {
243 { 251 {
244 const res = await getAccountBlocklistByAccount(servers[0].url, servers[0].accessToken, 0, 1, 'createdAt') 252 const res = await getAccountBlocklistByAccount(servers[0].url, servers[0].accessToken, 0, 1, 'createdAt')
@@ -269,6 +277,61 @@ describe('Test blocklist', function () {
269 } 277 }
270 }) 278 })
271 279
280 it('Should not allow a remote blocked user to comment my videos', async function () {
281 this.timeout(60000)
282
283 {
284 await addVideoCommentThread(servers[1].url, userToken2, videoUUID3, 'comment user 2')
285 await waitJobs(servers)
286
287 await addVideoCommentThread(servers[0].url, servers[0].accessToken, videoUUID3, 'uploader')
288 await waitJobs(servers)
289
290 const commentId = await findCommentId(servers[1].url, videoUUID3, 'uploader')
291 const message = 'reply by user 2'
292 const resReply = await addVideoCommentReply(servers[1].url, userToken2, videoUUID3, commentId, message)
293 await addVideoCommentReply(servers[1].url, servers[1].accessToken, videoUUID3, resReply.body.comment.id, 'another reply')
294
295 await waitJobs(servers)
296 }
297
298 // Server 2 has all the comments
299 {
300 const resThreads = await getVideoCommentThreads(servers[1].url, videoUUID3, 0, 25, '-createdAt')
301 const threads: VideoComment[] = resThreads.body.data
302
303 expect(threads).to.have.lengthOf(2)
304 expect(threads[0].text).to.equal('uploader')
305 expect(threads[1].text).to.equal('comment user 2')
306
307 const resReplies = await getVideoThreadComments(servers[1].url, videoUUID3, threads[0].id)
308
309 const tree: VideoCommentThreadTree = resReplies.body
310 expect(tree.children).to.have.lengthOf(1)
311 expect(tree.children[0].comment.text).to.equal('reply by user 2')
312 expect(tree.children[0].children).to.have.lengthOf(1)
313 expect(tree.children[0].children[0].comment.text).to.equal('another reply')
314 }
315
316 // Server 1 and 3 should only have uploader comments
317 for (const server of [ servers[0], servers[2] ]) {
318 const resThreads = await getVideoCommentThreads(server.url, videoUUID3, 0, 25, '-createdAt')
319 const threads: VideoComment[] = resThreads.body.data
320
321 expect(threads).to.have.lengthOf(1)
322 expect(threads[0].text).to.equal('uploader')
323
324 const resReplies = await getVideoThreadComments(server.url, videoUUID3, threads[0].id)
325
326 const tree: VideoCommentThreadTree = resReplies.body
327 if (server.serverNumber === 1) {
328 expect(tree.children).to.have.lengthOf(0)
329 } else {
330 expect(tree.children).to.have.lengthOf(1)
331 }
332 }
333 })
334
272 it('Should unblock the remote account', async function () { 335 it('Should unblock the remote account', async function () {
273 await removeAccountFromAccountBlocklist(servers[0].url, servers[0].accessToken, 'user2@localhost:' + servers[1].port) 336 await removeAccountFromAccountBlocklist(servers[0].url, servers[0].accessToken, 'user2@localhost:' + servers[1].port)
274 }) 337 })
@@ -277,12 +340,37 @@ describe('Test blocklist', function () {
277 const res = await getVideosListWithToken(servers[0].url, servers[0].accessToken) 340 const res = await getVideosListWithToken(servers[0].url, servers[0].accessToken)
278 341
279 const videos: Video[] = res.body.data 342 const videos: Video[] = res.body.data
280 expect(videos).to.have.lengthOf(3) 343 expect(videos).to.have.lengthOf(4)
281 344
282 const v = videos.find(v => v.name === 'video user 2') 345 const v = videos.find(v => v.name === 'video user 2')
283 expect(v).not.to.be.undefined 346 expect(v).not.to.be.undefined
284 }) 347 })
285 348
349 it('Should display its comments on my video', async function () {
350 for (const server of servers) {
351 const resThreads = await getVideoCommentThreads(server.url, videoUUID3, 0, 25, '-createdAt')
352 const threads: VideoComment[] = resThreads.body.data
353
354 // Server 3 should not have 2 comment threads, because server 1 did not forward the server 2 comment
355 if (server.serverNumber === 3) {
356 expect(threads).to.have.lengthOf(1)
357 continue
358 }
359
360 expect(threads).to.have.lengthOf(2)
361 expect(threads[0].text).to.equal('uploader')
362 expect(threads[1].text).to.equal('comment user 2')
363
364 const resReplies = await getVideoThreadComments(server.url, videoUUID3, threads[0].id)
365
366 const tree: VideoCommentThreadTree = resReplies.body
367 expect(tree.children).to.have.lengthOf(1)
368 expect(tree.children[0].comment.text).to.equal('reply by user 2')
369 expect(tree.children[0].children).to.have.lengthOf(1)
370 expect(tree.children[0].children[0].comment.text).to.equal('another reply')
371 }
372 })
373
286 it('Should unblock the local account', async function () { 374 it('Should unblock the local account', async function () {
287 await removeAccountFromAccountBlocklist(servers[0].url, servers[0].accessToken, 'user1') 375 await removeAccountFromAccountBlocklist(servers[0].url, servers[0].accessToken, 'user1')
288 }) 376 })
@@ -328,7 +416,7 @@ describe('Test blocklist', function () {
328 const res = await getVideosListWithToken(servers[0].url, servers[0].accessToken) 416 const res = await getVideosListWithToken(servers[0].url, servers[0].accessToken)
329 417
330 const videos: Video[] = res.body.data 418 const videos: Video[] = res.body.data
331 expect(videos).to.have.lengthOf(2) 419 expect(videos).to.have.lengthOf(3)
332 420
333 const v1 = videos.find(v => v.name === 'video user 2') 421 const v1 = videos.find(v => v.name === 'video user 2')
334 const v2 = videos.find(v => v.name === 'video server 2') 422 const v2 = videos.find(v => v.name === 'video server 2')
@@ -442,7 +530,7 @@ describe('Test blocklist', function () {
442 const res = await getVideosListWithToken(servers[0].url, token) 530 const res = await getVideosListWithToken(servers[0].url, token)
443 531
444 const videos: Video[] = res.body.data 532 const videos: Video[] = res.body.data
445 expect(videos).to.have.lengthOf(3) 533 expect(videos).to.have.lengthOf(4)
446 534
447 const v = videos.find(v => v.name === 'video user 2') 535 const v = videos.find(v => v.name === 'video user 2')
448 expect(v).to.be.undefined 536 expect(v).to.be.undefined
@@ -458,7 +546,7 @@ describe('Test blocklist', function () {
458 const res = await getVideosListWithToken(servers[0].url, token) 546 const res = await getVideosListWithToken(servers[0].url, token)
459 547
460 const videos: Video[] = res.body.data 548 const videos: Video[] = res.body.data
461 expect(videos).to.have.lengthOf(2) 549 expect(videos).to.have.lengthOf(3)
462 550
463 const v = videos.find(v => v.name === 'video user 1') 551 const v = videos.find(v => v.name === 'video user 1')
464 expect(v).to.be.undefined 552 expect(v).to.be.undefined
@@ -467,9 +555,11 @@ describe('Test blocklist', function () {
467 555
468 it('Should hide its comments', async function () { 556 it('Should hide its comments', async function () {
469 for (const token of [ userModeratorToken, servers[0].accessToken ]) { 557 for (const token of [ userModeratorToken, servers[0].accessToken ]) {
470 const resThreads = await getVideoCommentThreads(servers[0].url, videoUUID1, 0, 5, '-createdAt', token) 558 const resThreads = await getVideoCommentThreads(servers[0].url, videoUUID1, 0, 20, '-createdAt', token)
559
560 let threads: VideoComment[] = resThreads.body.data
561 threads = threads.filter(t => t.isDeleted === false)
471 562
472 const threads: VideoComment[] = resThreads.body.data
473 expect(threads).to.have.lengthOf(1) 563 expect(threads).to.have.lengthOf(1)
474 expect(threads[0].totalReplies).to.equal(0) 564 expect(threads[0].totalReplies).to.equal(0)
475 565
@@ -543,7 +633,7 @@ describe('Test blocklist', function () {
543 const res = await getVideosListWithToken(servers[0].url, token) 633 const res = await getVideosListWithToken(servers[0].url, token)
544 634
545 const videos: Video[] = res.body.data 635 const videos: Video[] = res.body.data
546 expect(videos).to.have.lengthOf(3) 636 expect(videos).to.have.lengthOf(4)
547 637
548 const v = videos.find(v => v.name === 'video user 2') 638 const v = videos.find(v => v.name === 'video user 2')
549 expect(v).not.to.be.undefined 639 expect(v).not.to.be.undefined
@@ -604,7 +694,7 @@ describe('Test blocklist', function () {
604 694
605 for (const res of [ res1, res2 ]) { 695 for (const res of [ res1, res2 ]) {
606 const videos: Video[] = res.body.data 696 const videos: Video[] = res.body.data
607 expect(videos).to.have.lengthOf(2) 697 expect(videos).to.have.lengthOf(3)
608 698
609 const v1 = videos.find(v => v.name === 'video user 2') 699 const v1 = videos.find(v => v.name === 'video user 2')
610 const v2 = videos.find(v => v.name === 'video server 2') 700 const v2 = videos.find(v => v.name === 'video server 2')
@@ -629,7 +719,7 @@ describe('Test blocklist', function () {
629 }) 719 })
630 720
631 it('Should not have notification from blocked instances by instance', async function () { 721 it('Should not have notification from blocked instances by instance', async function () {
632 this.timeout(20000) 722 this.timeout(50000)
633 723
634 { 724 {
635 const comment = { server: servers[1], token: userToken2, videoUUID: videoUUID1, text: 'hidden comment' } 725 const comment = { server: servers[1], token: userToken2, videoUUID: videoUUID1, text: 'hidden comment' }
@@ -645,6 +735,24 @@ describe('Test blocklist', function () {
645 } 735 }
646 await checkCommentNotification(servers[0], comment, 'absence') 736 await checkCommentNotification(servers[0], comment, 'absence')
647 } 737 }
738
739 {
740 const now = new Date()
741 await unfollow(servers[1].url, servers[1].accessToken, servers[0])
742 await waitJobs(servers)
743 await follow(servers[1].url, [ servers[0].host ], servers[1].accessToken)
744
745 await waitJobs(servers)
746
747 const res = await getUserNotifications(servers[0].url, servers[0].accessToken, 0, 30)
748 const commentNotifications = (res.body.data as UserNotification[])
749 .filter(n => {
750 return n.type === UserNotificationType.NEW_INSTANCE_FOLLOWER &&
751 n.createdAt >= now.toISOString()
752 })
753
754 expect(commentNotifications).to.have.lengthOf(0)
755 }
648 }) 756 })
649 757
650 it('Should list blocked servers', async function () { 758 it('Should list blocked servers', async function () {
@@ -676,7 +784,7 @@ describe('Test blocklist', function () {
676 }) 784 })
677 785
678 it('Should have notification from unblocked instances', async function () { 786 it('Should have notification from unblocked instances', async function () {
679 this.timeout(20000) 787 this.timeout(50000)
680 788
681 { 789 {
682 const comment = { server: servers[1], token: userToken2, videoUUID: videoUUID1, text: 'displayed comment' } 790 const comment = { server: servers[1], token: userToken2, videoUUID: videoUUID1, text: 'displayed comment' }
@@ -692,6 +800,24 @@ describe('Test blocklist', function () {
692 } 800 }
693 await checkCommentNotification(servers[0], comment, 'presence') 801 await checkCommentNotification(servers[0], comment, 'presence')
694 } 802 }
803
804 {
805 const now = new Date()
806 await unfollow(servers[1].url, servers[1].accessToken, servers[0])
807 await waitJobs(servers)
808 await follow(servers[1].url, [ servers[0].host ], servers[1].accessToken)
809
810 await waitJobs(servers)
811
812 const res = await getUserNotifications(servers[0].url, servers[0].accessToken, 0, 30)
813 const commentNotifications = (res.body.data as UserNotification[])
814 .filter(n => {
815 return n.type === UserNotificationType.NEW_INSTANCE_FOLLOWER &&
816 n.createdAt >= now.toISOString()
817 })
818
819 expect(commentNotifications).to.have.lengthOf(1)
820 }
695 }) 821 })
696 }) 822 })
697 }) 823 })
diff --git a/server/tests/api/videos/multiple-servers.ts b/server/tests/api/videos/multiple-servers.ts
index e3029f1ae..d7b04373f 100644
--- a/server/tests/api/videos/multiple-servers.ts
+++ b/server/tests/api/videos/multiple-servers.ts
@@ -37,7 +37,8 @@ import {
37 addVideoCommentThread, 37 addVideoCommentThread,
38 deleteVideoComment, 38 deleteVideoComment,
39 getVideoCommentThreads, 39 getVideoCommentThreads,
40 getVideoThreadComments 40 getVideoThreadComments,
41 findCommentId
41} from '../../../../shared/extra-utils/videos/video-comments' 42} from '../../../../shared/extra-utils/videos/video-comments'
42import { waitJobs } from '../../../../shared/extra-utils/server/jobs' 43import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
43 44
@@ -773,8 +774,7 @@ describe('Test multiple servers', function () {
773 await waitJobs(servers) 774 await waitJobs(servers)
774 775
775 { 776 {
776 const res = await getVideoCommentThreads(servers[1].url, videoUUID, 0, 5) 777 const threadId = await findCommentId(servers[1].url, videoUUID, 'my super first comment')
777 const threadId = res.body.data.find(c => c.text === 'my super first comment').id
778 778
779 const text = 'my super answer to thread 1' 779 const text = 'my super answer to thread 1'
780 await addVideoCommentReply(servers[1].url, servers[1].accessToken, videoUUID, threadId, text) 780 await addVideoCommentReply(servers[1].url, servers[1].accessToken, videoUUID, threadId, text)
@@ -783,8 +783,7 @@ describe('Test multiple servers', function () {
783 await waitJobs(servers) 783 await waitJobs(servers)
784 784
785 { 785 {
786 const res1 = await getVideoCommentThreads(servers[2].url, videoUUID, 0, 5) 786 const threadId = await findCommentId(servers[2].url, videoUUID, 'my super first comment')
787 const threadId = res1.body.data.find(c => c.text === 'my super first comment').id
788 787
789 const res2 = await getVideoThreadComments(servers[2].url, videoUUID, threadId) 788 const res2 = await getVideoThreadComments(servers[2].url, videoUUID, threadId)
790 const childCommentId = res2.body.children[0].comment.id 789 const childCommentId = res2.body.children[0].comment.id