diff options
23 files changed, 737 insertions, 523 deletions
diff --git a/client/src/app/+admin/follows/followers-list/followers-list.component.html b/client/src/app/+admin/follows/followers-list/followers-list.component.html index 549aacdf0..84c49ae80 100644 --- a/client/src/app/+admin/follows/followers-list/followers-list.component.html +++ b/client/src/app/+admin/follows/followers-list/followers-list.component.html | |||
@@ -10,6 +10,7 @@ | |||
10 | <p-column field="follower.host" header="Host"></p-column> | 10 | <p-column field="follower.host" header="Host"></p-column> |
11 | <p-column field="email" header="Email"></p-column> | 11 | <p-column field="email" header="Email"></p-column> |
12 | <p-column field="follower.score" header="Score"></p-column> | 12 | <p-column field="follower.score" header="Score"></p-column> |
13 | <p-column field="state" header="State"></p-column> | ||
13 | <p-column field="createdAt" header="Created date" [sortable]="true"></p-column> | 14 | <p-column field="createdAt" header="Created date" [sortable]="true"></p-column> |
14 | </p-dataTable> | 15 | </p-dataTable> |
15 | </div> | 16 | </div> |
diff --git a/client/src/app/+admin/follows/following-list/following-list.component.html b/client/src/app/+admin/follows/following-list/following-list.component.html index dcc03f4a5..dbc9852d0 100644 --- a/client/src/app/+admin/follows/following-list/following-list.component.html +++ b/client/src/app/+admin/follows/following-list/following-list.component.html | |||
@@ -9,7 +9,7 @@ | |||
9 | <p-column field="id" header="ID"></p-column> | 9 | <p-column field="id" header="ID"></p-column> |
10 | <p-column field="following.host" header="Host"></p-column> | 10 | <p-column field="following.host" header="Host"></p-column> |
11 | <p-column field="email" header="Email"></p-column> | 11 | <p-column field="email" header="Email"></p-column> |
12 | <p-column field="following.score" header="Score"></p-column> | 12 | <p-column field="state" header="State"></p-column> |
13 | <p-column field="createdAt" header="Created date" [sortable]="true"></p-column> | 13 | <p-column field="createdAt" header="Created date" [sortable]="true"></p-column> |
14 | <p-column header="Unfollow" styleClass="action-cell"> | 14 | <p-column header="Unfollow" styleClass="action-cell"> |
15 | <ng-template pTemplate="body" let-following="rowData"> | 15 | <ng-template pTemplate="body" let-following="rowData"> |
diff --git a/server/controllers/api/server/follows.ts b/server/controllers/api/server/follows.ts index 8fc70f34f..c759824e0 100644 --- a/server/controllers/api/server/follows.ts +++ b/server/controllers/api/server/follows.ts | |||
@@ -16,6 +16,9 @@ import { followersSortValidator, followingSortValidator } from '../../../middlew | |||
16 | import { AccountFollowInstance } from '../../../models/index' | 16 | import { AccountFollowInstance } from '../../../models/index' |
17 | import { sendFollow } from '../../../lib/index' | 17 | import { sendFollow } from '../../../lib/index' |
18 | import { sendUndoFollow } from '../../../lib/activitypub/send/send-undo' | 18 | import { sendUndoFollow } from '../../../lib/activitypub/send/send-undo' |
19 | import { AccountInstance } from '../../../models/account/account-interface' | ||
20 | import { retryTransactionWrapper } from '../../../helpers/database-utils' | ||
21 | import { saveAccountAndServerIfNotExist } from '../../../lib/activitypub/account' | ||
19 | 22 | ||
20 | const serverFollowsRouter = express.Router() | 23 | const serverFollowsRouter = express.Router() |
21 | 24 | ||
@@ -32,7 +35,7 @@ serverFollowsRouter.post('/following', | |||
32 | ensureUserHasRight(UserRight.MANAGE_SERVER_FOLLOW), | 35 | ensureUserHasRight(UserRight.MANAGE_SERVER_FOLLOW), |
33 | followValidator, | 36 | followValidator, |
34 | setBodyHostsPort, | 37 | setBodyHostsPort, |
35 | asyncMiddleware(follow) | 38 | asyncMiddleware(followRetry) |
36 | ) | 39 | ) |
37 | 40 | ||
38 | serverFollowsRouter.delete('/following/:accountId', | 41 | serverFollowsRouter.delete('/following/:accountId', |
@@ -72,7 +75,7 @@ async function listFollowers (req: express.Request, res: express.Response, next: | |||
72 | return res.json(getFormattedObjects(resultList.data, resultList.total)) | 75 | return res.json(getFormattedObjects(resultList.data, resultList.total)) |
73 | } | 76 | } |
74 | 77 | ||
75 | async function follow (req: express.Request, res: express.Response, next: express.NextFunction) { | 78 | async function followRetry (req: express.Request, res: express.Response, next: express.NextFunction) { |
76 | const hosts = req.body.hosts as string[] | 79 | const hosts = req.body.hosts as string[] |
77 | const fromAccount = await getServerAccount() | 80 | const fromAccount = await getServerAccount() |
78 | 81 | ||
@@ -88,31 +91,12 @@ async function follow (req: express.Request, res: express.Response, next: expres | |||
88 | .then(accountResult => { | 91 | .then(accountResult => { |
89 | let targetAccount = accountResult.account | 92 | let targetAccount = accountResult.account |
90 | 93 | ||
91 | return db.sequelize.transaction(async t => { | 94 | const options = { |
92 | if (accountResult.loadedFromDB === false) { | 95 | arguments: [ fromAccount, targetAccount, accountResult.loadedFromDB ], |
93 | targetAccount = await targetAccount.save({ transaction: t }) | 96 | errorMessage: 'Cannot follow with many retries.' |
94 | } | 97 | } |
95 | 98 | ||
96 | const [ accountFollow ] = await db.AccountFollow.findOrCreate({ | 99 | return retryTransactionWrapper(follow, options) |
97 | where: { | ||
98 | accountId: fromAccount.id, | ||
99 | targetAccountId: targetAccount.id | ||
100 | }, | ||
101 | defaults: { | ||
102 | state: 'pending', | ||
103 | accountId: fromAccount.id, | ||
104 | targetAccountId: targetAccount.id | ||
105 | }, | ||
106 | transaction: t | ||
107 | }) | ||
108 | accountFollow.AccountFollowing = targetAccount | ||
109 | accountFollow.AccountFollower = fromAccount | ||
110 | |||
111 | // Send a notification to remote server | ||
112 | if (accountFollow.state === 'pending') { | ||
113 | await sendFollow(accountFollow, t) | ||
114 | } | ||
115 | }) | ||
116 | }) | 100 | }) |
117 | .catch(err => logger.warn('Cannot follow server %s.', `${accountName}@${host}`, err)) | 101 | .catch(err => logger.warn('Cannot follow server %s.', `${accountName}@${host}`, err)) |
118 | 102 | ||
@@ -121,19 +105,51 @@ async function follow (req: express.Request, res: express.Response, next: expres | |||
121 | 105 | ||
122 | // Don't make the client wait the tasks | 106 | // Don't make the client wait the tasks |
123 | Promise.all(tasks) | 107 | Promise.all(tasks) |
124 | .catch(err => { | 108 | .catch(err => logger.error('Error in follow.', err)) |
125 | logger.error('Error in follow.', err) | ||
126 | }) | ||
127 | 109 | ||
128 | return res.status(204).end() | 110 | return res.status(204).end() |
129 | } | 111 | } |
130 | 112 | ||
113 | async function follow (fromAccount: AccountInstance, targetAccount: AccountInstance, targetAlreadyInDB: boolean) { | ||
114 | try { | ||
115 | await db.sequelize.transaction(async t => { | ||
116 | if (targetAlreadyInDB === false) { | ||
117 | await saveAccountAndServerIfNotExist(targetAccount, t) | ||
118 | } | ||
119 | |||
120 | const [ accountFollow ] = await db.AccountFollow.findOrCreate({ | ||
121 | where: { | ||
122 | accountId: fromAccount.id, | ||
123 | targetAccountId: targetAccount.id | ||
124 | }, | ||
125 | defaults: { | ||
126 | state: 'pending', | ||
127 | accountId: fromAccount.id, | ||
128 | targetAccountId: targetAccount.id | ||
129 | }, | ||
130 | transaction: t | ||
131 | }) | ||
132 | accountFollow.AccountFollowing = targetAccount | ||
133 | accountFollow.AccountFollower = fromAccount | ||
134 | |||
135 | // Send a notification to remote server | ||
136 | if (accountFollow.state === 'pending') { | ||
137 | await sendFollow(accountFollow, t) | ||
138 | } | ||
139 | }) | ||
140 | } catch (err) { | ||
141 | // Reset target account | ||
142 | targetAccount.isNewRecord = !targetAlreadyInDB | ||
143 | throw err | ||
144 | } | ||
145 | } | ||
146 | |||
131 | async function removeFollow (req: express.Request, res: express.Response, next: express.NextFunction) { | 147 | async function removeFollow (req: express.Request, res: express.Response, next: express.NextFunction) { |
132 | const following: AccountFollowInstance = res.locals.following | 148 | const follow: AccountFollowInstance = res.locals.follow |
133 | 149 | ||
134 | await db.sequelize.transaction(async t => { | 150 | await db.sequelize.transaction(async t => { |
135 | await sendUndoFollow(following, t) | 151 | await sendUndoFollow(follow, t) |
136 | await following.destroy({ transaction: t }) | 152 | await follow.destroy({ transaction: t }) |
137 | }) | 153 | }) |
138 | 154 | ||
139 | return res.status(204).end() | 155 | return res.status(204).end() |
diff --git a/server/helpers/database-utils.ts b/server/helpers/database-utils.ts index 169b80065..dacd747c9 100644 --- a/server/helpers/database-utils.ts +++ b/server/helpers/database-utils.ts | |||
@@ -4,12 +4,15 @@ import * as Bluebird from 'bluebird' | |||
4 | import { logger } from './logger' | 4 | import { logger } from './logger' |
5 | 5 | ||
6 | type RetryTransactionWrapperOptions = { errorMessage: string, arguments?: any[] } | 6 | type RetryTransactionWrapperOptions = { errorMessage: string, arguments?: any[] } |
7 | function retryTransactionWrapper (functionToRetry: (...args) => Promise<any> | Bluebird<any>, options: RetryTransactionWrapperOptions) { | 7 | function retryTransactionWrapper <T> ( |
8 | functionToRetry: (...args) => Promise<T> | Bluebird<T>, | ||
9 | options: RetryTransactionWrapperOptions | ||
10 | ): Promise<T> { | ||
8 | const args = options.arguments ? options.arguments : [] | 11 | const args = options.arguments ? options.arguments : [] |
9 | 12 | ||
10 | return transactionRetryer(callback => { | 13 | return transactionRetryer<T>(callback => { |
11 | functionToRetry.apply(this, args) | 14 | functionToRetry.apply(this, args) |
12 | .then(result => callback(null, result)) | 15 | .then((result: T) => callback(null, result)) |
13 | .catch(err => callback(err)) | 16 | .catch(err => callback(err)) |
14 | }) | 17 | }) |
15 | .catch(err => { | 18 | .catch(err => { |
@@ -18,8 +21,8 @@ function retryTransactionWrapper (functionToRetry: (...args) => Promise<any> | B | |||
18 | }) | 21 | }) |
19 | } | 22 | } |
20 | 23 | ||
21 | function transactionRetryer (func: Function) { | 24 | function transactionRetryer <T> (func: (err: any, data: T) => any) { |
22 | return new Promise((res, rej) => { | 25 | return new Promise<T>((res, rej) => { |
23 | retry({ | 26 | retry({ |
24 | times: 5, | 27 | times: 5, |
25 | 28 | ||
diff --git a/server/helpers/webfinger.ts b/server/helpers/webfinger.ts index b7408c845..a5b4785fe 100644 --- a/server/helpers/webfinger.ts +++ b/server/helpers/webfinger.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as WebFinger from 'webfinger.js' | 1 | import * as WebFinger from 'webfinger.js' |
2 | import { WebFingerData } from '../../shared' | 2 | import { WebFingerData } from '../../shared' |
3 | import { fetchRemoteAccount } from '../lib/activitypub/account' | ||
3 | 4 | ||
4 | import { isTestInstance } from './core-utils' | 5 | import { isTestInstance } from './core-utils' |
5 | import { isActivityPubUrlValid } from './custom-validators' | 6 | import { isActivityPubUrlValid } from './custom-validators' |
6 | import { fetchRemoteAccountAndCreateServer } from '../lib/activitypub/account' | ||
7 | 7 | ||
8 | const webfinger = new WebFinger({ | 8 | const webfinger = new WebFinger({ |
9 | webfist_fallback: false, | 9 | webfist_fallback: false, |
@@ -22,10 +22,10 @@ async function getAccountFromWebfinger (nameWithHost: string) { | |||
22 | throw new Error('Cannot find self link or href is not a valid URL.') | 22 | throw new Error('Cannot find self link or href is not a valid URL.') |
23 | } | 23 | } |
24 | 24 | ||
25 | const res = await fetchRemoteAccountAndCreateServer(selfLink.href) | 25 | const account = await fetchRemoteAccount(selfLink.href) |
26 | if (res === undefined) throw new Error('Cannot fetch and create server of remote account ' + selfLink.href) | 26 | if (account === undefined) throw new Error('Cannot fetch remote account ' + selfLink.href) |
27 | 27 | ||
28 | return res.account | 28 | return account |
29 | } | 29 | } |
30 | 30 | ||
31 | // --------------------------------------------------------------------------- | 31 | // --------------------------------------------------------------------------- |
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts index c46043931..7c0640cc0 100644 --- a/server/initializers/constants.ts +++ b/server/initializers/constants.ts | |||
@@ -323,7 +323,7 @@ const OPENGRAPH_AND_OEMBED_COMMENT = '<!-- open graph and oembed tags -->' | |||
323 | if (isTestInstance() === true) { | 323 | if (isTestInstance() === true) { |
324 | CONSTRAINTS_FIELDS.VIDEOS.DURATION.max = 14 | 324 | CONSTRAINTS_FIELDS.VIDEOS.DURATION.max = 14 |
325 | FRIEND_SCORE.BASE = 20 | 325 | FRIEND_SCORE.BASE = 20 |
326 | JOBS_FETCHING_INTERVAL = 2000 | 326 | JOBS_FETCHING_INTERVAL = 1000 |
327 | REMOTE_SCHEME.HTTP = 'http' | 327 | REMOTE_SCHEME.HTTP = 'http' |
328 | REMOTE_SCHEME.WS = 'ws' | 328 | REMOTE_SCHEME.WS = 'ws' |
329 | STATIC_MAX_AGE = '0' | 329 | STATIC_MAX_AGE = '0' |
diff --git a/server/lib/activitypub/account.ts b/server/lib/activitypub/account.ts index 704a92e13..906c8ff29 100644 --- a/server/lib/activitypub/account.ts +++ b/server/lib/activitypub/account.ts | |||
@@ -1,27 +1,65 @@ | |||
1 | import * as Bluebird from 'bluebird' | ||
1 | import * as url from 'url' | 2 | import * as url from 'url' |
2 | import { ActivityPubActor } from '../../../shared/models/activitypub/activitypub-actor' | 3 | import { ActivityPubActor } from '../../../shared/models/activitypub/activitypub-actor' |
3 | import { isRemoteAccountValid } from '../../helpers/custom-validators/activitypub/account' | 4 | import { isRemoteAccountValid } from '../../helpers/custom-validators/activitypub/account' |
5 | import { retryTransactionWrapper } from '../../helpers/database-utils' | ||
4 | import { logger } from '../../helpers/logger' | 6 | import { logger } from '../../helpers/logger' |
5 | import { doRequest } from '../../helpers/requests' | 7 | import { doRequest } from '../../helpers/requests' |
6 | import { ACTIVITY_PUB } from '../../initializers/constants' | 8 | import { ACTIVITY_PUB } from '../../initializers/constants' |
7 | import { database as db } from '../../initializers/database' | 9 | import { database as db } from '../../initializers/database' |
10 | import { AccountInstance } from '../../models/account/account-interface' | ||
11 | import { Transaction } from 'sequelize' | ||
8 | 12 | ||
9 | async function getOrCreateAccount (accountUrl: string) { | 13 | async function getOrCreateAccountAndServer (accountUrl: string) { |
10 | let account = await db.Account.loadByUrl(accountUrl) | 14 | let account = await db.Account.loadByUrl(accountUrl) |
11 | 15 | ||
12 | // We don't have this account in our database, fetch it on remote | 16 | // We don't have this account in our database, fetch it on remote |
13 | if (!account) { | 17 | if (!account) { |
14 | const res = await fetchRemoteAccountAndCreateServer(accountUrl) | 18 | account = await fetchRemoteAccount(accountUrl) |
15 | if (res === undefined) throw new Error('Cannot fetch remote account.') | 19 | if (account === undefined) throw new Error('Cannot fetch remote account.') |
16 | 20 | ||
17 | // Save our new account in database | 21 | const options = { |
18 | account = await res.account.save() | 22 | arguments: [ account ], |
23 | errorMessage: 'Cannot save account and server with many retries.' | ||
24 | } | ||
25 | account = await retryTransactionWrapper(saveAccountAndServerIfNotExist, options) | ||
19 | } | 26 | } |
20 | 27 | ||
21 | return account | 28 | return account |
22 | } | 29 | } |
23 | 30 | ||
24 | async function fetchRemoteAccountAndCreateServer (accountUrl: string) { | 31 | function saveAccountAndServerIfNotExist (account: AccountInstance, t?: Transaction): Bluebird<AccountInstance> | Promise<AccountInstance> { |
32 | if (t !== undefined) { | ||
33 | return save(t) | ||
34 | } else { | ||
35 | return db.sequelize.transaction(t => { | ||
36 | return save(t) | ||
37 | }) | ||
38 | } | ||
39 | |||
40 | async function save (t: Transaction) { | ||
41 | const accountHost = url.parse(account.url).host | ||
42 | |||
43 | const serverOptions = { | ||
44 | where: { | ||
45 | host: accountHost | ||
46 | }, | ||
47 | defaults: { | ||
48 | host: accountHost | ||
49 | }, | ||
50 | transaction: t | ||
51 | } | ||
52 | const [ server ] = await db.Server.findOrCreate(serverOptions) | ||
53 | |||
54 | // Save our new account in database | ||
55 | account.set('serverId', server.id) | ||
56 | account = await account.save({ transaction: t }) | ||
57 | |||
58 | return account | ||
59 | } | ||
60 | } | ||
61 | |||
62 | async function fetchRemoteAccount (accountUrl: string) { | ||
25 | const options = { | 63 | const options = { |
26 | uri: accountUrl, | 64 | uri: accountUrl, |
27 | method: 'GET', | 65 | method: 'GET', |
@@ -64,24 +102,13 @@ async function fetchRemoteAccountAndCreateServer (accountUrl: string) { | |||
64 | followingUrl: accountJSON.following | 102 | followingUrl: accountJSON.following |
65 | }) | 103 | }) |
66 | 104 | ||
67 | const accountHost = url.parse(account.url).host | 105 | return account |
68 | const serverOptions = { | ||
69 | where: { | ||
70 | host: accountHost | ||
71 | }, | ||
72 | defaults: { | ||
73 | host: accountHost | ||
74 | } | ||
75 | } | ||
76 | const [ server ] = await db.Server.findOrCreate(serverOptions) | ||
77 | account.set('serverId', server.id) | ||
78 | |||
79 | return { account, server } | ||
80 | } | 106 | } |
81 | 107 | ||
82 | export { | 108 | export { |
83 | getOrCreateAccount, | 109 | getOrCreateAccountAndServer, |
84 | fetchRemoteAccountAndCreateServer | 110 | fetchRemoteAccount, |
111 | saveAccountAndServerIfNotExist | ||
85 | } | 112 | } |
86 | 113 | ||
87 | // --------------------------------------------------------------------------- | 114 | // --------------------------------------------------------------------------- |
diff --git a/server/lib/activitypub/process/process-add.ts b/server/lib/activitypub/process/process-add.ts index 281036228..edc90dee5 100644 --- a/server/lib/activitypub/process/process-add.ts +++ b/server/lib/activitypub/process/process-add.ts | |||
@@ -6,7 +6,7 @@ import { logger } from '../../../helpers/logger' | |||
6 | import { database as db } from '../../../initializers' | 6 | import { database as db } from '../../../initializers' |
7 | import { AccountInstance } from '../../../models/account/account-interface' | 7 | import { AccountInstance } from '../../../models/account/account-interface' |
8 | import { VideoChannelInstance } from '../../../models/video/video-channel-interface' | 8 | import { VideoChannelInstance } from '../../../models/video/video-channel-interface' |
9 | import { getOrCreateAccount } from '../account' | 9 | import { getOrCreateAccountAndServer } from '../account' |
10 | import { getOrCreateVideoChannel } from '../video-channels' | 10 | import { getOrCreateVideoChannel } from '../video-channels' |
11 | import { generateThumbnailFromUrl } from '../videos' | 11 | import { generateThumbnailFromUrl } from '../videos' |
12 | import { videoActivityObjectToDBAttributes, videoFileActivityUrlToDBAttributes } from './misc' | 12 | import { videoActivityObjectToDBAttributes, videoFileActivityUrlToDBAttributes } from './misc' |
@@ -14,7 +14,7 @@ import { videoActivityObjectToDBAttributes, videoFileActivityUrlToDBAttributes } | |||
14 | async function processAddActivity (activity: ActivityAdd) { | 14 | async function processAddActivity (activity: ActivityAdd) { |
15 | const activityObject = activity.object | 15 | const activityObject = activity.object |
16 | const activityType = activityObject.type | 16 | const activityType = activityObject.type |
17 | const account = await getOrCreateAccount(activity.actor) | 17 | const account = await getOrCreateAccountAndServer(activity.actor) |
18 | 18 | ||
19 | if (activityType === 'Video') { | 19 | if (activityType === 'Video') { |
20 | const videoChannelUrl = activity.target | 20 | const videoChannelUrl = activity.target |
diff --git a/server/lib/activitypub/process/process-announce.ts b/server/lib/activitypub/process/process-announce.ts index 40712ef03..d8532d3a1 100644 --- a/server/lib/activitypub/process/process-announce.ts +++ b/server/lib/activitypub/process/process-announce.ts | |||
@@ -5,11 +5,11 @@ import { VideoInstance } from '../../../models/index' | |||
5 | import { VideoChannelInstance } from '../../../models/video/video-channel-interface' | 5 | import { VideoChannelInstance } from '../../../models/video/video-channel-interface' |
6 | import { processAddActivity } from './process-add' | 6 | import { processAddActivity } from './process-add' |
7 | import { processCreateActivity } from './process-create' | 7 | import { processCreateActivity } from './process-create' |
8 | import { getOrCreateAccount } from '../account' | 8 | import { getOrCreateAccountAndServer } from '../account' |
9 | 9 | ||
10 | async function processAnnounceActivity (activity: ActivityAnnounce) { | 10 | async function processAnnounceActivity (activity: ActivityAnnounce) { |
11 | const announcedActivity = activity.object | 11 | const announcedActivity = activity.object |
12 | const accountAnnouncer = await getOrCreateAccount(activity.actor) | 12 | const accountAnnouncer = await getOrCreateAccountAndServer(activity.actor) |
13 | 13 | ||
14 | if (announcedActivity.type === 'Create' && announcedActivity.object.type === 'VideoChannel') { | 14 | if (announcedActivity.type === 'Create' && announcedActivity.object.type === 'VideoChannel') { |
15 | // Add share entry | 15 | // Add share entry |
diff --git a/server/lib/activitypub/process/process-create.ts b/server/lib/activitypub/process/process-create.ts index fc635eb1f..ddf7c74f6 100644 --- a/server/lib/activitypub/process/process-create.ts +++ b/server/lib/activitypub/process/process-create.ts | |||
@@ -3,14 +3,14 @@ import { VideoAbuseObject } from '../../../../shared/models/activitypub/objects/ | |||
3 | import { logger, retryTransactionWrapper } from '../../../helpers' | 3 | import { logger, retryTransactionWrapper } from '../../../helpers' |
4 | import { database as db } from '../../../initializers' | 4 | import { database as db } from '../../../initializers' |
5 | import { AccountInstance } from '../../../models/account/account-interface' | 5 | import { AccountInstance } from '../../../models/account/account-interface' |
6 | import { getOrCreateAccount } from '../account' | 6 | import { getOrCreateAccountAndServer } from '../account' |
7 | import { getVideoChannelActivityPubUrl } from '../url' | 7 | import { getVideoChannelActivityPubUrl } from '../url' |
8 | import { videoChannelActivityObjectToDBAttributes } from './misc' | 8 | import { videoChannelActivityObjectToDBAttributes } from './misc' |
9 | 9 | ||
10 | async function processCreateActivity (activity: ActivityCreate) { | 10 | async function processCreateActivity (activity: ActivityCreate) { |
11 | const activityObject = activity.object | 11 | const activityObject = activity.object |
12 | const activityType = activityObject.type | 12 | const activityType = activityObject.type |
13 | const account = await getOrCreateAccount(activity.actor) | 13 | const account = await getOrCreateAccountAndServer(activity.actor) |
14 | 14 | ||
15 | if (activityType === 'VideoChannel') { | 15 | if (activityType === 'VideoChannel') { |
16 | return processCreateVideoChannel(account, activityObject as VideoChannelObject) | 16 | return processCreateVideoChannel(account, activityObject as VideoChannelObject) |
diff --git a/server/lib/activitypub/process/process-delete.ts b/server/lib/activitypub/process/process-delete.ts index 0328d1a7d..41cdc236d 100644 --- a/server/lib/activitypub/process/process-delete.ts +++ b/server/lib/activitypub/process/process-delete.ts | |||
@@ -5,10 +5,10 @@ import { database as db } from '../../../initializers' | |||
5 | import { AccountInstance } from '../../../models/account/account-interface' | 5 | import { AccountInstance } from '../../../models/account/account-interface' |
6 | import { VideoChannelInstance } from '../../../models/video/video-channel-interface' | 6 | import { VideoChannelInstance } from '../../../models/video/video-channel-interface' |
7 | import { VideoInstance } from '../../../models/video/video-interface' | 7 | import { VideoInstance } from '../../../models/video/video-interface' |
8 | import { getOrCreateAccount } from '../account' | 8 | import { getOrCreateAccountAndServer } from '../account' |
9 | 9 | ||
10 | async function processDeleteActivity (activity: ActivityDelete) { | 10 | async function processDeleteActivity (activity: ActivityDelete) { |
11 | const account = await getOrCreateAccount(activity.actor) | 11 | const account = await getOrCreateAccountAndServer(activity.actor) |
12 | 12 | ||
13 | if (account.url === activity.id) { | 13 | if (account.url === activity.id) { |
14 | return processDeleteAccount(account) | 14 | return processDeleteAccount(account) |
diff --git a/server/lib/activitypub/process/process-follow.ts b/server/lib/activitypub/process/process-follow.ts index 41b38828c..248004226 100644 --- a/server/lib/activitypub/process/process-follow.ts +++ b/server/lib/activitypub/process/process-follow.ts | |||
@@ -4,11 +4,11 @@ import { database as db } from '../../../initializers' | |||
4 | import { AccountInstance } from '../../../models/account/account-interface' | 4 | import { AccountInstance } from '../../../models/account/account-interface' |
5 | import { logger } from '../../../helpers/logger' | 5 | import { logger } from '../../../helpers/logger' |
6 | import { sendAccept } from '../send/send-accept' | 6 | import { sendAccept } from '../send/send-accept' |
7 | import { getOrCreateAccount } from '../account' | 7 | import { getOrCreateAccountAndServer } from '../account' |
8 | 8 | ||
9 | async function processFollowActivity (activity: ActivityFollow) { | 9 | async function processFollowActivity (activity: ActivityFollow) { |
10 | const activityObject = activity.object | 10 | const activityObject = activity.object |
11 | const account = await getOrCreateAccount(activity.actor) | 11 | const account = await getOrCreateAccountAndServer(activity.actor) |
12 | 12 | ||
13 | return processFollow(account, activityObject) | 13 | return processFollow(account, activityObject) |
14 | } | 14 | } |
diff --git a/server/lib/activitypub/process/process-update.ts b/server/lib/activitypub/process/process-update.ts index 4876735b8..7caf2ca78 100644 --- a/server/lib/activitypub/process/process-update.ts +++ b/server/lib/activitypub/process/process-update.ts | |||
@@ -8,10 +8,10 @@ import { AccountInstance } from '../../../models/account/account-interface' | |||
8 | import { VideoInstance } from '../../../models/video/video-interface' | 8 | import { VideoInstance } from '../../../models/video/video-interface' |
9 | import { videoActivityObjectToDBAttributes, videoFileActivityUrlToDBAttributes } from './misc' | 9 | import { videoActivityObjectToDBAttributes, videoFileActivityUrlToDBAttributes } from './misc' |
10 | import Bluebird = require('bluebird') | 10 | import Bluebird = require('bluebird') |
11 | import { getOrCreateAccount } from '../account' | 11 | import { getOrCreateAccountAndServer } from '../account' |
12 | 12 | ||
13 | async function processUpdateActivity (activity: ActivityUpdate) { | 13 | async function processUpdateActivity (activity: ActivityUpdate) { |
14 | const account = await getOrCreateAccount(activity.actor) | 14 | const account = await getOrCreateAccountAndServer(activity.actor) |
15 | 15 | ||
16 | if (activity.object.type === 'Video') { | 16 | if (activity.object.type === 'Video') { |
17 | return processUpdateVideo(account, activity.object) | 17 | return processUpdateVideo(account, activity.object) |
diff --git a/server/middlewares/activitypub.ts b/server/middlewares/activitypub.ts index 29bec0c97..061b2dddc 100644 --- a/server/middlewares/activitypub.ts +++ b/server/middlewares/activitypub.ts | |||
@@ -4,7 +4,7 @@ import { ActivityPubSignature } from '../../shared' | |||
4 | import { isSignatureVerified, logger } from '../helpers' | 4 | import { isSignatureVerified, logger } from '../helpers' |
5 | import { database as db } from '../initializers' | 5 | import { database as db } from '../initializers' |
6 | import { ACTIVITY_PUB } from '../initializers/constants' | 6 | import { ACTIVITY_PUB } from '../initializers/constants' |
7 | import { fetchRemoteAccountAndCreateServer } from '../lib/activitypub/account' | 7 | import { fetchRemoteAccount, saveAccountAndServerIfNotExist } from '../lib/activitypub/account' |
8 | 8 | ||
9 | async function checkSignature (req: Request, res: Response, next: NextFunction) { | 9 | async function checkSignature (req: Request, res: Response, next: NextFunction) { |
10 | const signatureObject: ActivityPubSignature = req.body.signature | 10 | const signatureObject: ActivityPubSignature = req.body.signature |
@@ -15,15 +15,14 @@ async function checkSignature (req: Request, res: Response, next: NextFunction) | |||
15 | 15 | ||
16 | // We don't have this account in our database, fetch it on remote | 16 | // We don't have this account in our database, fetch it on remote |
17 | if (!account) { | 17 | if (!account) { |
18 | const accountResult = await fetchRemoteAccountAndCreateServer(signatureObject.creator) | 18 | account = await fetchRemoteAccount(signatureObject.creator) |
19 | 19 | ||
20 | if (!accountResult) { | 20 | if (!account) { |
21 | return res.sendStatus(403) | 21 | return res.sendStatus(403) |
22 | } | 22 | } |
23 | 23 | ||
24 | // Save our new account in database | 24 | // Save our new account and its server in database |
25 | account = accountResult.account | 25 | await saveAccountAndServerIfNotExist(account) |
26 | await account.save() | ||
27 | } | 26 | } |
28 | 27 | ||
29 | const verified = await isSignatureVerified(account, req.body) | 28 | const verified = await isSignatureVerified(account, req.body) |
diff --git a/server/middlewares/validators/follows.ts b/server/middlewares/validators/follows.ts index dfd6e7f03..ddc4c1de1 100644 --- a/server/middlewares/validators/follows.ts +++ b/server/middlewares/validators/follows.ts | |||
@@ -31,19 +31,19 @@ const removeFollowingValidator = [ | |||
31 | param('accountId').custom(isIdOrUUIDValid).withMessage('Should have a valid account id'), | 31 | param('accountId').custom(isIdOrUUIDValid).withMessage('Should have a valid account id'), |
32 | 32 | ||
33 | (req: express.Request, res: express.Response, next: express.NextFunction) => { | 33 | (req: express.Request, res: express.Response, next: express.NextFunction) => { |
34 | logger.debug('Checking follow parameters', { parameters: req.body }) | 34 | logger.debug('Checking unfollow parameters', { parameters: req.params }) |
35 | 35 | ||
36 | checkErrors(req, res, async () => { | 36 | checkErrors(req, res, async () => { |
37 | try { | 37 | try { |
38 | const serverAccount = await getServerAccount() | 38 | const serverAccount = await getServerAccount() |
39 | const following = await db.AccountFollow.loadByAccountAndTarget(serverAccount.id, req.params.accountId) | 39 | const follow = await db.AccountFollow.loadByAccountAndTarget(serverAccount.id, req.params.accountId) |
40 | 40 | ||
41 | if (!following) { | 41 | if (!follow) { |
42 | return res.status(404) | 42 | return res.status(404) |
43 | .end() | 43 | .end() |
44 | } | 44 | } |
45 | 45 | ||
46 | res.locals.following = following | 46 | res.locals.follow = follow |
47 | 47 | ||
48 | return next() | 48 | return next() |
49 | } catch (err) { | 49 | } catch (err) { |
diff --git a/server/tests/api/check-params/follows.ts b/server/tests/api/check-params/follows.ts index a215e7b1a..0af1562f5 100644 --- a/server/tests/api/check-params/follows.ts +++ b/server/tests/api/check-params/follows.ts | |||
@@ -166,47 +166,49 @@ describe('Test server follows API validators', function () { | |||
166 | }) | 166 | }) |
167 | 167 | ||
168 | describe('When removing following', function () { | 168 | describe('When removing following', function () { |
169 | // it('Should fail with an invalid token', async function () { | 169 | const path = '/api/v1/server/following' |
170 | // await request(server.url) | 170 | |
171 | // .delete(path + '/1') | 171 | it('Should fail with an invalid token', async function () { |
172 | // .set('Authorization', 'Bearer faketoken') | 172 | await request(server.url) |
173 | // .set('Accept', 'application/json') | 173 | .delete(path + '/1') |
174 | // .expect(401) | 174 | .set('Authorization', 'Bearer faketoken') |
175 | // }) | 175 | .set('Accept', 'application/json') |
176 | // | 176 | .expect(401) |
177 | // it('Should fail if the user is not an administrator', async function () { | 177 | }) |
178 | // await request(server.url) | 178 | |
179 | // .delete(path + '/1') | 179 | it('Should fail if the user is not an administrator', async function () { |
180 | // .set('Authorization', 'Bearer ' + userAccessToken) | 180 | await request(server.url) |
181 | // .set('Accept', 'application/json') | 181 | .delete(path + '/1') |
182 | // .expect(403) | 182 | .set('Authorization', 'Bearer ' + userAccessToken) |
183 | // }) | 183 | .set('Accept', 'application/json') |
184 | // | 184 | .expect(403) |
185 | // it('Should fail with an undefined id', async function () { | 185 | }) |
186 | // await request(server.url) | 186 | |
187 | // .delete(path + '/' + undefined) | 187 | it('Should fail with an undefined id', async function () { |
188 | // .set('Authorization', 'Bearer ' + server.accessToken) | 188 | await request(server.url) |
189 | // .set('Accept', 'application/json') | 189 | .delete(path + '/' + undefined) |
190 | // .expect(400) | 190 | .set('Authorization', 'Bearer ' + server.accessToken) |
191 | // }) | 191 | .set('Accept', 'application/json') |
192 | // | 192 | .expect(400) |
193 | // it('Should fail with an invalid id', async function () { | 193 | }) |
194 | // await request(server.url) | 194 | |
195 | // .delete(path + '/foobar') | 195 | it('Should fail with an invalid id', async function () { |
196 | // .set('Authorization', 'Bearer ' + server.accessToken) | 196 | await request(server.url) |
197 | // .set('Accept', 'application/json') | 197 | .delete(path + '/foobar') |
198 | // .expect(400) | 198 | .set('Authorization', 'Bearer ' + server.accessToken) |
199 | // }) | 199 | .set('Accept', 'application/json') |
200 | // | 200 | .expect(400) |
201 | // it('Should fail we do not follow this server', async function () { | 201 | }) |
202 | // await request(server.url) | 202 | |
203 | // .delete(path + '/-1') | 203 | it('Should fail we do not follow this server', async function () { |
204 | // .set('Authorization', 'Bearer ' + server.accessToken) | 204 | await request(server.url) |
205 | // .set('Accept', 'application/json') | 205 | .delete(path + '/-1') |
206 | // .expect(404) | 206 | .set('Authorization', 'Bearer ' + server.accessToken) |
207 | // }) | 207 | .set('Accept', 'application/json') |
208 | // | 208 | .expect(404) |
209 | // it('Should succeed with the correct parameters') | 209 | }) |
210 | |||
211 | it('Should succeed with the correct parameters') | ||
210 | }) | 212 | }) |
211 | }) | 213 | }) |
212 | 214 | ||
diff --git a/server/tests/api/follows.ts b/server/tests/api/follows.ts new file mode 100644 index 000000000..b2f53d3a7 --- /dev/null +++ b/server/tests/api/follows.ts | |||
@@ -0,0 +1,174 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | ||
2 | |||
3 | import * as chai from 'chai' | ||
4 | import 'mocha' | ||
5 | |||
6 | import { | ||
7 | flushAndRunMultipleServers, | ||
8 | flushTests, | ||
9 | getVideosList, | ||
10 | killallServers, | ||
11 | ServerInfo, | ||
12 | setAccessTokensToServers, | ||
13 | uploadVideo, | ||
14 | wait | ||
15 | } from '../utils' | ||
16 | import { follow, getFollowersListPaginationAndSort, getFollowingListPaginationAndSort, unfollow } from '../utils/follows' | ||
17 | |||
18 | const expect = chai.expect | ||
19 | |||
20 | describe('Test follows', function () { | ||
21 | let servers: ServerInfo[] = [] | ||
22 | let server3Id: number | ||
23 | |||
24 | before(async function () { | ||
25 | this.timeout(120000) | ||
26 | |||
27 | servers = await flushAndRunMultipleServers(3) | ||
28 | |||
29 | // Get the access tokens | ||
30 | await setAccessTokensToServers(servers) | ||
31 | }) | ||
32 | |||
33 | it('Should not have followers', async function () { | ||
34 | for (const server of servers) { | ||
35 | const res = await getFollowersListPaginationAndSort(server.url, 0, 5, 'createdAt') | ||
36 | const follows = res.body.data | ||
37 | |||
38 | expect(res.body.total).to.equal(0) | ||
39 | expect(follows).to.be.an('array') | ||
40 | expect(follows.length).to.equal(0) | ||
41 | } | ||
42 | }) | ||
43 | |||
44 | it('Should not have following', async function () { | ||
45 | for (const server of servers) { | ||
46 | const res = await getFollowingListPaginationAndSort(server.url, 0, 5, 'createdAt') | ||
47 | const follows = res.body.data | ||
48 | |||
49 | expect(res.body.total).to.equal(0) | ||
50 | expect(follows).to.be.an('array') | ||
51 | expect(follows.length).to.equal(0) | ||
52 | } | ||
53 | }) | ||
54 | |||
55 | it('Should have server 1 following server 2 and 3', async function () { | ||
56 | this.timeout(10000) | ||
57 | |||
58 | await follow(servers[0].url, [ servers[1].url, servers[2].url ], servers[0].accessToken) | ||
59 | |||
60 | await wait(7000) | ||
61 | }) | ||
62 | |||
63 | it('Should have 2 followings on server 1', async function () { | ||
64 | let res = await getFollowingListPaginationAndSort(servers[0].url, 0, 1, 'createdAt') | ||
65 | let follows = res.body.data | ||
66 | |||
67 | expect(res.body.total).to.equal(2) | ||
68 | expect(follows).to.be.an('array') | ||
69 | expect(follows.length).to.equal(1) | ||
70 | |||
71 | res = await getFollowingListPaginationAndSort(servers[0].url, 1, 1, 'createdAt') | ||
72 | follows = follows.concat(res.body.data) | ||
73 | |||
74 | const server2Follow = follows.find(f => f.following.host === 'localhost:9002') | ||
75 | const server3Follow = follows.find(f => f.following.host === 'localhost:9003') | ||
76 | |||
77 | expect(server2Follow).to.not.be.undefined | ||
78 | expect(server3Follow).to.not.be.undefined | ||
79 | expect(server2Follow.state).to.equal('accepted') | ||
80 | expect(server3Follow.state).to.equal('accepted') | ||
81 | |||
82 | server3Id = server3Follow.following.id | ||
83 | }) | ||
84 | |||
85 | it('Should have 0 followings on server 1 and 2', async function () { | ||
86 | for (const server of [ servers[1], servers[2] ]) { | ||
87 | const res = await getFollowingListPaginationAndSort(server.url, 0, 5, 'createdAt') | ||
88 | const follows = res.body.data | ||
89 | |||
90 | expect(res.body.total).to.equal(0) | ||
91 | expect(follows).to.be.an('array') | ||
92 | expect(follows.length).to.equal(0) | ||
93 | } | ||
94 | }) | ||
95 | |||
96 | it('Should have 1 followers on server 2 and 3', async function () { | ||
97 | for (const server of [ servers[1], servers[2] ]) { | ||
98 | let res = await getFollowersListPaginationAndSort(server.url, 0, 1, 'createdAt') | ||
99 | |||
100 | let follows = res.body.data | ||
101 | expect(res.body.total).to.equal(1) | ||
102 | expect(follows).to.be.an('array') | ||
103 | expect(follows.length).to.equal(1) | ||
104 | expect(follows[0].follower.host).to.equal('localhost:9001') | ||
105 | } | ||
106 | }) | ||
107 | |||
108 | it('Should have 0 followers on server 1', async function () { | ||
109 | const res = await getFollowersListPaginationAndSort(servers[0].url, 0, 5, 'createdAt') | ||
110 | const follows = res.body.data | ||
111 | |||
112 | expect(res.body.total).to.equal(0) | ||
113 | expect(follows).to.be.an('array') | ||
114 | expect(follows.length).to.equal(0) | ||
115 | }) | ||
116 | |||
117 | it('Should unfollow server 3 on server 1', async function () { | ||
118 | this.timeout(5000) | ||
119 | |||
120 | await unfollow(servers[0].url, servers[0].accessToken, server3Id) | ||
121 | |||
122 | await wait(3000) | ||
123 | }) | ||
124 | |||
125 | it('Should not follow server 3 on server 1 anymore', async function () { | ||
126 | const res = await getFollowingListPaginationAndSort(servers[0].url, 0, 2, 'createdAt') | ||
127 | let follows = res.body.data | ||
128 | |||
129 | expect(res.body.total).to.equal(1) | ||
130 | expect(follows).to.be.an('array') | ||
131 | expect(follows.length).to.equal(1) | ||
132 | |||
133 | expect(follows[0].following.host).to.equal('localhost:9002') | ||
134 | }) | ||
135 | |||
136 | it('Should not have server 1 as follower on server 3 anymore', async function () { | ||
137 | const res = await getFollowersListPaginationAndSort(servers[2].url, 0, 1, 'createdAt') | ||
138 | |||
139 | let follows = res.body.data | ||
140 | expect(res.body.total).to.equal(0) | ||
141 | expect(follows).to.be.an('array') | ||
142 | expect(follows.length).to.equal(0) | ||
143 | }) | ||
144 | |||
145 | it('Should upload a video on server 2 ans 3 and propagate only the video of server 2', async function () { | ||
146 | this.timeout(10000) | ||
147 | |||
148 | await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'server2' }) | ||
149 | await uploadVideo(servers[2].url, servers[2].accessToken, { name: 'server3' }) | ||
150 | |||
151 | await wait(5000) | ||
152 | |||
153 | let res = await getVideosList(servers[0].url) | ||
154 | expect(res.body.total).to.equal(1) | ||
155 | expect(res.body.data[0].name).to.equal('server2') | ||
156 | |||
157 | res = await getVideosList(servers[1].url) | ||
158 | expect(res.body.total).to.equal(1) | ||
159 | expect(res.body.data[0].name).to.equal('server2') | ||
160 | |||
161 | res = await getVideosList(servers[2].url) | ||
162 | expect(res.body.total).to.equal(1) | ||
163 | expect(res.body.data[0].name).to.equal('server3') | ||
164 | }) | ||
165 | |||
166 | after(async function () { | ||
167 | killallServers(servers) | ||
168 | |||
169 | // Keep the logs if the test failed | ||
170 | if (this['ok']) { | ||
171 | await flushTests() | ||
172 | } | ||
173 | }) | ||
174 | }) | ||
diff --git a/server/tests/api/index-slow.ts b/server/tests/api/index-slow.ts index b3c3d778c..da56398b1 100644 --- a/server/tests/api/index-slow.ts +++ b/server/tests/api/index-slow.ts | |||
@@ -1,3 +1,4 @@ | |||
1 | // Order of the tests we want to execute | 1 | // Order of the tests we want to execute |
2 | // import './multiple-servers' | 2 | // import './multiple-servers' |
3 | import './video-transcoder' | 3 | import './video-transcoder' |
4 | import './follows' | ||
diff --git a/server/tests/cli/reset-password.ts b/server/tests/cli/reset-password.ts index c75a1611c..98ea7d456 100644 --- a/server/tests/cli/reset-password.ts +++ b/server/tests/cli/reset-password.ts | |||
@@ -26,7 +26,7 @@ describe('Test reset password scripts', function () { | |||
26 | }) | 26 | }) |
27 | 27 | ||
28 | it('Should change the user password from CLI', async function () { | 28 | it('Should change the user password from CLI', async function () { |
29 | this.timeout(30000) | 29 | this.timeout(60000) |
30 | 30 | ||
31 | const env = getEnvCli(server) | 31 | const env = getEnvCli(server) |
32 | await execCLI(`echo coucou | ${env} npm run reset-password -- -u user_1`) | 32 | await execCLI(`echo coucou | ${env} npm run reset-password -- -u user_1`) |
diff --git a/server/tests/real-world/real-world.ts b/server/tests/real-world/real-world.ts index ac83d64a6..1afa55267 100644 --- a/server/tests/real-world/real-world.ts +++ b/server/tests/real-world/real-world.ts | |||
@@ -1,373 +1,372 @@ | |||
1 | // /!\ Before imports /!\ | 1 | // // /!\ Before imports /!\ |
2 | process.env.NODE_ENV = 'test' | 2 | // process.env.NODE_ENV = 'test' |
3 | 3 | // | |
4 | import * as program from 'commander' | 4 | // import * as program from 'commander' |
5 | import { Video, VideoFile, VideoRateType } from '../../../shared' | 5 | // import { Video, VideoFile, VideoRateType } from '../../../shared' |
6 | import { | 6 | // import { |
7 | flushAndRunMultipleServers, | 7 | // flushAndRunMultipleServers, |
8 | flushTests, | 8 | // flushTests, |
9 | getAllVideosListBy, | 9 | // getAllVideosListBy, |
10 | getRequestsStats, | 10 | // getVideo, |
11 | getVideo, | 11 | // getVideosList, |
12 | getVideosList, | 12 | // killallServers, |
13 | killallServers, | 13 | // removeVideo, |
14 | removeVideo, | 14 | // ServerInfo as DefaultServerInfo, |
15 | ServerInfo as DefaultServerInfo, | 15 | // setAccessTokensToServers, |
16 | setAccessTokensToServers, | 16 | // updateVideo, |
17 | updateVideo, | 17 | // uploadVideo, |
18 | uploadVideo, | 18 | // wait |
19 | wait | 19 | // } from '../utils' |
20 | } from '../utils' | 20 | // import { follow } from '../utils/follows' |
21 | import { follow } from '../utils/follows' | 21 | // |
22 | 22 | // interface ServerInfo extends DefaultServerInfo { | |
23 | interface ServerInfo extends DefaultServerInfo { | 23 | // requestsNumber: number |
24 | requestsNumber: number | 24 | // } |
25 | } | 25 | // |
26 | 26 | // program | |
27 | program | 27 | // .option('-c, --create [weight]', 'Weight for creating videos') |
28 | .option('-c, --create [weight]', 'Weight for creating videos') | 28 | // .option('-r, --remove [weight]', 'Weight for removing videos') |
29 | .option('-r, --remove [weight]', 'Weight for removing videos') | 29 | // .option('-u, --update [weight]', 'Weight for updating videos') |
30 | .option('-u, --update [weight]', 'Weight for updating videos') | 30 | // .option('-v, --view [weight]', 'Weight for viewing videos') |
31 | .option('-v, --view [weight]', 'Weight for viewing videos') | 31 | // .option('-l, --like [weight]', 'Weight for liking videos') |
32 | .option('-l, --like [weight]', 'Weight for liking videos') | 32 | // .option('-s, --dislike [weight]', 'Weight for disliking videos') |
33 | .option('-s, --dislike [weight]', 'Weight for disliking videos') | 33 | // .option('-p, --servers [n]', 'Number of servers to run (3 or 6)', /^3|6$/, 3) |
34 | .option('-p, --servers [n]', 'Number of servers to run (3 or 6)', /^3|6$/, 3) | 34 | // .option('-i, --interval-action [interval]', 'Interval in ms for an action') |
35 | .option('-i, --interval-action [interval]', 'Interval in ms for an action') | 35 | // .option('-I, --interval-integrity [interval]', 'Interval in ms for an integrity check') |
36 | .option('-I, --interval-integrity [interval]', 'Interval in ms for an integrity check') | 36 | // .option('-f, --flush', 'Flush datas on exit') |
37 | .option('-f, --flush', 'Flush datas on exit') | 37 | // .option('-d, --difference', 'Display difference if integrity is not okay') |
38 | .option('-d, --difference', 'Display difference if integrity is not okay') | 38 | // .parse(process.argv) |
39 | .parse(process.argv) | 39 | // |
40 | 40 | // const createWeight = program['create'] !== undefined ? parseInt(program['create'], 10) : 5 | |
41 | const createWeight = program['create'] !== undefined ? parseInt(program['create'], 10) : 5 | 41 | // const removeWeight = program['remove'] !== undefined ? parseInt(program['remove'], 10) : 4 |
42 | const removeWeight = program['remove'] !== undefined ? parseInt(program['remove'], 10) : 4 | 42 | // const updateWeight = program['update'] !== undefined ? parseInt(program['update'], 10) : 4 |
43 | const updateWeight = program['update'] !== undefined ? parseInt(program['update'], 10) : 4 | 43 | // const viewWeight = program['view'] !== undefined ? parseInt(program['view'], 10) : 4 |
44 | const viewWeight = program['view'] !== undefined ? parseInt(program['view'], 10) : 4 | 44 | // const likeWeight = program['like'] !== undefined ? parseInt(program['like'], 10) : 4 |
45 | const likeWeight = program['like'] !== undefined ? parseInt(program['like'], 10) : 4 | 45 | // const dislikeWeight = program['dislike'] !== undefined ? parseInt(program['dislike'], 10) : 4 |
46 | const dislikeWeight = program['dislike'] !== undefined ? parseInt(program['dislike'], 10) : 4 | 46 | // const flushAtExit = program['flush'] || false |
47 | const flushAtExit = program['flush'] || false | 47 | // const actionInterval = program['intervalAction'] !== undefined ? parseInt(program['intervalAction'], 10) : 500 |
48 | const actionInterval = program['intervalAction'] !== undefined ? parseInt(program['intervalAction'], 10) : 500 | 48 | // const integrityInterval = program['intervalIntegrity'] !== undefined ? parseInt(program['intervalIntegrity'], 10) : 60000 |
49 | const integrityInterval = program['intervalIntegrity'] !== undefined ? parseInt(program['intervalIntegrity'], 10) : 60000 | 49 | // const displayDiffOnFail = program['difference'] || false |
50 | const displayDiffOnFail = program['difference'] || false | 50 | // |
51 | 51 | // const numberOfServers = 6 | |
52 | const numberOfServers = 6 | 52 | // |
53 | 53 | // console.log( | |
54 | console.log( | 54 | // 'Create weight: %d, update weight: %d, remove weight: %d, view weight: %d, like weight: %d, dislike weight: %d.', |
55 | 'Create weight: %d, update weight: %d, remove weight: %d, view weight: %d, like weight: %d, dislike weight: %d.', | 55 | // createWeight, updateWeight, removeWeight, viewWeight, likeWeight, dislikeWeight |
56 | createWeight, updateWeight, removeWeight, viewWeight, likeWeight, dislikeWeight | 56 | // ) |
57 | ) | 57 | // |
58 | 58 | // if (flushAtExit) { | |
59 | if (flushAtExit) { | 59 | // console.log('Program will flush data on exit.') |
60 | console.log('Program will flush data on exit.') | 60 | // } else { |
61 | } else { | 61 | // console.log('Program will not flush data on exit.') |
62 | console.log('Program will not flush data on exit.') | 62 | // } |
63 | } | 63 | // if (displayDiffOnFail) { |
64 | if (displayDiffOnFail) { | 64 | // console.log('Program will display diff on failure.') |
65 | console.log('Program will display diff on failure.') | 65 | // } else { |
66 | } else { | 66 | // console.log('Program will not display diff on failure') |
67 | console.log('Program will not display diff on failure') | 67 | // } |
68 | } | 68 | // console.log('Interval in ms for each action: %d.', actionInterval) |
69 | console.log('Interval in ms for each action: %d.', actionInterval) | 69 | // console.log('Interval in ms for each integrity check: %d.', integrityInterval) |
70 | console.log('Interval in ms for each integrity check: %d.', integrityInterval) | 70 | // |
71 | 71 | // console.log('Run servers...') | |
72 | console.log('Run servers...') | 72 | // |
73 | 73 | // start() | |
74 | start() | 74 | // |
75 | 75 | // // ---------------------------------------------------------------------------- | |
76 | // ---------------------------------------------------------------------------- | 76 | // |
77 | 77 | // async function start () { | |
78 | async function start () { | 78 | // const servers = await runServers(numberOfServers) |
79 | const servers = await runServers(numberOfServers) | 79 | // |
80 | 80 | // process.on('exit', async () => { | |
81 | process.on('exit', async () => { | 81 | // await exitServers(servers, flushAtExit) |
82 | await exitServers(servers, flushAtExit) | 82 | // |
83 | 83 | // return | |
84 | return | 84 | // }) |
85 | }) | 85 | // process.on('SIGINT', goodbye) |
86 | process.on('SIGINT', goodbye) | 86 | // process.on('SIGTERM', goodbye) |
87 | process.on('SIGTERM', goodbye) | 87 | // |
88 | 88 | // console.log('Servers ran') | |
89 | console.log('Servers ran') | 89 | // initializeRequestsPerServer(servers) |
90 | initializeRequestsPerServer(servers) | 90 | // |
91 | 91 | // let checking = false | |
92 | let checking = false | 92 | // |
93 | 93 | // setInterval(async () => { | |
94 | setInterval(async () => { | 94 | // if (checking === true) return |
95 | if (checking === true) return | 95 | // |
96 | 96 | // const rand = getRandomInt(0, createWeight + updateWeight + removeWeight + viewWeight + likeWeight + dislikeWeight) | |
97 | const rand = getRandomInt(0, createWeight + updateWeight + removeWeight + viewWeight + likeWeight + dislikeWeight) | 97 | // |
98 | 98 | // const numServer = getRandomNumServer(servers) | |
99 | const numServer = getRandomNumServer(servers) | 99 | // servers[numServer].requestsNumber++ |
100 | servers[numServer].requestsNumber++ | 100 | // |
101 | 101 | // if (rand < createWeight) { | |
102 | if (rand < createWeight) { | 102 | // await upload(servers, numServer) |
103 | await upload(servers, numServer) | 103 | // } else if (rand < createWeight + updateWeight) { |
104 | } else if (rand < createWeight + updateWeight) { | 104 | // await update(servers, numServer) |
105 | await update(servers, numServer) | 105 | // } else if (rand < createWeight + updateWeight + removeWeight) { |
106 | } else if (rand < createWeight + updateWeight + removeWeight) { | 106 | // await remove(servers, numServer) |
107 | await remove(servers, numServer) | 107 | // } else if (rand < createWeight + updateWeight + removeWeight + viewWeight) { |
108 | } else if (rand < createWeight + updateWeight + removeWeight + viewWeight) { | 108 | // await view(servers, numServer) |
109 | await view(servers, numServer) | 109 | // } else if (rand < createWeight + updateWeight + removeWeight + viewWeight + likeWeight) { |
110 | } else if (rand < createWeight + updateWeight + removeWeight + viewWeight + likeWeight) { | 110 | // await like(servers, numServer) |
111 | await like(servers, numServer) | 111 | // } else { |
112 | } else { | 112 | // await dislike(servers, numServer) |
113 | await dislike(servers, numServer) | 113 | // } |
114 | } | 114 | // }, actionInterval) |
115 | }, actionInterval) | 115 | // |
116 | 116 | // // The function will check the consistency between servers (should have the same videos with same attributes...) | |
117 | // The function will check the consistency between servers (should have the same videos with same attributes...) | 117 | // setInterval(function () { |
118 | setInterval(function () { | 118 | // if (checking === true) return |
119 | if (checking === true) return | 119 | // |
120 | 120 | // console.log('Checking integrity...') | |
121 | console.log('Checking integrity...') | 121 | // checking = true |
122 | checking = true | 122 | // |
123 | 123 | // const waitingInterval = setInterval(async () => { | |
124 | const waitingInterval = setInterval(async () => { | 124 | // const pendingRequests = await isTherePendingRequests(servers) |
125 | const pendingRequests = await isTherePendingRequests(servers) | 125 | // if (pendingRequests === true) { |
126 | if (pendingRequests === true) { | 126 | // console.log('A server has pending requests, waiting...') |
127 | console.log('A server has pending requests, waiting...') | 127 | // return |
128 | return | 128 | // } |
129 | } | 129 | // |
130 | 130 | // // Even if there are no pending request, wait some potential processes | |
131 | // Even if there are no pending request, wait some potential processes | 131 | // await wait(2000) |
132 | await wait(2000) | 132 | // await checkIntegrity(servers) |
133 | await checkIntegrity(servers) | 133 | // |
134 | 134 | // initializeRequestsPerServer(servers) | |
135 | initializeRequestsPerServer(servers) | 135 | // checking = false |
136 | checking = false | 136 | // clearInterval(waitingInterval) |
137 | clearInterval(waitingInterval) | 137 | // }, 10000) |
138 | }, 10000) | 138 | // }, integrityInterval) |
139 | }, integrityInterval) | 139 | // } |
140 | } | 140 | // |
141 | 141 | // function initializeRequestsPerServer (servers: ServerInfo[]) { | |
142 | function initializeRequestsPerServer (servers: ServerInfo[]) { | 142 | // servers.forEach(server => server.requestsNumber = 0) |
143 | servers.forEach(server => server.requestsNumber = 0) | 143 | // } |
144 | } | 144 | // |
145 | 145 | // function getRandomInt (min, max) { | |
146 | function getRandomInt (min, max) { | 146 | // return Math.floor(Math.random() * (max - min)) + min |
147 | return Math.floor(Math.random() * (max - min)) + min | 147 | // } |
148 | } | 148 | // |
149 | 149 | // function getRandomNumServer (servers) { | |
150 | function getRandomNumServer (servers) { | 150 | // return getRandomInt(0, servers.length) |
151 | return getRandomInt(0, servers.length) | 151 | // } |
152 | } | 152 | // |
153 | 153 | // async function runServers (numberOfServers: number) { | |
154 | async function runServers (numberOfServers: number) { | 154 | // const servers: ServerInfo[] = (await flushAndRunMultipleServers(numberOfServers)) |
155 | const servers: ServerInfo[] = (await flushAndRunMultipleServers(numberOfServers)) | 155 | // .map(s => Object.assign({ requestsNumber: 0 }, s)) |
156 | .map(s => Object.assign({ requestsNumber: 0 }, s)) | 156 | // |
157 | 157 | // // Get the access tokens | |
158 | // Get the access tokens | 158 | // await setAccessTokensToServers(servers) |
159 | await setAccessTokensToServers(servers) | 159 | // |
160 | 160 | // for (let i = 0; i < numberOfServers; i++) { | |
161 | for (let i = 0; i < numberOfServers; i++) { | 161 | // for (let j = 0; j < numberOfServers; j++) { |
162 | for (let j = 0; j < numberOfServers; j++) { | 162 | // if (i === j) continue |
163 | if (i === j) continue | 163 | // |
164 | 164 | // await follow(servers[i].url, [ servers[j].url ], servers[i].accessToken) | |
165 | await follow(servers[i].url, [ servers[j].url ], servers[i].accessToken) | 165 | // } |
166 | } | 166 | // } |
167 | } | 167 | // |
168 | 168 | // return servers | |
169 | return servers | 169 | // } |
170 | } | 170 | // |
171 | 171 | // async function exitServers (servers: ServerInfo[], flushAtExit: boolean) { | |
172 | async function exitServers (servers: ServerInfo[], flushAtExit: boolean) { | 172 | // killallServers(servers) |
173 | killallServers(servers) | 173 | // |
174 | 174 | // if (flushAtExit) await flushTests() | |
175 | if (flushAtExit) await flushTests() | 175 | // } |
176 | } | 176 | // |
177 | 177 | // function upload (servers: ServerInfo[], numServer: number) { | |
178 | function upload (servers: ServerInfo[], numServer: number) { | 178 | // console.log('Uploading video to server ' + numServer) |
179 | console.log('Uploading video to server ' + numServer) | 179 | // |
180 | 180 | // const videoAttributes = { | |
181 | const videoAttributes = { | 181 | // name: Date.now() + ' name', |
182 | name: Date.now() + ' name', | 182 | // category: 4, |
183 | category: 4, | 183 | // nsfw: false, |
184 | nsfw: false, | 184 | // licence: 2, |
185 | licence: 2, | 185 | // language: 1, |
186 | language: 1, | 186 | // description: Date.now() + ' description', |
187 | description: Date.now() + ' description', | 187 | // tags: [ Date.now().toString().substring(0, 5) + 't1', Date.now().toString().substring(0, 5) + 't2' ], |
188 | tags: [ Date.now().toString().substring(0, 5) + 't1', Date.now().toString().substring(0, 5) + 't2' ], | 188 | // fixture: 'video_short1.webm' |
189 | fixture: 'video_short1.webm' | 189 | // } |
190 | } | 190 | // return uploadVideo(servers[numServer].url, servers[numServer].accessToken, videoAttributes) |
191 | return uploadVideo(servers[numServer].url, servers[numServer].accessToken, videoAttributes) | 191 | // } |
192 | } | 192 | // |
193 | 193 | // async function update (servers: ServerInfo[], numServer: number) { | |
194 | async function update (servers: ServerInfo[], numServer: number) { | 194 | // const res = await getVideosList(servers[numServer].url) |
195 | const res = await getVideosList(servers[numServer].url) | 195 | // |
196 | 196 | // const videos = res.body.data.filter(video => video.isLocal === true) | |
197 | const videos = res.body.data.filter(video => video.isLocal === true) | 197 | // if (videos.length === 0) return undefined |
198 | if (videos.length === 0) return undefined | 198 | // |
199 | 199 | // const toUpdate = videos[getRandomInt(0, videos.length)].id | |
200 | const toUpdate = videos[getRandomInt(0, videos.length)].id | 200 | // const attributes = { |
201 | const attributes = { | 201 | // name: Date.now() + ' name', |
202 | name: Date.now() + ' name', | 202 | // description: Date.now() + ' description', |
203 | description: Date.now() + ' description', | 203 | // tags: [ Date.now().toString().substring(0, 5) + 't1', Date.now().toString().substring(0, 5) + 't2' ] |
204 | tags: [ Date.now().toString().substring(0, 5) + 't1', Date.now().toString().substring(0, 5) + 't2' ] | 204 | // } |
205 | } | 205 | // |
206 | 206 | // console.log('Updating video of server ' + numServer) | |
207 | console.log('Updating video of server ' + numServer) | 207 | // |
208 | 208 | // return updateVideo(servers[numServer].url, servers[numServer].accessToken, toUpdate, attributes) | |
209 | return updateVideo(servers[numServer].url, servers[numServer].accessToken, toUpdate, attributes) | 209 | // } |
210 | } | 210 | // |
211 | 211 | // async function remove (servers: ServerInfo[], numServer: number) { | |
212 | async function remove (servers: ServerInfo[], numServer: number) { | 212 | // const res = await getVideosList(servers[numServer].url) |
213 | const res = await getVideosList(servers[numServer].url) | 213 | // const videos = res.body.data.filter(video => video.isLocal === true) |
214 | const videos = res.body.data.filter(video => video.isLocal === true) | 214 | // if (videos.length === 0) return undefined |
215 | if (videos.length === 0) return undefined | 215 | // |
216 | 216 | // const toRemove = videos[getRandomInt(0, videos.length)].id | |
217 | const toRemove = videos[getRandomInt(0, videos.length)].id | 217 | // |
218 | 218 | // console.log('Removing video from server ' + numServer) | |
219 | console.log('Removing video from server ' + numServer) | 219 | // return removeVideo(servers[numServer].url, servers[numServer].accessToken, toRemove) |
220 | return removeVideo(servers[numServer].url, servers[numServer].accessToken, toRemove) | 220 | // } |
221 | } | 221 | // |
222 | 222 | // async function view (servers: ServerInfo[], numServer: number) { | |
223 | async function view (servers: ServerInfo[], numServer: number) { | 223 | // const res = await getVideosList(servers[numServer].url) |
224 | const res = await getVideosList(servers[numServer].url) | 224 | // |
225 | 225 | // const videos = res.body.data | |
226 | const videos = res.body.data | 226 | // if (videos.length === 0) return undefined |
227 | if (videos.length === 0) return undefined | 227 | // |
228 | 228 | // const toView = videos[getRandomInt(0, videos.length)].id | |
229 | const toView = videos[getRandomInt(0, videos.length)].id | 229 | // |
230 | 230 | // console.log('Viewing video from server ' + numServer) | |
231 | console.log('Viewing video from server ' + numServer) | 231 | // return getVideo(servers[numServer].url, toView) |
232 | return getVideo(servers[numServer].url, toView) | 232 | // } |
233 | } | 233 | // |
234 | 234 | // function like (servers: ServerInfo[], numServer: number) { | |
235 | function like (servers: ServerInfo[], numServer: number) { | 235 | // return rate(servers, numServer, 'like') |
236 | return rate(servers, numServer, 'like') | 236 | // } |
237 | } | 237 | // |
238 | 238 | // function dislike (servers: ServerInfo[], numServer: number) { | |
239 | function dislike (servers: ServerInfo[], numServer: number) { | 239 | // return rate(servers, numServer, 'dislike') |
240 | return rate(servers, numServer, 'dislike') | 240 | // } |
241 | } | 241 | // |
242 | 242 | // async function rate (servers: ServerInfo[], numServer: number, rating: VideoRateType) { | |
243 | async function rate (servers: ServerInfo[], numServer: number, rating: VideoRateType) { | 243 | // const res = await getVideosList(servers[numServer].url) |
244 | const res = await getVideosList(servers[numServer].url) | 244 | // |
245 | 245 | // const videos = res.body.data | |
246 | const videos = res.body.data | 246 | // if (videos.length === 0) return undefined |
247 | if (videos.length === 0) return undefined | 247 | // |
248 | 248 | // const toRate = videos[getRandomInt(0, videos.length)].id | |
249 | const toRate = videos[getRandomInt(0, videos.length)].id | 249 | // |
250 | 250 | // console.log('Rating (%s) video from server %d', rating, numServer) | |
251 | console.log('Rating (%s) video from server %d', rating, numServer) | 251 | // return getVideo(servers[numServer].url, toRate) |
252 | return getVideo(servers[numServer].url, toRate) | 252 | // } |
253 | } | 253 | // |
254 | 254 | // async function checkIntegrity (servers: ServerInfo[]) { | |
255 | async function checkIntegrity (servers: ServerInfo[]) { | 255 | // const videos: Video[][] = [] |
256 | const videos: Video[][] = [] | 256 | // const tasks: Promise<any>[] = [] |
257 | const tasks: Promise<any>[] = [] | 257 | // |
258 | 258 | // // Fetch all videos and remove some fields that can differ between servers | |
259 | // Fetch all videos and remove some fields that can differ between servers | 259 | // for (const server of servers) { |
260 | for (const server of servers) { | 260 | // const p = getAllVideosListBy(server.url).then(res => videos.push(res.body.data)) |
261 | const p = getAllVideosListBy(server.url).then(res => videos.push(res.body.data)) | 261 | // tasks.push(p) |
262 | tasks.push(p) | 262 | // } |
263 | } | 263 | // |
264 | 264 | // await Promise.all(tasks) | |
265 | await Promise.all(tasks) | 265 | // |
266 | 266 | // let i = 0 | |
267 | let i = 0 | 267 | // for (const video of videos) { |
268 | for (const video of videos) { | 268 | // const differences = areDifferences(video, videos[0]) |
269 | const differences = areDifferences(video, videos[0]) | 269 | // if (differences !== undefined) { |
270 | if (differences !== undefined) { | 270 | // console.error('Integrity not ok with server %d!', i + 1) |
271 | console.error('Integrity not ok with server %d!', i + 1) | 271 | // |
272 | 272 | // if (displayDiffOnFail) { | |
273 | if (displayDiffOnFail) { | 273 | // console.log(differences) |
274 | console.log(differences) | 274 | // } |
275 | } | 275 | // |
276 | 276 | // process.exit(-1) | |
277 | process.exit(-1) | 277 | // } |
278 | } | 278 | // |
279 | 279 | // i++ | |
280 | i++ | 280 | // } |
281 | } | 281 | // |
282 | 282 | // console.log('Integrity ok.') | |
283 | console.log('Integrity ok.') | 283 | // } |
284 | } | 284 | // |
285 | 285 | // function areDifferences (videos1: Video[], videos2: Video[]) { | |
286 | function areDifferences (videos1: Video[], videos2: Video[]) { | 286 | // // Remove some keys we don't want to compare |
287 | // Remove some keys we don't want to compare | 287 | // videos1.concat(videos2).forEach(video => { |
288 | videos1.concat(videos2).forEach(video => { | 288 | // delete video.id |
289 | delete video.id | 289 | // delete video.isLocal |
290 | delete video.isLocal | 290 | // delete video.thumbnailPath |
291 | delete video.thumbnailPath | 291 | // delete video.updatedAt |
292 | delete video.updatedAt | 292 | // delete video.views |
293 | delete video.views | 293 | // }) |
294 | }) | 294 | // |
295 | 295 | // if (videos1.length !== videos2.length) { | |
296 | if (videos1.length !== videos2.length) { | 296 | // return `Videos length are different (${videos1.length}/${videos2.length}).` |
297 | return `Videos length are different (${videos1.length}/${videos2.length}).` | 297 | // } |
298 | } | 298 | // |
299 | 299 | // for (const video1 of videos1) { | |
300 | for (const video1 of videos1) { | 300 | // const video2 = videos2.find(video => video.uuid === video1.uuid) |
301 | const video2 = videos2.find(video => video.uuid === video1.uuid) | 301 | // |
302 | 302 | // if (!video2) return 'Video ' + video1.uuid + ' is missing.' | |
303 | if (!video2) return 'Video ' + video1.uuid + ' is missing.' | 303 | // |
304 | 304 | // for (const videoKey of Object.keys(video1)) { | |
305 | for (const videoKey of Object.keys(video1)) { | 305 | // const attribute1 = video1[videoKey] |
306 | const attribute1 = video1[videoKey] | 306 | // const attribute2 = video2[videoKey] |
307 | const attribute2 = video2[videoKey] | 307 | // |
308 | 308 | // if (videoKey === 'tags') { | |
309 | if (videoKey === 'tags') { | 309 | // if (attribute1.length !== attribute2.length) { |
310 | if (attribute1.length !== attribute2.length) { | 310 | // return 'Tags are different.' |
311 | return 'Tags are different.' | 311 | // } |
312 | } | 312 | // |
313 | 313 | // attribute1.forEach(tag1 => { | |
314 | attribute1.forEach(tag1 => { | 314 | // if (attribute2.indexOf(tag1) === -1) { |
315 | if (attribute2.indexOf(tag1) === -1) { | 315 | // return 'Tag ' + tag1 + ' is missing.' |
316 | return 'Tag ' + tag1 + ' is missing.' | 316 | // } |
317 | } | 317 | // }) |
318 | }) | 318 | // } else if (videoKey === 'files') { |
319 | } else if (videoKey === 'files') { | 319 | // if (attribute1.length !== attribute2.length) { |
320 | if (attribute1.length !== attribute2.length) { | 320 | // return 'Video files are different.' |
321 | return 'Video files are different.' | 321 | // } |
322 | } | 322 | // |
323 | 323 | // attribute1.forEach((videoFile1: VideoFile) => { | |
324 | attribute1.forEach((videoFile1: VideoFile) => { | 324 | // const videoFile2: VideoFile = attribute2.find(videoFile => videoFile.magnetUri === videoFile1.magnetUri) |
325 | const videoFile2: VideoFile = attribute2.find(videoFile => videoFile.magnetUri === videoFile1.magnetUri) | 325 | // if (!videoFile2) { |
326 | if (!videoFile2) { | 326 | // return `Video ${video1.uuid} has missing video file ${videoFile1.magnetUri}.` |
327 | return `Video ${video1.uuid} has missing video file ${videoFile1.magnetUri}.` | 327 | // } |
328 | } | 328 | // |
329 | 329 | // if (videoFile1.size !== videoFile2.size || videoFile1.resolutionLabel !== videoFile2.resolutionLabel) { | |
330 | if (videoFile1.size !== videoFile2.size || videoFile1.resolutionLabel !== videoFile2.resolutionLabel) { | 330 | // return `Video ${video1.uuid} has different video file ${videoFile1.magnetUri}.` |
331 | return `Video ${video1.uuid} has different video file ${videoFile1.magnetUri}.` | 331 | // } |
332 | } | 332 | // }) |
333 | }) | 333 | // } else { |
334 | } else { | 334 | // if (attribute1 !== attribute2) { |
335 | if (attribute1 !== attribute2) { | 335 | // return `Video ${video1.uuid} has different value for attribute ${videoKey}.` |
336 | return `Video ${video1.uuid} has different value for attribute ${videoKey}.` | 336 | // } |
337 | } | 337 | // } |
338 | } | 338 | // } |
339 | } | 339 | // } |
340 | } | 340 | // |
341 | 341 | // return undefined | |
342 | return undefined | 342 | // } |
343 | } | 343 | // |
344 | 344 | // function goodbye () { | |
345 | function goodbye () { | 345 | // return process.exit(-1) |
346 | return process.exit(-1) | 346 | // } |
347 | } | 347 | // |
348 | 348 | // async function isTherePendingRequests (servers: ServerInfo[]) { | |
349 | async function isTherePendingRequests (servers: ServerInfo[]) { | 349 | // const tasks: Promise<any>[] = [] |
350 | const tasks: Promise<any>[] = [] | 350 | // let pendingRequests = false |
351 | let pendingRequests = false | 351 | // |
352 | 352 | // // Check if each server has pending request | |
353 | // Check if each server has pending request | 353 | // for (const server of servers) { |
354 | for (const server of servers) { | 354 | // const p = getRequestsStats(server).then(res => { |
355 | const p = getRequestsStats(server).then(res => { | 355 | // const stats = res.body |
356 | const stats = res.body | 356 | // |
357 | 357 | // if ( | |
358 | if ( | 358 | // stats.requestScheduler.totalRequests !== 0 || |
359 | stats.requestScheduler.totalRequests !== 0 || | 359 | // stats.requestVideoEventScheduler.totalRequests !== 0 || |
360 | stats.requestVideoEventScheduler.totalRequests !== 0 || | 360 | // stats.requestVideoQaduScheduler.totalRequests !== 0 |
361 | stats.requestVideoQaduScheduler.totalRequests !== 0 | 361 | // ) { |
362 | ) { | 362 | // pendingRequests = true |
363 | pendingRequests = true | 363 | // } |
364 | } | 364 | // }) |
365 | }) | 365 | // |
366 | 366 | // tasks.push(p) | |
367 | tasks.push(p) | 367 | // } |
368 | } | 368 | // |
369 | 369 | // await Promise.all(tasks) | |
370 | await Promise.all(tasks) | 370 | // |
371 | 371 | // return pendingRequests | |
372 | return pendingRequests | 372 | // } |
373 | } | ||
diff --git a/server/tests/utils/follows.ts b/server/tests/utils/follows.ts index 618436b3c..b88776011 100644 --- a/server/tests/utils/follows.ts +++ b/server/tests/utils/follows.ts | |||
@@ -42,6 +42,18 @@ async function follow (follower: string, following: string[], accessToken: strin | |||
42 | return res | 42 | return res |
43 | } | 43 | } |
44 | 44 | ||
45 | async function unfollow (url: string, accessToken: string, id: number, expectedStatus = 204) { | ||
46 | const path = '/api/v1/server/following/' + id | ||
47 | |||
48 | const res = await request(url) | ||
49 | .delete(path) | ||
50 | .set('Accept', 'application/json') | ||
51 | .set('Authorization', 'Bearer ' + accessToken) | ||
52 | .expect(expectedStatus) | ||
53 | |||
54 | return res | ||
55 | } | ||
56 | |||
45 | async function doubleFollow (server1: ServerInfo, server2: ServerInfo) { | 57 | async function doubleFollow (server1: ServerInfo, server2: ServerInfo) { |
46 | await Promise.all([ | 58 | await Promise.all([ |
47 | follow(server1.url, [ server2.url ], server1.accessToken), | 59 | follow(server1.url, [ server2.url ], server1.accessToken), |
@@ -59,6 +71,7 @@ async function doubleFollow (server1: ServerInfo, server2: ServerInfo) { | |||
59 | export { | 71 | export { |
60 | getFollowersListPaginationAndSort, | 72 | getFollowersListPaginationAndSort, |
61 | getFollowingListPaginationAndSort, | 73 | getFollowingListPaginationAndSort, |
74 | unfollow, | ||
62 | follow, | 75 | follow, |
63 | doubleFollow | 76 | doubleFollow |
64 | } | 77 | } |
diff --git a/server/tests/utils/index.ts b/server/tests/utils/index.ts index fe6d3b041..4308fd49a 100644 --- a/server/tests/utils/index.ts +++ b/server/tests/utils/index.ts | |||
@@ -4,7 +4,6 @@ export * from './config' | |||
4 | export * from './login' | 4 | export * from './login' |
5 | export * from './miscs' | 5 | export * from './miscs' |
6 | export * from './follows' | 6 | export * from './follows' |
7 | export * from './request-schedulers' | ||
8 | export * from './requests' | 7 | export * from './requests' |
9 | export * from './servers' | 8 | export * from './servers' |
10 | export * from './services' | 9 | export * from './services' |
diff --git a/server/tests/utils/request-schedulers.ts b/server/tests/utils/request-schedulers.ts deleted file mode 100644 index f100f6d99..000000000 --- a/server/tests/utils/request-schedulers.ts +++ /dev/null | |||
@@ -1,20 +0,0 @@ | |||
1 | import * as request from 'supertest' | ||
2 | |||
3 | import { ServerInfo } from '../utils' | ||
4 | |||
5 | function getRequestsStats (server: ServerInfo) { | ||
6 | const path = '/api/v1/request-schedulers/stats' | ||
7 | |||
8 | return request(server.url) | ||
9 | .get(path) | ||
10 | .set('Accept', 'application/json') | ||
11 | .set('Authorization', 'Bearer ' + server.accessToken) | ||
12 | .expect(200) | ||
13 | .expect('Content-Type', /json/) | ||
14 | } | ||
15 | |||
16 | // --------------------------------------------------------------------------- | ||
17 | |||
18 | export { | ||
19 | getRequestsStats | ||
20 | } | ||