aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2021-07-07 09:16:40 +0200
committerChocobozzz <me@florianbigard.com>2021-07-20 15:27:17 +0200
commitc3d29f694bf8c910f917be655626d0f80871124f (patch)
treec90dfdc1245c8a9aca49e9ea9c71ed8e6b9dd35f
parent883a9019085ff9013079d6b1539b86f2f519175a (diff)
downloadPeerTube-c3d29f694bf8c910f917be655626d0f80871124f.tar.gz
PeerTube-c3d29f694bf8c910f917be655626d0f80871124f.tar.zst
PeerTube-c3d29f694bf8c910f917be655626d0f80871124f.zip
Introduce follows command
-rw-r--r--server/tests/api/moderation/blocklist.ts10
-rw-r--r--server/tests/api/notifications/moderation-notifications.ts16
-rw-r--r--server/tests/api/redundancy/redundancy-constraints.ts5
-rw-r--r--server/tests/api/redundancy/redundancy.ts24
-rw-r--r--server/tests/api/server/auto-follows.ts48
-rw-r--r--server/tests/api/server/follow-constraints.ts15
-rw-r--r--server/tests/api/server/follows-moderation.ts92
-rw-r--r--server/tests/api/server/follows.ts144
-rw-r--r--server/tests/api/server/handle-down.ts50
-rw-r--r--server/tests/api/server/jobs.ts4
-rw-r--r--server/tests/api/server/stats.ts22
-rw-r--r--server/tests/api/users/user-subscriptions.ts33
-rw-r--r--server/tests/api/users/users.ts8
-rw-r--r--server/tests/api/videos/video-description.ts2
-rw-r--r--server/tests/api/videos/video-playlists.ts41
-rw-r--r--shared/extra-utils/index.ts5
-rw-r--r--shared/extra-utils/server/follows-command.ts124
-rw-r--r--shared/extra-utils/server/follows.ts131
-rw-r--r--shared/extra-utils/server/index.ts2
-rw-r--r--shared/extra-utils/server/servers.ts3
20 files changed, 368 insertions, 411 deletions
diff --git a/server/tests/api/moderation/blocklist.ts b/server/tests/api/moderation/blocklist.ts
index 793abbcb4..9ca6324c2 100644
--- a/server/tests/api/moderation/blocklist.ts
+++ b/server/tests/api/moderation/blocklist.ts
@@ -15,7 +15,6 @@ import {
15 doubleFollow, 15 doubleFollow,
16 findCommentId, 16 findCommentId,
17 flushAndRunMultipleServers, 17 flushAndRunMultipleServers,
18 follow,
19 getAccountBlocklistByAccount, 18 getAccountBlocklistByAccount,
20 getAccountBlocklistByServer, 19 getAccountBlocklistByServer,
21 getServerBlocklistByAccount, 20 getServerBlocklistByAccount,
@@ -31,7 +30,6 @@ import {
31 removeServerFromServerBlocklist, 30 removeServerFromServerBlocklist,
32 ServerInfo, 31 ServerInfo,
33 setAccessTokensToServers, 32 setAccessTokensToServers,
34 unfollow,
35 uploadVideo, 33 uploadVideo,
36 userLogin, 34 userLogin,
37 waitJobs 35 waitJobs
@@ -742,9 +740,9 @@ describe('Test blocklist', function () {
742 740
743 { 741 {
744 const now = new Date() 742 const now = new Date()
745 await unfollow(servers[1].url, servers[1].accessToken, servers[0]) 743 await servers[1].followsCommand.unfollow({ target: servers[0] })
746 await waitJobs(servers) 744 await waitJobs(servers)
747 await follow(servers[1].url, [ servers[0].host ], servers[1].accessToken) 745 await servers[1].followsCommand.follow({ targets: [ servers[0].host ] })
748 746
749 await waitJobs(servers) 747 await waitJobs(servers)
750 748
@@ -807,9 +805,9 @@ describe('Test blocklist', function () {
807 805
808 { 806 {
809 const now = new Date() 807 const now = new Date()
810 await unfollow(servers[1].url, servers[1].accessToken, servers[0]) 808 await servers[1].followsCommand.unfollow({ target: servers[0] })
811 await waitJobs(servers) 809 await waitJobs(servers)
812 await follow(servers[1].url, [ servers[0].host ], servers[1].accessToken) 810 await servers[1].followsCommand.follow({ targets: [ servers[0].host ] })
813 811
814 await waitJobs(servers) 812 await waitJobs(servers)
815 813
diff --git a/server/tests/api/notifications/moderation-notifications.ts b/server/tests/api/notifications/moderation-notifications.ts
index c4f63200a..9a93ce401 100644
--- a/server/tests/api/notifications/moderation-notifications.ts
+++ b/server/tests/api/notifications/moderation-notifications.ts
@@ -21,7 +21,6 @@ import {
21 checkVideoIsPublished, 21 checkVideoIsPublished,
22 cleanupTests, 22 cleanupTests,
23 createUser, 23 createUser,
24 follow,
25 generateUserAccessToken, 24 generateUserAccessToken,
26 getAccount, 25 getAccount,
27 getCustomConfig, 26 getCustomConfig,
@@ -35,7 +34,6 @@ import {
35 removeUserSubscription, 34 removeUserSubscription,
36 removeVideoFromBlacklist, 35 removeVideoFromBlacklist,
37 ServerInfo, 36 ServerInfo,
38 unfollow,
39 updateCustomConfig, 37 updateCustomConfig,
40 updateCustomSubConfig, 38 updateCustomSubConfig,
41 uploadVideo, 39 uploadVideo,
@@ -386,7 +384,7 @@ describe('Test moderation notifications', function () {
386 it('Should send a notification only to admin when there is a new instance follower', async function () { 384 it('Should send a notification only to admin when there is a new instance follower', async function () {
387 this.timeout(20000) 385 this.timeout(20000)
388 386
389 await follow(servers[2].url, [ servers[0].url ], servers[2].accessToken) 387 await servers[2].followsCommand.follow({ targets: [ servers[0].url ] })
390 388
391 await waitJobs(servers) 389 await waitJobs(servers)
392 390
@@ -399,7 +397,7 @@ describe('Test moderation notifications', function () {
399 it('Should send a notification on auto follow back', async function () { 397 it('Should send a notification on auto follow back', async function () {
400 this.timeout(40000) 398 this.timeout(40000)
401 399
402 await unfollow(servers[2].url, servers[2].accessToken, servers[0]) 400 await servers[2].followsCommand.unfollow({ target: servers[0] })
403 await waitJobs(servers) 401 await waitJobs(servers)
404 402
405 const config = { 403 const config = {
@@ -411,7 +409,7 @@ describe('Test moderation notifications', function () {
411 } 409 }
412 await updateCustomSubConfig(servers[0].url, servers[0].accessToken, config) 410 await updateCustomSubConfig(servers[0].url, servers[0].accessToken, config)
413 411
414 await follow(servers[2].url, [ servers[0].url ], servers[2].accessToken) 412 await servers[2].followsCommand.follow({ targets: [ servers[0].url ] })
415 413
416 await waitJobs(servers) 414 await waitJobs(servers)
417 415
@@ -424,13 +422,13 @@ describe('Test moderation notifications', function () {
424 422
425 config.followings.instance.autoFollowBack.enabled = false 423 config.followings.instance.autoFollowBack.enabled = false
426 await updateCustomSubConfig(servers[0].url, servers[0].accessToken, config) 424 await updateCustomSubConfig(servers[0].url, servers[0].accessToken, config)
427 await unfollow(servers[0].url, servers[0].accessToken, servers[2]) 425 await servers[0].followsCommand.unfollow({ target: servers[2] })
428 await unfollow(servers[2].url, servers[2].accessToken, servers[0]) 426 await servers[2].followsCommand.unfollow({ target: servers[0] })
429 }) 427 })
430 428
431 it('Should send a notification on auto instances index follow', async function () { 429 it('Should send a notification on auto instances index follow', async function () {
432 this.timeout(30000) 430 this.timeout(30000)
433 await unfollow(servers[0].url, servers[0].accessToken, servers[1]) 431 await servers[0].followsCommand.unfollow({ target: servers[1] })
434 432
435 await updateCustomSubConfig(servers[0].url, servers[0].accessToken, config) 433 await updateCustomSubConfig(servers[0].url, servers[0].accessToken, config)
436 434
@@ -443,7 +441,7 @@ describe('Test moderation notifications', function () {
443 441
444 config.followings.instance.autoFollowIndex.enabled = false 442 config.followings.instance.autoFollowIndex.enabled = false
445 await updateCustomSubConfig(servers[0].url, servers[0].accessToken, config) 443 await updateCustomSubConfig(servers[0].url, servers[0].accessToken, config)
446 await unfollow(servers[0].url, servers[0].accessToken, servers[1]) 444 await servers[0].followsCommand.unfollow({ target: servers[1] })
447 }) 445 })
448 }) 446 })
449 447
diff --git a/server/tests/api/redundancy/redundancy-constraints.ts b/server/tests/api/redundancy/redundancy-constraints.ts
index 1cb1603bc..602f4bc1b 100644
--- a/server/tests/api/redundancy/redundancy-constraints.ts
+++ b/server/tests/api/redundancy/redundancy-constraints.ts
@@ -7,7 +7,6 @@ import { VideoPrivacy } from '@shared/models'
7import { 7import {
8 cleanupTests, 8 cleanupTests,
9 flushAndRunServer, 9 flushAndRunServer,
10 follow,
11 killallServers, 10 killallServers,
12 reRunServer, 11 reRunServer,
13 ServerInfo, 12 ServerInfo,
@@ -98,7 +97,7 @@ describe('Test redundancy constraints', function () {
98 await waitJobs(servers) 97 await waitJobs(servers)
99 98
100 // Server 1 and server 2 follow each other 99 // Server 1 and server 2 follow each other
101 await follow(remoteServer.url, [ localServer.url ], remoteServer.accessToken) 100 await remoteServer.followsCommand.follow({ targets: [ localServer.url ] })
102 await waitJobs(servers) 101 await waitJobs(servers)
103 await updateRedundancy(remoteServer.url, remoteServer.accessToken, localServer.host, true) 102 await updateRedundancy(remoteServer.url, remoteServer.accessToken, localServer.host, true)
104 103
@@ -184,7 +183,7 @@ describe('Test redundancy constraints', function () {
184 it('Should have redundancy on server 1 and on server 2 with followings filter now server 2 follows server 1', async function () { 183 it('Should have redundancy on server 1 and on server 2 with followings filter now server 2 follows server 1', async function () {
185 this.timeout(120000) 184 this.timeout(120000)
186 185
187 await follow(localServer.url, [ remoteServer.url ], localServer.accessToken) 186 await localServer.followsCommand.follow({ targets: [ remoteServer.url ] })
188 await waitJobs(servers) 187 await waitJobs(servers)
189 188
190 await uploadWrapper('video 4 server 2') 189 await uploadWrapper('video 4 server 2')
diff --git a/server/tests/api/redundancy/redundancy.ts b/server/tests/api/redundancy/redundancy.ts
index 0e0a73b9d..dfe8099ed 100644
--- a/server/tests/api/redundancy/redundancy.ts
+++ b/server/tests/api/redundancy/redundancy.ts
@@ -12,7 +12,6 @@ import {
12 cleanupTests, 12 cleanupTests,
13 doubleFollow, 13 doubleFollow,
14 flushAndRunMultipleServers, 14 flushAndRunMultipleServers,
15 getFollowingListPaginationAndSort,
16 getVideo, 15 getVideo,
17 getVideoWithToken, 16 getVideoWithToken,
18 immutableAssign, 17 immutableAssign,
@@ -23,7 +22,6 @@ import {
23 root, 22 root,
24 ServerInfo, 23 ServerInfo,
25 setAccessTokensToServers, 24 setAccessTokensToServers,
26 unfollow,
27 updateVideo, 25 updateVideo,
28 uploadVideo, 26 uploadVideo,
29 viewVideo, 27 viewVideo,
@@ -38,7 +36,6 @@ import {
38 updateRedundancy 36 updateRedundancy
39} from '../../../../shared/extra-utils/server/redundancy' 37} from '../../../../shared/extra-utils/server/redundancy'
40import { getStats } from '../../../../shared/extra-utils/server/stats' 38import { getStats } from '../../../../shared/extra-utils/server/stats'
41import { ActorFollow } from '../../../../shared/models/actors'
42import { VideoRedundancy, VideoRedundancyStrategy, VideoRedundancyStrategyWithManual } from '../../../../shared/models/redundancy' 39import { VideoRedundancy, VideoRedundancyStrategy, VideoRedundancyStrategyWithManual } from '../../../../shared/models/redundancy'
43import { ServerStats } from '../../../../shared/models/server/server-stats.model' 40import { ServerStats } from '../../../../shared/models/server/server-stats.model'
44import { VideoDetails, VideoPrivacy } from '../../../../shared/models/videos' 41import { VideoDetails, VideoPrivacy } from '../../../../shared/models/videos'
@@ -272,13 +269,19 @@ async function checkStatsWithoutRedundancy (strategy: VideoRedundancyStrategyWit
272 expect(stat.totalVideos).to.equal(0) 269 expect(stat.totalVideos).to.equal(0)
273} 270}
274 271
272async function findServerFollows () {
273 const body = await servers[0].followsCommand.getFollowings({ start: 0, count: 5, sort: '-createdAt' })
274 const follows = body.data
275 const server2 = follows.find(f => f.following.host === `localhost:${servers[1].port}`)
276 const server3 = follows.find(f => f.following.host === `localhost:${servers[2].port}`)
277
278 return { server2, server3 }
279}
280
275async function enableRedundancyOnServer1 () { 281async function enableRedundancyOnServer1 () {
276 await updateRedundancy(servers[0].url, servers[0].accessToken, servers[1].host, true) 282 await updateRedundancy(servers[0].url, servers[0].accessToken, servers[1].host, true)
277 283
278 const res = await getFollowingListPaginationAndSort({ url: servers[0].url, start: 0, count: 5, sort: '-createdAt' }) 284 const { server2, server3 } = await findServerFollows()
279 const follows: ActorFollow[] = res.body.data
280 const server2 = follows.find(f => f.following.host === `localhost:${servers[1].port}`)
281 const server3 = follows.find(f => f.following.host === `localhost:${servers[2].port}`)
282 285
283 expect(server3).to.not.be.undefined 286 expect(server3).to.not.be.undefined
284 expect(server3.following.hostRedundancyAllowed).to.be.false 287 expect(server3.following.hostRedundancyAllowed).to.be.false
@@ -290,10 +293,7 @@ async function enableRedundancyOnServer1 () {
290async function disableRedundancyOnServer1 () { 293async function disableRedundancyOnServer1 () {
291 await updateRedundancy(servers[0].url, servers[0].accessToken, servers[1].host, false) 294 await updateRedundancy(servers[0].url, servers[0].accessToken, servers[1].host, false)
292 295
293 const res = await getFollowingListPaginationAndSort({ url: servers[0].url, start: 0, count: 5, sort: '-createdAt' }) 296 const { server2, server3 } = await findServerFollows()
294 const follows: ActorFollow[] = res.body.data
295 const server2 = follows.find(f => f.following.host === `localhost:${servers[1].port}`)
296 const server3 = follows.find(f => f.following.host === `localhost:${servers[2].port}`)
297 297
298 expect(server3).to.not.be.undefined 298 expect(server3).to.not.be.undefined
299 expect(server3.following.hostRedundancyAllowed).to.be.false 299 expect(server3.following.hostRedundancyAllowed).to.be.false
@@ -388,7 +388,7 @@ describe('Test videos redundancy', function () {
388 it('Should unfollow on server 1 and remove duplicated videos', async function () { 388 it('Should unfollow on server 1 and remove duplicated videos', async function () {
389 this.timeout(80000) 389 this.timeout(80000)
390 390
391 await unfollow(servers[0].url, servers[0].accessToken, servers[1]) 391 await servers[0].followsCommand.unfollow({ target: servers[1] })
392 392
393 await waitJobs(servers) 393 await waitJobs(servers)
394 await wait(5000) 394 await wait(5000)
diff --git a/server/tests/api/server/auto-follows.ts b/server/tests/api/server/auto-follows.ts
index 1519b263f..02389b1e9 100644
--- a/server/tests/api/server/auto-follows.ts
+++ b/server/tests/api/server/auto-follows.ts
@@ -3,64 +3,46 @@
3import 'mocha' 3import 'mocha'
4import * as chai from 'chai' 4import * as chai from 'chai'
5import { 5import {
6 acceptFollower,
7 cleanupTests, 6 cleanupTests,
8 flushAndRunMultipleServers, 7 flushAndRunMultipleServers,
9 MockInstancesIndex, 8 MockInstancesIndex,
10 ServerInfo, 9 ServerInfo,
11 setAccessTokensToServers, 10 setAccessTokensToServers,
12 unfollow,
13 updateCustomSubConfig, 11 updateCustomSubConfig,
14 wait 12 wait,
15} from '../../../../shared/extra-utils/index' 13 waitJobs
16import { follow, getFollowersListPaginationAndSort, getFollowingListPaginationAndSort } from '../../../../shared/extra-utils/server/follows' 14} from '@shared/extra-utils'
17import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
18import { ActorFollow } from '../../../../shared/models/actors'
19 15
20const expect = chai.expect 16const expect = chai.expect
21 17
22async function checkFollow (follower: ServerInfo, following: ServerInfo, exists: boolean) { 18async function checkFollow (follower: ServerInfo, following: ServerInfo, exists: boolean) {
23 { 19 {
24 const res = await getFollowersListPaginationAndSort({ url: following.url, start: 0, count: 5, sort: '-createdAt' }) 20 const body = await following.followsCommand.getFollowers({ start: 0, count: 5, sort: '-createdAt' })
25 const follows = res.body.data as ActorFollow[] 21 const follow = body.data.find(f => f.follower.host === follower.host && f.state === 'accepted')
26 22
27 const follow = follows.find(f => { 23 if (exists === true) expect(follow).to.exist
28 return f.follower.host === follower.host && f.state === 'accepted' 24 else expect(follow).to.be.undefined
29 })
30
31 if (exists === true) {
32 expect(follow).to.exist
33 } else {
34 expect(follow).to.be.undefined
35 }
36 } 25 }
37 26
38 { 27 {
39 const res = await getFollowingListPaginationAndSort({ url: follower.url, start: 0, count: 5, sort: '-createdAt' }) 28 const body = await follower.followsCommand.getFollowings({ start: 0, count: 5, sort: '-createdAt' })
40 const follows = res.body.data as ActorFollow[] 29 const follow = body.data.find(f => f.following.host === following.host && f.state === 'accepted')
41
42 const follow = follows.find(f => {
43 return f.following.host === following.host && f.state === 'accepted'
44 })
45 30
46 if (exists === true) { 31 if (exists === true) expect(follow).to.exist
47 expect(follow).to.exist 32 else expect(follow).to.be.undefined
48 } else {
49 expect(follow).to.be.undefined
50 }
51 } 33 }
52} 34}
53 35
54async function server1Follows2 (servers: ServerInfo[]) { 36async function server1Follows2 (servers: ServerInfo[]) {
55 await follow(servers[0].url, [ servers[1].host ], servers[0].accessToken) 37 await servers[0].followsCommand.follow({ targets: [ servers[1].host ] })
56 38
57 await waitJobs(servers) 39 await waitJobs(servers)
58} 40}
59 41
60async function resetFollows (servers: ServerInfo[]) { 42async function resetFollows (servers: ServerInfo[]) {
61 try { 43 try {
62 await unfollow(servers[0].url, servers[0].accessToken, servers[1]) 44 await servers[0].followsCommand.unfollow({ target: servers[1] })
63 await unfollow(servers[1].url, servers[1].accessToken, servers[0]) 45 await servers[1].followsCommand.unfollow({ target: servers[0] })
64 } catch { /* empty */ 46 } catch { /* empty */
65 } 47 }
66 48
@@ -137,7 +119,7 @@ describe('Test auto follows', function () {
137 await checkFollow(servers[0], servers[1], false) 119 await checkFollow(servers[0], servers[1], false)
138 await checkFollow(servers[1], servers[0], false) 120 await checkFollow(servers[1], servers[0], false)
139 121
140 await acceptFollower(servers[1].url, servers[1].accessToken, 'peertube@' + servers[0].host) 122 await servers[1].followsCommand.acceptFollower({ follower: 'peertube@' + servers[0].host })
141 await waitJobs(servers) 123 await waitJobs(servers)
142 124
143 await checkFollow(servers[0], servers[1], true) 125 await checkFollow(servers[0], servers[1], true)
diff --git a/server/tests/api/server/follow-constraints.ts b/server/tests/api/server/follow-constraints.ts
index 3f2f71f46..0f1c6264d 100644
--- a/server/tests/api/server/follow-constraints.ts
+++ b/server/tests/api/server/follow-constraints.ts
@@ -1,9 +1,12 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai'
4import 'mocha' 3import 'mocha'
4import * as chai from 'chai'
5import { HttpStatusCode } from '@shared/core-utils'
6import { PeerTubeProblemDocument, ServerErrorCode } from '@shared/models'
5import { 7import {
6 cleanupTests, 8 cleanupTests,
9 createUser,
7 doubleFollow, 10 doubleFollow,
8 flushAndRunMultipleServers, 11 flushAndRunMultipleServers,
9 getAccountVideos, 12 getAccountVideos,
@@ -12,13 +15,9 @@ import {
12 getVideoWithToken, 15 getVideoWithToken,
13 ServerInfo, 16 ServerInfo,
14 setAccessTokensToServers, 17 setAccessTokensToServers,
15 uploadVideo 18 uploadVideo,
19 userLogin
16} from '../../../../shared/extra-utils' 20} from '../../../../shared/extra-utils'
17import { unfollow } from '../../../../shared/extra-utils/server/follows'
18import { userLogin } from '../../../../shared/extra-utils/users/login'
19import { createUser } from '../../../../shared/extra-utils/users/users'
20import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
21import { PeerTubeProblemDocument, ServerErrorCode } from '@shared/models'
22 21
23const expect = chai.expect 22const expect = chai.expect
24 23
@@ -144,7 +143,7 @@ describe('Test follow constraints', function () {
144 before(async function () { 143 before(async function () {
145 this.timeout(30000) 144 this.timeout(30000)
146 145
147 await unfollow(servers[0].url, servers[0].accessToken, servers[1]) 146 await servers[0].followsCommand.unfollow({ target: servers[1] })
148 }) 147 })
149 148
150 describe('With an unlogged user', function () { 149 describe('With an unlogged user', function () {
diff --git a/server/tests/api/server/follows-moderation.ts b/server/tests/api/server/follows-moderation.ts
index 73c212a32..4853b647d 100644
--- a/server/tests/api/server/follows-moderation.ts
+++ b/server/tests/api/server/follows-moderation.ts
@@ -1,43 +1,30 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai'
4import 'mocha' 3import 'mocha'
4import * as chai from 'chai'
5import { 5import {
6 acceptFollower,
7 cleanupTests, 6 cleanupTests,
8 flushAndRunMultipleServers, 7 flushAndRunMultipleServers,
8 FollowsCommand,
9 ServerInfo, 9 ServerInfo,
10 setAccessTokensToServers, 10 setAccessTokensToServers,
11 updateCustomSubConfig 11 updateCustomSubConfig,
12} from '../../../../shared/extra-utils/index' 12 waitJobs
13import { 13} from '@shared/extra-utils'
14 follow,
15 getFollowersListPaginationAndSort,
16 getFollowingListPaginationAndSort,
17 rejectFollower,
18 removeFollower
19} from '../../../../shared/extra-utils/server/follows'
20import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
21import { ActorFollow } from '../../../../shared/models/actors'
22 14
23const expect = chai.expect 15const expect = chai.expect
24 16
25async function checkServer1And2HasFollowers (servers: ServerInfo[], state = 'accepted') { 17async function checkServer1And2HasFollowers (servers: ServerInfo[], state = 'accepted') {
26 { 18 const fns = [
27 const res = await getFollowingListPaginationAndSort({ url: servers[0].url, start: 0, count: 5, sort: 'createdAt' }) 19 servers[0].followsCommand.getFollowings.bind(servers[0].followsCommand),
28 expect(res.body.total).to.equal(1) 20 servers[1].followsCommand.getFollowers.bind(servers[1].followsCommand)
21 ]
29 22
30 const follow = res.body.data[0] as ActorFollow 23 for (const fn of fns) {
31 expect(follow.state).to.equal(state) 24 const body = await fn({ start: 0, count: 5, sort: 'createdAt' })
32 expect(follow.follower.url).to.equal('http://localhost:' + servers[0].port + '/accounts/peertube') 25 expect(body.total).to.equal(1)
33 expect(follow.following.url).to.equal('http://localhost:' + servers[1].port + '/accounts/peertube')
34 }
35
36 {
37 const res = await getFollowersListPaginationAndSort({ url: servers[1].url, start: 0, count: 5, sort: 'createdAt' })
38 expect(res.body.total).to.equal(1)
39 26
40 const follow = res.body.data[0] as ActorFollow 27 const follow = body.data[0]
41 expect(follow.state).to.equal(state) 28 expect(follow.state).to.equal(state)
42 expect(follow.follower.url).to.equal('http://localhost:' + servers[0].port + '/accounts/peertube') 29 expect(follow.follower.url).to.equal('http://localhost:' + servers[0].port + '/accounts/peertube')
43 expect(follow.following.url).to.equal('http://localhost:' + servers[1].port + '/accounts/peertube') 30 expect(follow.following.url).to.equal('http://localhost:' + servers[1].port + '/accounts/peertube')
@@ -45,19 +32,20 @@ async function checkServer1And2HasFollowers (servers: ServerInfo[], state = 'acc
45} 32}
46 33
47async function checkNoFollowers (servers: ServerInfo[]) { 34async function checkNoFollowers (servers: ServerInfo[]) {
48 { 35 const fns = [
49 const res = await getFollowingListPaginationAndSort({ url: servers[0].url, start: 0, count: 5, sort: 'createdAt' }) 36 servers[0].followsCommand.getFollowings.bind(servers[0].followsCommand),
50 expect(res.body.total).to.equal(0) 37 servers[1].followsCommand.getFollowers.bind(servers[1].followsCommand)
51 } 38 ]
52 39
53 { 40 for (const fn of fns) {
54 const res = await getFollowersListPaginationAndSort({ url: servers[1].url, start: 0, count: 5, sort: 'createdAt' }) 41 const body = await fn({ start: 0, count: 5, sort: 'createdAt' })
55 expect(res.body.total).to.equal(0) 42 expect(body.total).to.equal(0)
56 } 43 }
57} 44}
58 45
59describe('Test follows moderation', function () { 46describe('Test follows moderation', function () {
60 let servers: ServerInfo[] = [] 47 let servers: ServerInfo[] = []
48 let commands: FollowsCommand[]
61 49
62 before(async function () { 50 before(async function () {
63 this.timeout(30000) 51 this.timeout(30000)
@@ -66,12 +54,14 @@ describe('Test follows moderation', function () {
66 54
67 // Get the access tokens 55 // Get the access tokens
68 await setAccessTokensToServers(servers) 56 await setAccessTokensToServers(servers)
57
58 commands = servers.map(s => s.followsCommand)
69 }) 59 })
70 60
71 it('Should have server 1 following server 2', async function () { 61 it('Should have server 1 following server 2', async function () {
72 this.timeout(30000) 62 this.timeout(30000)
73 63
74 await follow(servers[0].url, [ servers[1].url ], servers[0].accessToken) 64 await commands[0].follow({ targets: [ servers[1].url ] })
75 65
76 await waitJobs(servers) 66 await waitJobs(servers)
77 }) 67 })
@@ -83,7 +73,7 @@ describe('Test follows moderation', function () {
83 it('Should remove follower on server 2', async function () { 73 it('Should remove follower on server 2', async function () {
84 this.timeout(10000) 74 this.timeout(10000)
85 75
86 await removeFollower(servers[1].url, servers[1].accessToken, servers[0]) 76 await commands[1].removeFollower({ follower: servers[0] })
87 77
88 await waitJobs(servers) 78 await waitJobs(servers)
89 }) 79 })
@@ -106,7 +96,7 @@ describe('Test follows moderation', function () {
106 96
107 await updateCustomSubConfig(servers[1].url, servers[1].accessToken, subConfig) 97 await updateCustomSubConfig(servers[1].url, servers[1].accessToken, subConfig)
108 98
109 await follow(servers[0].url, [ servers[1].url ], servers[0].accessToken) 99 await commands[0].follow({ targets: [ servers[1].url ] })
110 await waitJobs(servers) 100 await waitJobs(servers)
111 101
112 await checkNoFollowers(servers) 102 await checkNoFollowers(servers)
@@ -126,7 +116,7 @@ describe('Test follows moderation', function () {
126 116
127 await updateCustomSubConfig(servers[1].url, servers[1].accessToken, subConfig) 117 await updateCustomSubConfig(servers[1].url, servers[1].accessToken, subConfig)
128 118
129 await follow(servers[0].url, [ servers[1].url ], servers[0].accessToken) 119 await commands[0].follow({ targets: [ servers[1].url ] })
130 await waitJobs(servers) 120 await waitJobs(servers)
131 121
132 await checkServer1And2HasFollowers(servers) 122 await checkServer1And2HasFollowers(servers)
@@ -135,7 +125,7 @@ describe('Test follows moderation', function () {
135 it('Should manually approve followers', async function () { 125 it('Should manually approve followers', async function () {
136 this.timeout(20000) 126 this.timeout(20000)
137 127
138 await removeFollower(servers[1].url, servers[1].accessToken, servers[0]) 128 await commands[1].removeFollower({ follower: servers[0] })
139 await waitJobs(servers) 129 await waitJobs(servers)
140 130
141 const subConfig = { 131 const subConfig = {
@@ -150,7 +140,7 @@ describe('Test follows moderation', function () {
150 await updateCustomSubConfig(servers[1].url, servers[1].accessToken, subConfig) 140 await updateCustomSubConfig(servers[1].url, servers[1].accessToken, subConfig)
151 await updateCustomSubConfig(servers[2].url, servers[2].accessToken, subConfig) 141 await updateCustomSubConfig(servers[2].url, servers[2].accessToken, subConfig)
152 142
153 await follow(servers[0].url, [ servers[1].url ], servers[0].accessToken) 143 await commands[0].follow({ targets: [ servers[1].url ] })
154 await waitJobs(servers) 144 await waitJobs(servers)
155 145
156 await checkServer1And2HasFollowers(servers, 'pending') 146 await checkServer1And2HasFollowers(servers, 'pending')
@@ -159,7 +149,7 @@ describe('Test follows moderation', function () {
159 it('Should accept a follower', async function () { 149 it('Should accept a follower', async function () {
160 this.timeout(10000) 150 this.timeout(10000)
161 151
162 await acceptFollower(servers[1].url, servers[1].accessToken, 'peertube@localhost:' + servers[0].port) 152 await commands[1].acceptFollower({ follower: 'peertube@localhost:' + servers[0].port })
163 await waitJobs(servers) 153 await waitJobs(servers)
164 154
165 await checkServer1And2HasFollowers(servers) 155 await checkServer1And2HasFollowers(servers)
@@ -168,32 +158,32 @@ describe('Test follows moderation', function () {
168 it('Should reject another follower', async function () { 158 it('Should reject another follower', async function () {
169 this.timeout(20000) 159 this.timeout(20000)
170 160
171 await follow(servers[0].url, [ servers[2].url ], servers[0].accessToken) 161 await commands[0].follow({ targets: [ servers[2].url ] })
172 await waitJobs(servers) 162 await waitJobs(servers)
173 163
174 { 164 {
175 const res = await getFollowingListPaginationAndSort({ url: servers[0].url, start: 0, count: 5, sort: 'createdAt' }) 165 const body = await commands[0].getFollowings({ start: 0, count: 5, sort: 'createdAt' })
176 expect(res.body.total).to.equal(2) 166 expect(body.total).to.equal(2)
177 } 167 }
178 168
179 { 169 {
180 const res = await getFollowersListPaginationAndSort({ url: servers[1].url, start: 0, count: 5, sort: 'createdAt' }) 170 const body = await commands[1].getFollowers({ start: 0, count: 5, sort: 'createdAt' })
181 expect(res.body.total).to.equal(1) 171 expect(body.total).to.equal(1)
182 } 172 }
183 173
184 { 174 {
185 const res = await getFollowersListPaginationAndSort({ url: servers[2].url, start: 0, count: 5, sort: 'createdAt' }) 175 const body = await commands[2].getFollowers({ start: 0, count: 5, sort: 'createdAt' })
186 expect(res.body.total).to.equal(1) 176 expect(body.total).to.equal(1)
187 } 177 }
188 178
189 await rejectFollower(servers[2].url, servers[2].accessToken, 'peertube@localhost:' + servers[0].port) 179 await commands[2].rejectFollower({ follower: 'peertube@localhost:' + servers[0].port })
190 await waitJobs(servers) 180 await waitJobs(servers)
191 181
192 await checkServer1And2HasFollowers(servers) 182 await checkServer1And2HasFollowers(servers)
193 183
194 { 184 {
195 const res = await getFollowersListPaginationAndSort({ url: servers[2].url, start: 0, count: 5, sort: 'createdAt' }) 185 const body = await commands[2].getFollowers({ start: 0, count: 5, sort: 'createdAt' })
196 expect(res.body.total).to.equal(0) 186 expect(body.total).to.equal(0)
197 } 187 }
198 }) 188 })
199 189
diff --git a/server/tests/api/server/follows.ts b/server/tests/api/server/follows.ts
index 9e5aa00c7..c8fcca02c 100644
--- a/server/tests/api/server/follows.ts
+++ b/server/tests/api/server/follows.ts
@@ -13,9 +13,7 @@ import {
13 deleteVideoComment, 13 deleteVideoComment,
14 expectAccountFollows, 14 expectAccountFollows,
15 flushAndRunMultipleServers, 15 flushAndRunMultipleServers,
16 follow, 16 FollowsCommand,
17 getFollowersListPaginationAndSort,
18 getFollowingListPaginationAndSort,
19 getVideoCommentThreads, 17 getVideoCommentThreads,
20 getVideosList, 18 getVideosList,
21 getVideoThreadComments, 19 getVideoThreadComments,
@@ -24,7 +22,6 @@ import {
24 ServerInfo, 22 ServerInfo,
25 setAccessTokensToServers, 23 setAccessTokensToServers,
26 testCaptionFile, 24 testCaptionFile,
27 unfollow,
28 uploadVideo, 25 uploadVideo,
29 userLogin, 26 userLogin,
30 waitJobs 27 waitJobs
@@ -35,11 +32,13 @@ const expect = chai.expect
35 32
36describe('Test follows', function () { 33describe('Test follows', function () {
37 let servers: ServerInfo[] = [] 34 let servers: ServerInfo[] = []
35 let followsCommands: FollowsCommand[]
38 36
39 before(async function () { 37 before(async function () {
40 this.timeout(30000) 38 this.timeout(30000)
41 39
42 servers = await flushAndRunMultipleServers(3) 40 servers = await flushAndRunMultipleServers(3)
41 followsCommands = servers.map(s => s.followsCommand)
43 42
44 // Get the access tokens 43 // Get the access tokens
45 await setAccessTokensToServers(servers) 44 await setAccessTokensToServers(servers)
@@ -47,10 +46,10 @@ describe('Test follows', function () {
47 46
48 it('Should not have followers', async function () { 47 it('Should not have followers', async function () {
49 for (const server of servers) { 48 for (const server of servers) {
50 const res = await getFollowersListPaginationAndSort({ url: server.url, start: 0, count: 5, sort: 'createdAt' }) 49 const body = await server.followsCommand.getFollowers({ start: 0, count: 5, sort: 'createdAt' })
51 const follows = res.body.data 50 expect(body.total).to.equal(0)
52 51
53 expect(res.body.total).to.equal(0) 52 const follows = body.data
54 expect(follows).to.be.an('array') 53 expect(follows).to.be.an('array')
55 expect(follows.length).to.equal(0) 54 expect(follows.length).to.equal(0)
56 } 55 }
@@ -58,10 +57,10 @@ describe('Test follows', function () {
58 57
59 it('Should not have following', async function () { 58 it('Should not have following', async function () {
60 for (const server of servers) { 59 for (const server of servers) {
61 const res = await getFollowingListPaginationAndSort({ url: server.url, start: 0, count: 5, sort: 'createdAt' }) 60 const body = await server.followsCommand.getFollowings({ start: 0, count: 5, sort: 'createdAt' })
62 const follows = res.body.data 61 expect(body.total).to.equal(0)
63 62
64 expect(res.body.total).to.equal(0) 63 const follows = body.data
65 expect(follows).to.be.an('array') 64 expect(follows).to.be.an('array')
66 expect(follows.length).to.equal(0) 65 expect(follows.length).to.equal(0)
67 } 66 }
@@ -70,21 +69,21 @@ describe('Test follows', function () {
70 it('Should have server 1 following server 2 and 3', async function () { 69 it('Should have server 1 following server 2 and 3', async function () {
71 this.timeout(30000) 70 this.timeout(30000)
72 71
73 await follow(servers[0].url, [ servers[1].url, servers[2].url ], servers[0].accessToken) 72 await followsCommands[0].follow({ targets: [ servers[1].url, servers[2].url ] })
74 73
75 await waitJobs(servers) 74 await waitJobs(servers)
76 }) 75 })
77 76
78 it('Should have 2 followings on server 1', async function () { 77 it('Should have 2 followings on server 1', async function () {
79 let res = await getFollowingListPaginationAndSort({ url: servers[0].url, start: 0, count: 1, sort: 'createdAt' }) 78 const body = await followsCommands[0].getFollowings({ start: 0, count: 1, sort: 'createdAt' })
80 let follows = res.body.data 79 expect(body.total).to.equal(2)
81 80
82 expect(res.body.total).to.equal(2) 81 let follows = body.data
83 expect(follows).to.be.an('array') 82 expect(follows).to.be.an('array')
84 expect(follows.length).to.equal(1) 83 expect(follows.length).to.equal(1)
85 84
86 res = await getFollowingListPaginationAndSort({ url: servers[0].url, start: 1, count: 1, sort: 'createdAt' }) 85 const body2 = await followsCommands[0].getFollowings({ start: 1, count: 1, sort: 'createdAt' })
87 follows = follows.concat(res.body.data) 86 follows = follows.concat(body2.data)
88 87
89 const server2Follow = follows.find(f => f.following.host === 'localhost:' + servers[1].port) 88 const server2Follow = follows.find(f => f.following.host === 'localhost:' + servers[1].port)
90 const server3Follow = follows.find(f => f.following.host === 'localhost:' + servers[2].port) 89 const server3Follow = follows.find(f => f.following.host === 'localhost:' + servers[2].port)
@@ -99,35 +98,33 @@ describe('Test follows', function () {
99 const sort = 'createdAt' 98 const sort = 'createdAt'
100 const start = 0 99 const start = 0
101 const count = 1 100 const count = 1
102 const url = servers[0].url
103 101
104 { 102 {
105 const search = ':' + servers[1].port 103 const search = ':' + servers[1].port
106 104
107 { 105 {
108 const res = await getFollowingListPaginationAndSort({ url, start, count, sort, search }) 106 const body = await followsCommands[0].getFollowings({ start, count, sort, search })
109 const follows = res.body.data 107 expect(body.total).to.equal(1)
110 108
111 expect(res.body.total).to.equal(1) 109 const follows = body.data
112 expect(follows.length).to.equal(1) 110 expect(follows.length).to.equal(1)
113 expect(follows[0].following.host).to.equal('localhost:' + servers[1].port) 111 expect(follows[0].following.host).to.equal('localhost:' + servers[1].port)
114 } 112 }
115 113
116 { 114 {
117 const res = await getFollowingListPaginationAndSort({ url, start, count, sort, search, state: 'accepted' }) 115 const body = await followsCommands[0].getFollowings({ start, count, sort, search, state: 'accepted' })
118 expect(res.body.total).to.equal(1) 116 expect(body.total).to.equal(1)
119 expect(res.body.data).to.have.lengthOf(1) 117 expect(body.data).to.have.lengthOf(1)
120 } 118 }
121 119
122 { 120 {
123 const res = await getFollowingListPaginationAndSort({ url, start, count, sort, search, state: 'accepted', actorType: 'Person' }) 121 const body = await followsCommands[0].getFollowings({ start, count, sort, search, state: 'accepted', actorType: 'Person' })
124 expect(res.body.total).to.equal(0) 122 expect(body.total).to.equal(0)
125 expect(res.body.data).to.have.lengthOf(0) 123 expect(body.data).to.have.lengthOf(0)
126 } 124 }
127 125
128 { 126 {
129 const res = await getFollowingListPaginationAndSort({ 127 const body = await followsCommands[0].getFollowings({
130 url,
131 start, 128 start,
132 count, 129 count,
133 sort, 130 sort,
@@ -135,32 +132,31 @@ describe('Test follows', function () {
135 state: 'accepted', 132 state: 'accepted',
136 actorType: 'Application' 133 actorType: 'Application'
137 }) 134 })
138 expect(res.body.total).to.equal(1) 135 expect(body.total).to.equal(1)
139 expect(res.body.data).to.have.lengthOf(1) 136 expect(body.data).to.have.lengthOf(1)
140 } 137 }
141 138
142 { 139 {
143 const res = await getFollowingListPaginationAndSort({ url, start, count, sort, search, state: 'pending' }) 140 const body = await followsCommands[0].getFollowings({ start, count, sort, search, state: 'pending' })
144 expect(res.body.total).to.equal(0) 141 expect(body.total).to.equal(0)
145 expect(res.body.data).to.have.lengthOf(0) 142 expect(body.data).to.have.lengthOf(0)
146 } 143 }
147 } 144 }
148 145
149 { 146 {
150 const res = await getFollowingListPaginationAndSort({ url, start, count, sort, search: 'bla' }) 147 const body = await followsCommands[0].getFollowings({ start, count, sort, search: 'bla' })
151 const follows = res.body.data 148 expect(body.total).to.equal(0)
152 149
153 expect(res.body.total).to.equal(0) 150 expect(body.data.length).to.equal(0)
154 expect(follows.length).to.equal(0)
155 } 151 }
156 }) 152 })
157 153
158 it('Should have 0 followings on server 2 and 3', async function () { 154 it('Should have 0 followings on server 2 and 3', async function () {
159 for (const server of [ servers[1], servers[2] ]) { 155 for (const server of [ servers[1], servers[2] ]) {
160 const res = await getFollowingListPaginationAndSort({ url: server.url, start: 0, count: 5, sort: 'createdAt' }) 156 const body = await server.followsCommand.getFollowings({ start: 0, count: 5, sort: 'createdAt' })
161 const follows = res.body.data 157 expect(body.total).to.equal(0)
162 158
163 expect(res.body.total).to.equal(0) 159 const follows = body.data
164 expect(follows).to.be.an('array') 160 expect(follows).to.be.an('array')
165 expect(follows.length).to.equal(0) 161 expect(follows.length).to.equal(0)
166 } 162 }
@@ -168,10 +164,10 @@ describe('Test follows', function () {
168 164
169 it('Should have 1 followers on server 2 and 3', async function () { 165 it('Should have 1 followers on server 2 and 3', async function () {
170 for (const server of [ servers[1], servers[2] ]) { 166 for (const server of [ servers[1], servers[2] ]) {
171 const res = await getFollowersListPaginationAndSort({ url: server.url, start: 0, count: 1, sort: 'createdAt' }) 167 const body = await server.followsCommand.getFollowers({ start: 0, count: 1, sort: 'createdAt' })
168 expect(body.total).to.equal(1)
172 169
173 const follows = res.body.data 170 const follows = body.data
174 expect(res.body.total).to.equal(1)
175 expect(follows).to.be.an('array') 171 expect(follows).to.be.an('array')
176 expect(follows.length).to.equal(1) 172 expect(follows.length).to.equal(1)
177 expect(follows[0].follower.host).to.equal('localhost:' + servers[0].port) 173 expect(follows[0].follower.host).to.equal('localhost:' + servers[0].port)
@@ -179,7 +175,6 @@ describe('Test follows', function () {
179 }) 175 })
180 176
181 it('Should search/filter followers on server 2', async function () { 177 it('Should search/filter followers on server 2', async function () {
182 const url = servers[2].url
183 const start = 0 178 const start = 0
184 const count = 5 179 const count = 5
185 const sort = 'createdAt' 180 const sort = 'createdAt'
@@ -188,29 +183,28 @@ describe('Test follows', function () {
188 const search = servers[0].port + '' 183 const search = servers[0].port + ''
189 184
190 { 185 {
191 const res = await getFollowersListPaginationAndSort({ url, start, count, sort, search }) 186 const body = await followsCommands[2].getFollowers({ start, count, sort, search })
192 const follows = res.body.data 187 expect(body.total).to.equal(1)
193 188
194 expect(res.body.total).to.equal(1) 189 const follows = body.data
195 expect(follows.length).to.equal(1) 190 expect(follows.length).to.equal(1)
196 expect(follows[0].following.host).to.equal('localhost:' + servers[2].port) 191 expect(follows[0].following.host).to.equal('localhost:' + servers[2].port)
197 } 192 }
198 193
199 { 194 {
200 const res = await getFollowersListPaginationAndSort({ url, start, count, sort, search, state: 'accepted' }) 195 const body = await followsCommands[2].getFollowers({ start, count, sort, search, state: 'accepted' })
201 expect(res.body.total).to.equal(1) 196 expect(body.total).to.equal(1)
202 expect(res.body.data).to.have.lengthOf(1) 197 expect(body.data).to.have.lengthOf(1)
203 } 198 }
204 199
205 { 200 {
206 const res = await getFollowersListPaginationAndSort({ url, start, count, sort, search, state: 'accepted', actorType: 'Person' }) 201 const body = await followsCommands[2].getFollowers({ start, count, sort, search, state: 'accepted', actorType: 'Person' })
207 expect(res.body.total).to.equal(0) 202 expect(body.total).to.equal(0)
208 expect(res.body.data).to.have.lengthOf(0) 203 expect(body.data).to.have.lengthOf(0)
209 } 204 }
210 205
211 { 206 {
212 const res = await getFollowersListPaginationAndSort({ 207 const body = await followsCommands[2].getFollowers({
213 url,
214 start, 208 start,
215 count, 209 count,
216 sort, 210 sort,
@@ -218,31 +212,31 @@ describe('Test follows', function () {
218 state: 'accepted', 212 state: 'accepted',
219 actorType: 'Application' 213 actorType: 'Application'
220 }) 214 })
221 expect(res.body.total).to.equal(1) 215 expect(body.total).to.equal(1)
222 expect(res.body.data).to.have.lengthOf(1) 216 expect(body.data).to.have.lengthOf(1)
223 } 217 }
224 218
225 { 219 {
226 const res = await getFollowersListPaginationAndSort({ url, start, count, sort, search, state: 'pending' }) 220 const body = await followsCommands[2].getFollowers({ start, count, sort, search, state: 'pending' })
227 expect(res.body.total).to.equal(0) 221 expect(body.total).to.equal(0)
228 expect(res.body.data).to.have.lengthOf(0) 222 expect(body.data).to.have.lengthOf(0)
229 } 223 }
230 } 224 }
231 225
232 { 226 {
233 const res = await getFollowersListPaginationAndSort({ url, start, count, sort, search: 'bla' }) 227 const body = await followsCommands[2].getFollowers({ start, count, sort, search: 'bla' })
234 const follows = res.body.data 228 expect(body.total).to.equal(0)
235 229
236 expect(res.body.total).to.equal(0) 230 const follows = body.data
237 expect(follows.length).to.equal(0) 231 expect(follows.length).to.equal(0)
238 } 232 }
239 }) 233 })
240 234
241 it('Should have 0 followers on server 1', async function () { 235 it('Should have 0 followers on server 1', async function () {
242 const res = await getFollowersListPaginationAndSort({ url: servers[0].url, start: 0, count: 5, sort: 'createdAt' }) 236 const body = await followsCommands[0].getFollowers({ start: 0, count: 5, sort: 'createdAt' })
243 const follows = res.body.data 237 expect(body.total).to.equal(0)
244 238
245 expect(res.body.total).to.equal(0) 239 const follows = body.data
246 expect(follows).to.be.an('array') 240 expect(follows).to.be.an('array')
247 expect(follows.length).to.equal(0) 241 expect(follows.length).to.equal(0)
248 }) 242 })
@@ -263,16 +257,16 @@ describe('Test follows', function () {
263 it('Should unfollow server 3 on server 1', async function () { 257 it('Should unfollow server 3 on server 1', async function () {
264 this.timeout(5000) 258 this.timeout(5000)
265 259
266 await unfollow(servers[0].url, servers[0].accessToken, servers[2]) 260 await followsCommands[0].unfollow({ target: servers[2] })
267 261
268 await waitJobs(servers) 262 await waitJobs(servers)
269 }) 263 })
270 264
271 it('Should not follow server 3 on server 1 anymore', async function () { 265 it('Should not follow server 3 on server 1 anymore', async function () {
272 const res = await getFollowingListPaginationAndSort({ url: servers[0].url, start: 0, count: 2, sort: 'createdAt' }) 266 const body = await followsCommands[0].getFollowings({ start: 0, count: 2, sort: 'createdAt' })
273 const follows = res.body.data 267 expect(body.total).to.equal(1)
274 268
275 expect(res.body.total).to.equal(1) 269 const follows = body.data
276 expect(follows).to.be.an('array') 270 expect(follows).to.be.an('array')
277 expect(follows.length).to.equal(1) 271 expect(follows.length).to.equal(1)
278 272
@@ -280,10 +274,10 @@ describe('Test follows', function () {
280 }) 274 })
281 275
282 it('Should not have server 1 as follower on server 3 anymore', async function () { 276 it('Should not have server 1 as follower on server 3 anymore', async function () {
283 const res = await getFollowersListPaginationAndSort({ url: servers[2].url, start: 0, count: 1, sort: 'createdAt' }) 277 const body = await followsCommands[2].getFollowers({ start: 0, count: 1, sort: 'createdAt' })
278 expect(body.total).to.equal(0)
284 279
285 const follows = res.body.data 280 const follows = body.data
286 expect(res.body.total).to.equal(0)
287 expect(follows).to.be.an('array') 281 expect(follows).to.be.an('array')
288 expect(follows.length).to.equal(0) 282 expect(follows.length).to.equal(0)
289 }) 283 })
@@ -404,7 +398,7 @@ describe('Test follows', function () {
404 await waitJobs(servers) 398 await waitJobs(servers)
405 399
406 // Server 1 follows server 3 400 // Server 1 follows server 3
407 await follow(servers[0].url, [ servers[2].url ], servers[0].accessToken) 401 await followsCommands[0].follow({ targets: [ servers[2].url ] })
408 402
409 await waitJobs(servers) 403 await waitJobs(servers)
410 }) 404 })
@@ -563,7 +557,7 @@ describe('Test follows', function () {
563 it('Should unfollow server 3 on server 1 and does not list server 3 videos', async function () { 557 it('Should unfollow server 3 on server 1 and does not list server 3 videos', async function () {
564 this.timeout(5000) 558 this.timeout(5000)
565 559
566 await unfollow(servers[0].url, servers[0].accessToken, servers[2]) 560 await followsCommands[0].unfollow({ target: servers[2] })
567 561
568 await waitJobs(servers) 562 await waitJobs(servers)
569 563
diff --git a/server/tests/api/server/handle-down.ts b/server/tests/api/server/handle-down.ts
index d57d72f5e..eff4451e5 100644
--- a/server/tests/api/server/handle-down.ts
+++ b/server/tests/api/server/handle-down.ts
@@ -1,39 +1,33 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai'
4import 'mocha' 3import 'mocha'
5import { JobState, Video } from '../../../../shared/models' 4import * as chai from 'chai'
6import { VideoPrivacy } from '../../../../shared/models/videos' 5import { HttpStatusCode } from '@shared/core-utils'
7import { VideoCommentThreadTree } from '../../../../shared/models/videos/comment/video-comment.model'
8
9import { 6import {
7 addVideoCommentReply,
8 addVideoCommentThread,
10 cleanupTests, 9 cleanupTests,
11 closeAllSequelize, 10 closeAllSequelize,
12 completeVideoCheck, 11 completeVideoCheck,
13 flushAndRunMultipleServers, 12 flushAndRunMultipleServers,
13 getJobsListPaginationAndSort,
14 getVideo, 14 getVideo,
15 getVideoCommentThreads,
15 getVideosList, 16 getVideosList,
17 getVideoThreadComments,
16 immutableAssign, 18 immutableAssign,
17 killallServers, 19 killallServers,
18 reRunServer, 20 reRunServer,
19 ServerInfo, 21 ServerInfo,
20 setAccessTokensToServers, 22 setAccessTokensToServers,
21 setActorFollowScores, 23 setActorFollowScores,
22 unfollow,
23 updateVideo, 24 updateVideo,
24 uploadVideo, 25 uploadVideo,
25 uploadVideoAndGetId, 26 uploadVideoAndGetId,
26 wait 27 wait,
27} from '../../../../shared/extra-utils' 28 waitJobs
28import { follow, getFollowersListPaginationAndSort } from '../../../../shared/extra-utils/server/follows' 29} from '@shared/extra-utils'
29import { getJobsListPaginationAndSort, waitJobs } from '../../../../shared/extra-utils/server/jobs' 30import { JobState, Video, VideoCommentThreadTree, VideoPrivacy } from '@shared/models'
30import {
31 addVideoCommentReply,
32 addVideoCommentThread,
33 getVideoCommentThreads,
34 getVideoThreadComments
35} from '../../../../shared/extra-utils/videos/video-comments'
36import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
37 31
38const expect = chai.expect 32const expect = chai.expect
39 33
@@ -118,8 +112,8 @@ describe('Test handle downs', function () {
118 this.timeout(240000) 112 this.timeout(240000)
119 113
120 // Server 2 and 3 follow server 1 114 // Server 2 and 3 follow server 1
121 await follow(servers[1].url, [ servers[0].url ], servers[1].accessToken) 115 await servers[1].followsCommand.follow({ targets: [ servers[0].url ] })
122 await follow(servers[2].url, [ servers[0].url ], servers[2].accessToken) 116 await servers[2].followsCommand.follow({ targets: [ servers[0].url ] })
123 117
124 await waitJobs(servers) 118 await waitJobs(servers)
125 119
@@ -177,10 +171,10 @@ describe('Test handle downs', function () {
177 await wait(11000) 171 await wait(11000)
178 172
179 // Only server 3 is still a follower of server 1 173 // Only server 3 is still a follower of server 1
180 const res = await getFollowersListPaginationAndSort({ url: servers[0].url, start: 0, count: 2, sort: 'createdAt' }) 174 const body = await servers[0].followsCommand.getFollowers({ start: 0, count: 2, sort: 'createdAt' })
181 expect(res.body.data).to.be.an('array') 175 expect(body.data).to.be.an('array')
182 expect(res.body.data).to.have.lengthOf(1) 176 expect(body.data).to.have.lengthOf(1)
183 expect(res.body.data[0].follower.host).to.equal('localhost:' + servers[2].port) 177 expect(body.data[0].follower.host).to.equal('localhost:' + servers[2].port)
184 }) 178 })
185 179
186 it('Should not have pending/processing jobs anymore', async function () { 180 it('Should not have pending/processing jobs anymore', async function () {
@@ -205,16 +199,16 @@ describe('Test handle downs', function () {
205 await reRunServer(servers[1]) 199 await reRunServer(servers[1])
206 await reRunServer(servers[2]) 200 await reRunServer(servers[2])
207 201
208 await unfollow(servers[1].url, servers[1].accessToken, servers[0]) 202 await servers[1].followsCommand.unfollow({ target: servers[0] })
209 await waitJobs(servers) 203 await waitJobs(servers)
210 204
211 await follow(servers[1].url, [ servers[0].url ], servers[1].accessToken) 205 await servers[1].followsCommand.follow({ targets: [ servers[0].url ] })
212 206
213 await waitJobs(servers) 207 await waitJobs(servers)
214 208
215 const res = await getFollowersListPaginationAndSort({ url: servers[0].url, start: 0, count: 2, sort: 'createdAt' }) 209 const body = await servers[0].followsCommand.getFollowers({ start: 0, count: 2, sort: 'createdAt' })
216 expect(res.body.data).to.be.an('array') 210 expect(body.data).to.be.an('array')
217 expect(res.body.data).to.have.lengthOf(2) 211 expect(body.data).to.have.lengthOf(2)
218 }) 212 })
219 213
220 it('Should send an update to server 3, and automatically fetch the video', async function () { 214 it('Should send an update to server 3, and automatically fetch the video', async function () {
diff --git a/server/tests/api/server/jobs.ts b/server/tests/api/server/jobs.ts
index d0e222997..6576dd7af 100644
--- a/server/tests/api/server/jobs.ts
+++ b/server/tests/api/server/jobs.ts
@@ -1,13 +1,13 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai'
4import 'mocha' 3import 'mocha'
4import * as chai from 'chai'
5import { cleanupTests, ServerInfo, setAccessTokensToServers } from '../../../../shared/extra-utils/index' 5import { cleanupTests, ServerInfo, setAccessTokensToServers } from '../../../../shared/extra-utils/index'
6import { dateIsValid } from '../../../../shared/extra-utils/miscs/miscs'
6import { doubleFollow } from '../../../../shared/extra-utils/server/follows' 7import { doubleFollow } from '../../../../shared/extra-utils/server/follows'
7import { getJobsList, getJobsListPaginationAndSort, waitJobs } from '../../../../shared/extra-utils/server/jobs' 8import { getJobsList, getJobsListPaginationAndSort, waitJobs } from '../../../../shared/extra-utils/server/jobs'
8import { flushAndRunMultipleServers } from '../../../../shared/extra-utils/server/servers' 9import { flushAndRunMultipleServers } from '../../../../shared/extra-utils/server/servers'
9import { uploadVideo } from '../../../../shared/extra-utils/videos/videos' 10import { uploadVideo } from '../../../../shared/extra-utils/videos/videos'
10import { dateIsValid } from '../../../../shared/extra-utils/miscs/miscs'
11import { Job } from '../../../../shared/models/server' 11import { Job } from '../../../../shared/models/server'
12 12
13const expect = chai.expect 13const expect = chai.expect
diff --git a/server/tests/api/server/stats.ts b/server/tests/api/server/stats.ts
index 304181a6d..f609ea725 100644
--- a/server/tests/api/server/stats.ts
+++ b/server/tests/api/server/stats.ts
@@ -4,27 +4,23 @@ import 'mocha'
4import * as chai from 'chai' 4import * as chai from 'chai'
5import { 5import {
6 addVideoChannel, 6 addVideoChannel,
7 addVideoCommentThread,
7 cleanupTests, 8 cleanupTests,
8 createUser, 9 createUser,
9 createVideoPlaylist, 10 createVideoPlaylist,
10 doubleFollow, 11 doubleFollow,
11 flushAndRunMultipleServers, 12 flushAndRunMultipleServers,
12 follow,
13 ServerInfo, 13 ServerInfo,
14 unfollow, 14 setAccessTokensToServers,
15 updateCustomSubConfig, 15 updateCustomSubConfig,
16 uploadVideo, 16 uploadVideo,
17 userLogin, 17 userLogin,
18 viewVideo, 18 viewVideo,
19 wait 19 wait,
20} from '../../../../shared/extra-utils' 20 waitJobs
21import { setAccessTokensToServers } from '../../../../shared/extra-utils/index' 21} from '@shared/extra-utils'
22import { waitJobs } from '../../../../shared/extra-utils/server/jobs' 22import { getStats } from '@shared/extra-utils/server/stats'
23import { getStats } from '../../../../shared/extra-utils/server/stats' 23import { ActivityType, ServerStats, VideoPlaylistPrivacy } from '@shared/models'
24import { addVideoCommentThread } from '../../../../shared/extra-utils/videos/video-comments'
25import { ServerStats } from '../../../../shared/models/server/server-stats.model'
26import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model'
27import { ActivityType } from '@shared/models'
28 24
29const expect = chai.expect 25const expect = chai.expect
30 26
@@ -57,7 +53,7 @@ describe('Test stats (excluding redundancy)', function () {
57 // Wait the video views repeatable job 53 // Wait the video views repeatable job
58 await wait(8000) 54 await wait(8000)
59 55
60 await follow(servers[2].url, [ servers[0].url ], servers[2].accessToken) 56 await servers[2].followsCommand.follow({ targets: [ servers[0].url ] })
61 await waitJobs(servers) 57 await waitJobs(servers)
62 }) 58 })
63 59
@@ -111,7 +107,7 @@ describe('Test stats (excluding redundancy)', function () {
111 it('Should have the correct total videos stats after an unfollow', async function () { 107 it('Should have the correct total videos stats after an unfollow', async function () {
112 this.timeout(15000) 108 this.timeout(15000)
113 109
114 await unfollow(servers[2].url, servers[2].accessToken, servers[0]) 110 await servers[2].followsCommand.unfollow({ target: servers[0] })
115 await waitJobs(servers) 111 await waitJobs(servers)
116 112
117 const res = await getStats(servers[2].url) 113 const res = await getStats(servers[2].url)
diff --git a/server/tests/api/users/user-subscriptions.ts b/server/tests/api/users/user-subscriptions.ts
index 60676a37b..7e365d797 100644
--- a/server/tests/api/users/user-subscriptions.ts
+++ b/server/tests/api/users/user-subscriptions.ts
@@ -1,30 +1,27 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai'
4import 'mocha' 3import 'mocha'
4import * as chai from 'chai'
5import { 5import {
6 addUserSubscription,
7 areSubscriptionsExist,
6 cleanupTests, 8 cleanupTests,
7 createUser, 9 createUser,
8 doubleFollow, 10 doubleFollow,
9 flushAndRunMultipleServers, 11 flushAndRunMultipleServers,
10 follow,
11 getVideosList,
12 unfollow,
13 updateVideo,
14 userLogin
15} from '../../../../shared/extra-utils'
16import { ServerInfo, uploadVideo } from '../../../../shared/extra-utils/index'
17import { setAccessTokensToServers } from '../../../../shared/extra-utils/users/login'
18import { Video, VideoChannel } from '../../../../shared/models/videos'
19import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
20import {
21 addUserSubscription,
22 areSubscriptionsExist,
23 getUserSubscription, 12 getUserSubscription,
13 getVideosList,
24 listUserSubscriptions, 14 listUserSubscriptions,
25 listUserSubscriptionVideos, 15 listUserSubscriptionVideos,
26 removeUserSubscription 16 removeUserSubscription,
27} from '../../../../shared/extra-utils/users/user-subscriptions' 17 ServerInfo,
18 setAccessTokensToServers,
19 updateVideo,
20 uploadVideo,
21 userLogin,
22 waitJobs
23} from '@shared/extra-utils'
24import { Video, VideoChannel } from '@shared/models'
28 25
29const expect = chai.expect 26const expect = chai.expect
30 27
@@ -250,7 +247,7 @@ describe('Test users subscriptions', function () {
250 it('Should have server 1 follow server 3 and display server 3 videos', async function () { 247 it('Should have server 1 follow server 3 and display server 3 videos', async function () {
251 this.timeout(60000) 248 this.timeout(60000)
252 249
253 await follow(servers[0].url, [ servers[2].url ], servers[0].accessToken) 250 await servers[0].followsCommand.follow({ targets: [ servers[2].url ] })
254 251
255 await waitJobs(servers) 252 await waitJobs(servers)
256 253
@@ -268,7 +265,7 @@ describe('Test users subscriptions', function () {
268 it('Should remove follow server 1 -> server 3 and hide server 3 videos', async function () { 265 it('Should remove follow server 1 -> server 3 and hide server 3 videos', async function () {
269 this.timeout(60000) 266 this.timeout(60000)
270 267
271 await unfollow(servers[0].url, servers[0].accessToken, servers[2]) 268 await servers[0].followsCommand.unfollow({ target: servers[2] })
272 269
273 await waitJobs(servers) 270 await waitJobs(servers)
274 271
diff --git a/server/tests/api/users/users.ts b/server/tests/api/users/users.ts
index 6bfc7cfe5..92927ea97 100644
--- a/server/tests/api/users/users.ts
+++ b/server/tests/api/users/users.ts
@@ -11,7 +11,6 @@ import {
11 createUser, 11 createUser,
12 deleteMe, 12 deleteMe,
13 flushAndRunServer, 13 flushAndRunServer,
14 follow,
15 getAccountRatings, 14 getAccountRatings,
16 getBlacklistedVideosList, 15 getBlacklistedVideosList,
17 getCustomConfig, 16 getCustomConfig,
@@ -138,7 +137,12 @@ describe('Test users', function () {
138 137
139 it('Should not be able to follow', async function () { 138 it('Should not be able to follow', async function () {
140 accessToken = 'my_super_token' 139 accessToken = 'my_super_token'
141 await follow(server.url, [ 'http://example.com' ], accessToken, HttpStatusCode.UNAUTHORIZED_401) 140
141 await server.followsCommand.follow({
142 targets: [ 'http://example.com' ],
143 token: accessToken,
144 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
145 })
142 }) 146 })
143 147
144 it('Should not be able to unfollow') 148 it('Should not be able to unfollow')
diff --git a/server/tests/api/videos/video-description.ts b/server/tests/api/videos/video-description.ts
index b8e98e45f..e1c9afe79 100644
--- a/server/tests/api/videos/video-description.ts
+++ b/server/tests/api/videos/video-description.ts
@@ -1,7 +1,7 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai'
4import 'mocha' 3import 'mocha'
4import * as chai from 'chai'
5import { 5import {
6 cleanupTests, 6 cleanupTests,
7 flushAndRunMultipleServers, 7 flushAndRunMultipleServers,
diff --git a/server/tests/api/videos/video-playlists.ts b/server/tests/api/videos/video-playlists.ts
index da8de054b..28f68dcfe 100644
--- a/server/tests/api/videos/video-playlists.ts
+++ b/server/tests/api/videos/video-playlists.ts
@@ -2,8 +2,12 @@
2 2
3import 'mocha' 3import 'mocha'
4import * as chai from 'chai' 4import * as chai from 'chai'
5import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' 5import { HttpStatusCode } from '@shared/core-utils'
6import { 6import {
7 addAccountToAccountBlocklist,
8 addAccountToServerBlocklist,
9 addServerToAccountBlocklist,
10 addServerToServerBlocklist,
7 addVideoChannel, 11 addVideoChannel,
8 addVideoInPlaylist, 12 addVideoInPlaylist,
9 addVideoToBlacklist, 13 addVideoToBlacklist,
@@ -27,6 +31,10 @@ import {
27 getVideoPlaylistPrivacies, 31 getVideoPlaylistPrivacies,
28 getVideoPlaylistsList, 32 getVideoPlaylistsList,
29 getVideoPlaylistWithToken, 33 getVideoPlaylistWithToken,
34 removeAccountFromAccountBlocklist,
35 removeAccountFromServerBlocklist,
36 removeServerFromAccountBlocklist,
37 removeServerFromServerBlocklist,
30 removeUser, 38 removeUser,
31 removeVideoFromBlacklist, 39 removeVideoFromBlacklist,
32 removeVideoFromPlaylist, 40 removeVideoFromPlaylist,
@@ -35,7 +43,6 @@ import {
35 setAccessTokensToServers, 43 setAccessTokensToServers,
36 setDefaultVideoChannel, 44 setDefaultVideoChannel,
37 testImage, 45 testImage,
38 unfollow,
39 updateVideo, 46 updateVideo,
40 updateVideoPlaylist, 47 updateVideoPlaylist,
41 updateVideoPlaylistElement, 48 updateVideoPlaylistElement,
@@ -44,24 +51,18 @@ import {
44 userLogin, 51 userLogin,
45 wait, 52 wait,
46 waitJobs 53 waitJobs
47} from '../../../../shared/extra-utils' 54} from '@shared/extra-utils'
48import { 55import {
49 addAccountToAccountBlocklist, 56 User,
50 addAccountToServerBlocklist, 57 VideoExistInPlaylist,
51 addServerToAccountBlocklist, 58 VideoPlaylist,
52 addServerToServerBlocklist, 59 VideoPlaylistCreateResult,
53 removeAccountFromAccountBlocklist, 60 VideoPlaylistElement,
54 removeAccountFromServerBlocklist, 61 VideoPlaylistElementType,
55 removeServerFromAccountBlocklist, 62 VideoPlaylistPrivacy,
56 removeServerFromServerBlocklist 63 VideoPlaylistType,
57} from '../../../../shared/extra-utils/users/blocklist' 64 VideoPrivacy
58import { User } from '../../../../shared/models/users' 65} from '@shared/models'
59import { VideoPlaylistCreateResult, VideoPrivacy } from '../../../../shared/models/videos'
60import { VideoExistInPlaylist } from '../../../../shared/models/videos/playlist/video-exist-in-playlist.model'
61import { VideoPlaylistElement, VideoPlaylistElementType } from '../../../../shared/models/videos/playlist/video-playlist-element.model'
62import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model'
63import { VideoPlaylistType } from '../../../../shared/models/videos/playlist/video-playlist-type.model'
64import { VideoPlaylist } from '../../../../shared/models/videos/playlist/video-playlist.model'
65 66
66const expect = chai.expect 67const expect = chai.expect
67 68
@@ -1171,7 +1172,7 @@ describe('Test video playlists', function () {
1171 expect(finder(res.body.data)).to.not.be.undefined 1172 expect(finder(res.body.data)).to.not.be.undefined
1172 } 1173 }
1173 1174
1174 await unfollow(servers[2].url, servers[2].accessToken, servers[0]) 1175 await servers[2].followsCommand.unfollow({ target: servers[0] })
1175 1176
1176 { 1177 {
1177 const res = await getVideoPlaylistsList(servers[2].url, 0, 5) 1178 const res = await getVideoPlaylistsList(servers[2].url, 0, 5)
diff --git a/shared/extra-utils/index.ts b/shared/extra-utils/index.ts
index 7b5835e47..48431ed83 100644
--- a/shared/extra-utils/index.ts
+++ b/shared/extra-utils/index.ts
@@ -7,15 +7,14 @@ export * from './miscs'
7export * from './mock-servers' 7export * from './mock-servers'
8export * from './moderation' 8export * from './moderation'
9export * from './overviews' 9export * from './overviews'
10export * from './search'
11export * from './server'
10 12
11export * from './requests/check-api-params' 13export * from './requests/check-api-params'
12export * from './requests/requests' 14export * from './requests/requests'
13 15
14export * from './search'
15
16export * from './server/clients' 16export * from './server/clients'
17export * from './server/config' 17export * from './server/config'
18export * from './server/follows'
19export * from './server/jobs' 18export * from './server/jobs'
20export * from './server/plugins' 19export * from './server/plugins'
21export * from './server/servers' 20export * from './server/servers'
diff --git a/shared/extra-utils/server/follows-command.ts b/shared/extra-utils/server/follows-command.ts
new file mode 100644
index 000000000..aba7bce82
--- /dev/null
+++ b/shared/extra-utils/server/follows-command.ts
@@ -0,0 +1,124 @@
1import { pick } from 'lodash'
2import { ActivityPubActorType, ActorFollow, FollowState, ResultList } from '@shared/models'
3import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes'
4import { AbstractCommand, OverrideCommandOptions } from '../shared'
5import { ServerInfo } from './servers'
6
7export class FollowsCommand extends AbstractCommand {
8
9 getFollowers (options: OverrideCommandOptions & {
10 start: number
11 count: number
12 sort: string
13 search?: string
14 actorType?: ActivityPubActorType
15 state?: FollowState
16 }) {
17 const path = '/api/v1/server/followers'
18
19 const toPick = [ 'start', 'count', 'sort', 'search', 'state', 'actorType' ]
20 const query = pick(options, toPick)
21
22 return this.getRequestBody<ResultList<ActorFollow>>({
23 ...options,
24
25 token: null,
26
27 path,
28 query,
29 defaultExpectedStatus: HttpStatusCode.OK_200
30 })
31 }
32
33 getFollowings (options: OverrideCommandOptions & {
34 start: number
35 count: number
36 sort: string
37 search?: string
38 actorType?: ActivityPubActorType
39 state?: FollowState
40 }) {
41 const path = '/api/v1/server/following'
42
43 const toPick = [ 'start', 'count', 'sort', 'search', 'state', 'actorType' ]
44 const query = pick(options, toPick)
45
46 return this.getRequestBody<ResultList<ActorFollow>>({
47 ...options,
48
49 token: null,
50
51 path,
52 query,
53 defaultExpectedStatus: HttpStatusCode.OK_200
54 })
55 }
56
57 follow (options: OverrideCommandOptions & {
58 targets: string[]
59 }) {
60 const path = '/api/v1/server/following'
61
62 const hosts = options.targets.map(f => f.replace(/^http:\/\//, ''))
63
64 return this.postBodyRequest({
65 ...options,
66
67 path,
68 fields: { hosts },
69 defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204
70 })
71 }
72
73 async unfollow (options: OverrideCommandOptions & {
74 target: ServerInfo
75 }) {
76 const path = '/api/v1/server/following/' + options.target.host
77
78 return this.deleteRequest({
79 ...options,
80
81 path,
82 defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204
83 })
84 }
85
86 acceptFollower (options: OverrideCommandOptions & {
87 follower: string
88 }) {
89 const path = '/api/v1/server/followers/' + options.follower + '/accept'
90
91 return this.postBodyRequest({
92 ...options,
93
94 path,
95 defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204
96 })
97 }
98
99 rejectFollower (options: OverrideCommandOptions & {
100 follower: string
101 }) {
102 const path = '/api/v1/server/followers/' + options.follower + '/reject'
103
104 return this.postBodyRequest({
105 ...options,
106
107 path,
108 defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204
109 })
110 }
111
112 removeFollower (options: OverrideCommandOptions & {
113 follower: ServerInfo
114 }) {
115 const path = '/api/v1/server/followers/peertube@' + options.follower.host
116
117 return this.deleteRequest({
118 ...options,
119
120 path,
121 defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204
122 })
123 }
124}
diff --git a/shared/extra-utils/server/follows.ts b/shared/extra-utils/server/follows.ts
index 6aae4a31d..c23cebd81 100644
--- a/shared/extra-utils/server/follows.ts
+++ b/shared/extra-utils/server/follows.ts
@@ -1,126 +1,10 @@
1import * as request from 'supertest'
2import { ServerInfo } from './servers'
3import { waitJobs } from './jobs' 1import { waitJobs } from './jobs'
4import { makePostBodyRequest } from '../requests/requests' 2import { ServerInfo } from './servers'
5import { ActivityPubActorType, FollowState } from '@shared/models'
6import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes'
7
8function getFollowersListPaginationAndSort (options: {
9 url: string
10 start: number
11 count: number
12 sort: string
13 search?: string
14 actorType?: ActivityPubActorType
15 state?: FollowState
16}) {
17 const { url, start, count, sort, search, state, actorType } = options
18 const path = '/api/v1/server/followers'
19
20 const query = {
21 start,
22 count,
23 sort,
24 search,
25 state,
26 actorType
27 }
28
29 return request(url)
30 .get(path)
31 .query(query)
32 .set('Accept', 'application/json')
33 .expect(HttpStatusCode.OK_200)
34 .expect('Content-Type', /json/)
35}
36
37function acceptFollower (url: string, token: string, follower: string, statusCodeExpected = HttpStatusCode.NO_CONTENT_204) {
38 const path = '/api/v1/server/followers/' + follower + '/accept'
39
40 return makePostBodyRequest({
41 url,
42 token,
43 path,
44 statusCodeExpected
45 })
46}
47
48function rejectFollower (url: string, token: string, follower: string, statusCodeExpected = HttpStatusCode.NO_CONTENT_204) {
49 const path = '/api/v1/server/followers/' + follower + '/reject'
50
51 return makePostBodyRequest({
52 url,
53 token,
54 path,
55 statusCodeExpected
56 })
57}
58
59function getFollowingListPaginationAndSort (options: {
60 url: string
61 start: number
62 count: number
63 sort: string
64 search?: string
65 actorType?: ActivityPubActorType
66 state?: FollowState
67}) {
68 const { url, start, count, sort, search, state, actorType } = options
69 const path = '/api/v1/server/following'
70
71 const query = {
72 start,
73 count,
74 sort,
75 search,
76 state,
77 actorType
78 }
79
80 return request(url)
81 .get(path)
82 .query(query)
83 .set('Accept', 'application/json')
84 .expect(HttpStatusCode.OK_200)
85 .expect('Content-Type', /json/)
86}
87
88function follow (follower: string, following: string[], accessToken: string, expectedStatus = HttpStatusCode.NO_CONTENT_204) {
89 const path = '/api/v1/server/following'
90
91 const followingHosts = following.map(f => f.replace(/^http:\/\//, ''))
92 return request(follower)
93 .post(path)
94 .set('Accept', 'application/json')
95 .set('Authorization', 'Bearer ' + accessToken)
96 .send({ hosts: followingHosts })
97 .expect(expectedStatus)
98}
99
100async function unfollow (url: string, accessToken: string, target: ServerInfo, expectedStatus = HttpStatusCode.NO_CONTENT_204) {
101 const path = '/api/v1/server/following/' + target.host
102
103 return request(url)
104 .delete(path)
105 .set('Accept', 'application/json')
106 .set('Authorization', 'Bearer ' + accessToken)
107 .expect(expectedStatus)
108}
109
110function removeFollower (url: string, accessToken: string, follower: ServerInfo, expectedStatus = HttpStatusCode.NO_CONTENT_204) {
111 const path = '/api/v1/server/followers/peertube@' + follower.host
112
113 return request(url)
114 .delete(path)
115 .set('Accept', 'application/json')
116 .set('Authorization', 'Bearer ' + accessToken)
117 .expect(expectedStatus)
118}
119 3
120async function doubleFollow (server1: ServerInfo, server2: ServerInfo) { 4async function doubleFollow (server1: ServerInfo, server2: ServerInfo) {
121 await Promise.all([ 5 await Promise.all([
122 follow(server1.url, [ server2.url ], server1.accessToken), 6 server1.followsCommand.follow({ targets: [ server2.url ] }),
123 follow(server2.url, [ server1.url ], server2.accessToken) 7 server2.followsCommand.follow({ targets: [ server1.url ] })
124 ]) 8 ])
125 9
126 // Wait request propagation 10 // Wait request propagation
@@ -132,12 +16,5 @@ async function doubleFollow (server1: ServerInfo, server2: ServerInfo) {
132// --------------------------------------------------------------------------- 16// ---------------------------------------------------------------------------
133 17
134export { 18export {
135 getFollowersListPaginationAndSort, 19 doubleFollow
136 getFollowingListPaginationAndSort,
137 unfollow,
138 removeFollower,
139 follow,
140 doubleFollow,
141 acceptFollower,
142 rejectFollower
143} 20}
diff --git a/shared/extra-utils/server/index.ts b/shared/extra-utils/server/index.ts
index f0071ba72..258084623 100644
--- a/shared/extra-utils/server/index.ts
+++ b/shared/extra-utils/server/index.ts
@@ -1,2 +1,4 @@
1export * from './contact-form-command' 1export * from './contact-form-command'
2export * from './debug-command' 2export * from './debug-command'
3export * from './follows-command'
4export * from './follows'
diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts
index 30e712ab8..7ac80cea0 100644
--- a/shared/extra-utils/server/servers.ts
+++ b/shared/extra-utils/server/servers.ts
@@ -18,6 +18,7 @@ import { makeGetRequest } from '../requests/requests'
18import { SearchCommand } from '../search' 18import { SearchCommand } from '../search'
19import { ContactFormCommand } from './contact-form-command' 19import { ContactFormCommand } from './contact-form-command'
20import { DebugCommand } from './debug-command' 20import { DebugCommand } from './debug-command'
21import { FollowsCommand } from './follows-command'
21 22
22interface ServerInfo { 23interface ServerInfo {
23 app: ChildProcess 24 app: ChildProcess
@@ -81,6 +82,7 @@ interface ServerInfo {
81 searchCommand?: SearchCommand 82 searchCommand?: SearchCommand
82 contactFormCommand?: ContactFormCommand 83 contactFormCommand?: ContactFormCommand
83 debugCommand?: DebugCommand 84 debugCommand?: DebugCommand
85 followsCommand?: FollowsCommand
84} 86}
85 87
86function parallelTests () { 88function parallelTests () {
@@ -296,6 +298,7 @@ async function runServer (server: ServerInfo, configOverrideArg?: any, args = []
296 server.searchCommand = new SearchCommand(server) 298 server.searchCommand = new SearchCommand(server)
297 server.contactFormCommand = new ContactFormCommand(server) 299 server.contactFormCommand = new ContactFormCommand(server)
298 server.debugCommand = new DebugCommand(server) 300 server.debugCommand = new DebugCommand(server)
301 server.followsCommand = new FollowsCommand(server)
299 302
300 res(server) 303 res(server)
301 }) 304 })