aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rwxr-xr-xscripts/parse-log.ts8
-rw-r--r--server.ts4
-rw-r--r--server/helpers/activitypub.ts11
-rw-r--r--server/initializers/constants.ts2
-rw-r--r--server/lib/activitypub/send-request.ts170
-rw-r--r--server/lib/jobs/activitypub-http-job-scheduler/activitypub-http-broadcast-handler.ts43
-rw-r--r--server/lib/jobs/activitypub-http-job-scheduler/activitypub-http-job-scheduler.ts23
-rw-r--r--server/lib/jobs/activitypub-http-job-scheduler/activitypub-http-unicast-handler.ts40
-rw-r--r--server/lib/jobs/activitypub-http-job-scheduler/index.ts1
-rw-r--r--server/lib/jobs/http-request-job-scheduler/http-request-broadcast-handler.ts36
-rw-r--r--server/lib/jobs/http-request-job-scheduler/http-request-job-scheduler.ts22
-rw-r--r--server/lib/jobs/http-request-job-scheduler/http-request-unicast-handler.ts34
-rw-r--r--server/lib/jobs/http-request-job-scheduler/index.ts1
-rw-r--r--server/lib/jobs/index.ts2
-rw-r--r--server/tests/api/index-fast.ts1
-rw-r--r--server/tests/api/multiple-pods.ts6
-rw-r--r--server/tests/api/request-schedulers.ts82
-rw-r--r--server/tests/api/services.ts5
-rw-r--r--server/tests/api/single-pod.ts47
-rw-r--r--server/tests/api/users.ts319
-rw-r--r--server/tests/api/video-abuse.ts60
-rw-r--r--server/tests/utils/follows.ts25
-rw-r--r--server/tests/utils/servers.ts2
-rw-r--r--shared/models/activitypub/activity.ts4
-rw-r--r--shared/models/job.model.ts2
-rw-r--r--yarn.lock14
26 files changed, 522 insertions, 442 deletions
diff --git a/scripts/parse-log.ts b/scripts/parse-log.ts
index 8aac6fbda..24a09c885 100755
--- a/scripts/parse-log.ts
+++ b/scripts/parse-log.ts
@@ -38,5 +38,11 @@ const rl = createInterface({
38 38
39rl.on('line', line => { 39rl.on('line', line => {
40 const log = JSON.parse(line) 40 const log = JSON.parse(line)
41 logLevels[log.level](log.message, log.stack) 41 const additionalInfo: any = {}
42
43 Object.keys(log).forEach(logKey => {
44 if (logKey !== 'message' && logKey !== 'level') additionalInfo[logKey] = log[logKey]
45 })
46
47 logLevels[log.level](log.message, additionalInfo)
42}) 48})
diff --git a/server.ts b/server.ts
index 62219f7df..84535c7a5 100644
--- a/server.ts
+++ b/server.ts
@@ -46,7 +46,7 @@ db.init(false).then(() => onDatabaseInitDone())
46 46
47// ----------- PeerTube modules ----------- 47// ----------- PeerTube modules -----------
48import { migrate, installApplication } from './server/initializers' 48import { migrate, installApplication } from './server/initializers'
49import { httpRequestJobScheduler, transcodingJobScheduler, VideosPreviewCache } from './server/lib' 49import { activitypubHttpJobScheduler, transcodingJobScheduler, VideosPreviewCache } from './server/lib'
50import { apiRouter, clientsRouter, staticRouter, servicesRouter, webfingerRouter, activityPubRouter } from './server/controllers' 50import { apiRouter, clientsRouter, staticRouter, servicesRouter, webfingerRouter, activityPubRouter } from './server/controllers'
51 51
52// ----------- Command line ----------- 52// ----------- Command line -----------
@@ -154,7 +154,7 @@ function onDatabaseInitDone () {
154 // ----------- Make the server listening ----------- 154 // ----------- Make the server listening -----------
155 server.listen(port, () => { 155 server.listen(port, () => {
156 VideosPreviewCache.Instance.init(CONFIG.CACHE.PREVIEWS.SIZE) 156 VideosPreviewCache.Instance.init(CONFIG.CACHE.PREVIEWS.SIZE)
157 httpRequestJobScheduler.activate() 157 activitypubHttpJobScheduler.activate()
158 transcodingJobScheduler.activate() 158 transcodingJobScheduler.activate()
159 159
160 logger.info('Server listening on port %d', port) 160 logger.info('Server listening on port %d', port)
diff --git a/server/helpers/activitypub.ts b/server/helpers/activitypub.ts
index c710117cd..338698652 100644
--- a/server/helpers/activitypub.ts
+++ b/server/helpers/activitypub.ts
@@ -3,6 +3,7 @@ import * as request from 'request'
3import * as Sequelize from 'sequelize' 3import * as Sequelize from 'sequelize'
4import * as url from 'url' 4import * as url from 'url'
5import { ActivityIconObject } from '../../shared/index' 5import { ActivityIconObject } from '../../shared/index'
6import { Activity } from '../../shared/models/activitypub/activity'
6import { ActivityPubActor } from '../../shared/models/activitypub/activitypub-actor' 7import { ActivityPubActor } from '../../shared/models/activitypub/activitypub-actor'
7import { VideoChannelObject } from '../../shared/models/activitypub/objects/video-channel-object' 8import { VideoChannelObject } from '../../shared/models/activitypub/objects/video-channel-object'
8import { ResultList } from '../../shared/models/result-list.model' 9import { ResultList } from '../../shared/models/result-list.model'
@@ -17,6 +18,7 @@ import { VideoInstance } from '../models/video/video-interface'
17import { isRemoteAccountValid } from './custom-validators' 18import { isRemoteAccountValid } from './custom-validators'
18import { isVideoChannelObjectValid } from './custom-validators/activitypub/videos' 19import { isVideoChannelObjectValid } from './custom-validators/activitypub/videos'
19import { logger } from './logger' 20import { logger } from './logger'
21import { signObject } from './peertube-crypto'
20import { doRequest, doRequestAndSaveToFile } from './requests' 22import { doRequest, doRequestAndSaveToFile } from './requests'
21import { getServerAccount } from './utils' 23import { getServerAccount } from './utils'
22 24
@@ -239,6 +241,12 @@ function activityPubCollectionPagination (url: string, page: number, result: Res
239 return activityPubContextify(obj) 241 return activityPubContextify(obj)
240} 242}
241 243
244function buildSignedActivity (byAccount: AccountInstance, data: Object) {
245 const activity = activityPubContextify(data)
246
247 return signObject(byAccount, activity) as Promise<Activity>
248}
249
242// --------------------------------------------------------------------------- 250// ---------------------------------------------------------------------------
243 251
244export { 252export {
@@ -252,7 +260,8 @@ export {
252 fetchRemoteVideoDescription, 260 fetchRemoteVideoDescription,
253 shareVideoChannelByServer, 261 shareVideoChannelByServer,
254 shareVideoByServer, 262 shareVideoByServer,
255 getOrCreateVideoChannel 263 getOrCreateVideoChannel,
264 buildSignedActivity
256} 265}
257 266
258// --------------------------------------------------------------------------- 267// ---------------------------------------------------------------------------
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts
index f0a569410..48d7b5b98 100644
--- a/server/initializers/constants.ts
+++ b/server/initializers/constants.ts
@@ -260,7 +260,7 @@ const JOB_STATES: { [ id: string ]: JobState } = {
260} 260}
261const JOB_CATEGORIES: { [ id: string ]: JobCategory } = { 261const JOB_CATEGORIES: { [ id: string ]: JobCategory } = {
262 TRANSCODING: 'transcoding', 262 TRANSCODING: 'transcoding',
263 HTTP_REQUEST: 'http-request' 263 ACTIVITYPUB_HTTP: 'activitypub-http'
264} 264}
265// How many maximum jobs we fetch from the database per cycle 265// How many maximum jobs we fetch from the database per cycle
266const JOBS_FETCH_LIMIT_PER_CYCLE = { 266const JOBS_FETCH_LIMIT_PER_CYCLE = {
diff --git a/server/lib/activitypub/send-request.ts b/server/lib/activitypub/send-request.ts
index abc1b598d..8d013fa87 100644
--- a/server/lib/activitypub/send-request.ts
+++ b/server/lib/activitypub/send-request.ts
@@ -1,116 +1,124 @@
1import * as Sequelize from 'sequelize' 1import { Transaction } from 'sequelize'
2
3import { database as db } from '../../initializers'
4import { 2import {
5 AccountInstance, 3 ActivityAccept,
6 VideoInstance, 4 ActivityAdd,
7 VideoChannelInstance 5 ActivityCreate,
8} from '../../models' 6 ActivityDelete,
9import { httpRequestJobScheduler } from '../jobs' 7 ActivityFollow,
10import { signObject, activityPubContextify } from '../../helpers' 8 ActivityUpdate
11import { Activity, VideoAbuseObject } from '../../../shared' 9} from '../../../shared/models/activitypub/activity'
12import { VideoAbuseInstance } from '../../models/video/video-abuse-interface'
13import { getActivityPubUrl } from '../../helpers/activitypub' 10import { getActivityPubUrl } from '../../helpers/activitypub'
14import { logger } from '../../helpers/logger' 11import { logger } from '../../helpers/logger'
12import { database as db } from '../../initializers'
13import { AccountInstance, VideoChannelInstance, VideoInstance } from '../../models'
14import { VideoAbuseInstance } from '../../models/video/video-abuse-interface'
15import { activitypubHttpJobScheduler } from '../jobs'
16
17async function sendCreateVideoChannel (videoChannel: VideoChannelInstance, t: Transaction) {
18 const byAccount = videoChannel.Account
15 19
16async function sendCreateVideoChannel (videoChannel: VideoChannelInstance, t: Sequelize.Transaction) {
17 const videoChannelObject = videoChannel.toActivityPubObject() 20 const videoChannelObject = videoChannel.toActivityPubObject()
18 const data = await createActivityData(videoChannel.url, videoChannel.Account, videoChannelObject) 21 const data = await createActivityData(videoChannel.url, byAccount, videoChannelObject)
19 22
20 return broadcastToFollowers(data, [ videoChannel.Account ], t) 23 return broadcastToFollowers(data, byAccount, [ byAccount ], t)
21} 24}
22 25
23async function sendUpdateVideoChannel (videoChannel: VideoChannelInstance, t: Sequelize.Transaction) { 26async function sendUpdateVideoChannel (videoChannel: VideoChannelInstance, t: Transaction) {
27 const byAccount = videoChannel.Account
28
24 const videoChannelObject = videoChannel.toActivityPubObject() 29 const videoChannelObject = videoChannel.toActivityPubObject()
25 const data = await updateActivityData(videoChannel.url, videoChannel.Account, videoChannelObject) 30 const data = await updateActivityData(videoChannel.url, byAccount, videoChannelObject)
26 31
27 const accountsInvolved = await db.VideoChannelShare.loadAccountsByShare(videoChannel.id) 32 const accountsInvolved = await db.VideoChannelShare.loadAccountsByShare(videoChannel.id)
28 accountsInvolved.push(videoChannel.Account) 33 accountsInvolved.push(byAccount)
29 34
30 return broadcastToFollowers(data, accountsInvolved, t) 35 return broadcastToFollowers(data, byAccount, accountsInvolved, t)
31} 36}
32 37
33async function sendDeleteVideoChannel (videoChannel: VideoChannelInstance, t: Sequelize.Transaction) { 38async function sendDeleteVideoChannel (videoChannel: VideoChannelInstance, t: Transaction) {
34 const data = await deleteActivityData(videoChannel.url, videoChannel.Account) 39 const byAccount = videoChannel.Account
40
41 const data = await deleteActivityData(videoChannel.url, byAccount)
35 42
36 const accountsInvolved = await db.VideoChannelShare.loadAccountsByShare(videoChannel.id) 43 const accountsInvolved = await db.VideoChannelShare.loadAccountsByShare(videoChannel.id)
37 accountsInvolved.push(videoChannel.Account) 44 accountsInvolved.push(byAccount)
38 45
39 return broadcastToFollowers(data, accountsInvolved, t) 46 return broadcastToFollowers(data, byAccount, accountsInvolved, t)
40} 47}
41 48
42async function sendAddVideo (video: VideoInstance, t: Sequelize.Transaction) { 49async function sendAddVideo (video: VideoInstance, t: Transaction) {
50 const byAccount = video.VideoChannel.Account
51
43 const videoObject = video.toActivityPubObject() 52 const videoObject = video.toActivityPubObject()
44 const data = await addActivityData(video.url, video.VideoChannel.Account, video.VideoChannel.url, videoObject) 53 const data = await addActivityData(video.url, byAccount, video.VideoChannel.url, videoObject)
45 54
46 return broadcastToFollowers(data, [ video.VideoChannel.Account ], t) 55 return broadcastToFollowers(data, byAccount, [ byAccount ], t)
47} 56}
48 57
49async function sendUpdateVideo (video: VideoInstance, t: Sequelize.Transaction) { 58async function sendUpdateVideo (video: VideoInstance, t: Transaction) {
59 const byAccount = video.VideoChannel.Account
60
50 const videoObject = video.toActivityPubObject() 61 const videoObject = video.toActivityPubObject()
51 const data = await updateActivityData(video.url, video.VideoChannel.Account, videoObject) 62 const data = await updateActivityData(video.url, byAccount, videoObject)
52 63
53 const accountsInvolved = await db.VideoShare.loadAccountsByShare(video.id) 64 const accountsInvolved = await db.VideoShare.loadAccountsByShare(video.id)
54 accountsInvolved.push(video.VideoChannel.Account) 65 accountsInvolved.push(byAccount)
55 66
56 return broadcastToFollowers(data, accountsInvolved, t) 67 return broadcastToFollowers(data, byAccount, accountsInvolved, t)
57} 68}
58 69
59async function sendDeleteVideo (video: VideoInstance, t: Sequelize.Transaction) { 70async function sendDeleteVideo (video: VideoInstance, t: Transaction) {
60 const data = await deleteActivityData(video.url, video.VideoChannel.Account) 71 const byAccount = video.VideoChannel.Account
72
73 const data = await deleteActivityData(video.url, byAccount)
61 74
62 const accountsInvolved = await db.VideoShare.loadAccountsByShare(video.id) 75 const accountsInvolved = await db.VideoShare.loadAccountsByShare(video.id)
63 accountsInvolved.push(video.VideoChannel.Account) 76 accountsInvolved.push(byAccount)
64 77
65 return broadcastToFollowers(data, accountsInvolved, t) 78 return broadcastToFollowers(data, byAccount, accountsInvolved, t)
66} 79}
67 80
68async function sendDeleteAccount (account: AccountInstance, t: Sequelize.Transaction) { 81async function sendDeleteAccount (account: AccountInstance, t: Transaction) {
69 const data = await deleteActivityData(account.url, account) 82 const data = await deleteActivityData(account.url, account)
70 83
71 return broadcastToFollowers(data, [ account ], t) 84 return broadcastToFollowers(data, account, [ account ], t)
72} 85}
73 86
74async function sendVideoChannelAnnounce (byAccount: AccountInstance, videoChannel: VideoChannelInstance, t: Sequelize.Transaction) { 87async function sendVideoChannelAnnounce (byAccount: AccountInstance, videoChannel: VideoChannelInstance, t: Transaction) {
75 const url = getActivityPubUrl('videoChannel', videoChannel.uuid) + '#announce' 88 const url = getActivityPubUrl('videoChannel', videoChannel.uuid) + '#announce'
76 const announcedActivity = await createActivityData(url, videoChannel.Account, videoChannel.toActivityPubObject(), true) 89 const announcedActivity = await createActivityData(url, videoChannel.Account, videoChannel.toActivityPubObject())
77 90
78 const data = await announceActivityData(url, byAccount, announcedActivity) 91 const data = await announceActivityData(url, byAccount, announcedActivity)
79 return broadcastToFollowers(data, [ byAccount ], t) 92 return broadcastToFollowers(data, byAccount, [ byAccount ], t)
80} 93}
81 94
82async function sendVideoAnnounce (byAccount: AccountInstance, video: VideoInstance, t: Sequelize.Transaction) { 95async function sendVideoAnnounce (byAccount: AccountInstance, video: VideoInstance, t: Transaction) {
83 const url = getActivityPubUrl('video', video.uuid) + '#announce' 96 const url = getActivityPubUrl('video', video.uuid) + '#announce'
84 97
85 const videoChannel = video.VideoChannel 98 const videoChannel = video.VideoChannel
86 const announcedActivity = await addActivityData(url, videoChannel.Account, videoChannel.url, video.toActivityPubObject(), true) 99 const announcedActivity = await addActivityData(url, videoChannel.Account, videoChannel.url, video.toActivityPubObject())
87 100
88 const data = await announceActivityData(url, byAccount, announcedActivity) 101 const data = await announceActivityData(url, byAccount, announcedActivity)
89 return broadcastToFollowers(data, [ byAccount ], t) 102 return broadcastToFollowers(data, byAccount, [ byAccount ], t)
90} 103}
91 104
92async function sendVideoAbuse ( 105async function sendVideoAbuse (byAccount: AccountInstance, videoAbuse: VideoAbuseInstance, video: VideoInstance, t: Transaction) {
93 fromAccount: AccountInstance,
94 videoAbuse: VideoAbuseInstance,
95 video: VideoInstance,
96 t: Sequelize.Transaction
97) {
98 const url = getActivityPubUrl('videoAbuse', videoAbuse.id.toString()) 106 const url = getActivityPubUrl('videoAbuse', videoAbuse.id.toString())
99 const data = await createActivityData(url, fromAccount, videoAbuse.toActivityPubObject()) 107 const data = await createActivityData(url, byAccount, videoAbuse.toActivityPubObject())
100 108
101 return unicastTo(data, video.VideoChannel.Account.sharedInboxUrl, t) 109 return unicastTo(data, byAccount, video.VideoChannel.Account.sharedInboxUrl, t)
102} 110}
103 111
104async function sendAccept (fromAccount: AccountInstance, toAccount: AccountInstance, t: Sequelize.Transaction) { 112async function sendAccept (byAccount: AccountInstance, toAccount: AccountInstance, t: Transaction) {
105 const data = await acceptActivityData(fromAccount) 113 const data = await acceptActivityData(byAccount)
106 114
107 return unicastTo(data, toAccount.inboxUrl, t) 115 return unicastTo(data, byAccount, toAccount.inboxUrl, t)
108} 116}
109 117
110async function sendFollow (fromAccount: AccountInstance, toAccount: AccountInstance, t: Sequelize.Transaction) { 118async function sendFollow (byAccount: AccountInstance, toAccount: AccountInstance, t: Transaction) {
111 const data = await followActivityData(toAccount.url, fromAccount) 119 const data = await followActivityData(toAccount.url, byAccount)
112 120
113 return unicastTo(data, toAccount.inboxUrl, t) 121 return unicastTo(data, byAccount, toAccount.inboxUrl, t)
114} 122}
115 123
116// --------------------------------------------------------------------------- 124// ---------------------------------------------------------------------------
@@ -132,7 +140,7 @@ export {
132 140
133// --------------------------------------------------------------------------- 141// ---------------------------------------------------------------------------
134 142
135async function broadcastToFollowers (data: any, toAccountFollowers: AccountInstance[], t: Sequelize.Transaction) { 143async function broadcastToFollowers (data: any, byAccount: AccountInstance, toAccountFollowers: AccountInstance[], t: Transaction) {
136 const toAccountFollowerIds = toAccountFollowers.map(a => a.id) 144 const toAccountFollowerIds = toAccountFollowers.map(a => a.id)
137 const result = await db.AccountFollow.listAcceptedFollowerSharedInboxUrls(toAccountFollowerIds) 145 const result = await db.AccountFollow.listAcceptedFollowerSharedInboxUrls(toAccountFollowerIds)
138 if (result.data.length === 0) { 146 if (result.data.length === 0) {
@@ -142,25 +150,21 @@ async function broadcastToFollowers (data: any, toAccountFollowers: AccountInsta
142 150
143 const jobPayload = { 151 const jobPayload = {
144 uris: result.data, 152 uris: result.data,
153 signatureAccountId: byAccount.id,
145 body: data 154 body: data
146 } 155 }
147 156
148 return httpRequestJobScheduler.createJob(t, 'httpRequestBroadcastHandler', jobPayload) 157 return activitypubHttpJobScheduler.createJob(t, 'activitypubHttpBroadcastHandler', jobPayload)
149} 158}
150 159
151async function unicastTo (data: any, toAccountUrl: string, t: Sequelize.Transaction) { 160async function unicastTo (data: any, byAccount: AccountInstance, toAccountUrl: string, t: Transaction) {
152 const jobPayload = { 161 const jobPayload = {
153 uris: [ toAccountUrl ], 162 uris: [ toAccountUrl ],
163 signatureAccountId: byAccount.id,
154 body: data 164 body: data
155 } 165 }
156 166
157 return httpRequestJobScheduler.createJob(t, 'httpRequestUnicastHandler', jobPayload) 167 return activitypubHttpJobScheduler.createJob(t, 'activitypubHttpUnicastHandler', jobPayload)
158}
159
160function buildSignedActivity (byAccount: AccountInstance, data: Object) {
161 const activity = activityPubContextify(data)
162
163 return signObject(byAccount, activity) as Promise<Activity>
164} 168}
165 169
166async function getPublicActivityTo (account: AccountInstance) { 170async function getPublicActivityTo (account: AccountInstance) {
@@ -169,9 +173,9 @@ async function getPublicActivityTo (account: AccountInstance) {
169 return inboxUrls.concat('https://www.w3.org/ns/activitystreams#Public') 173 return inboxUrls.concat('https://www.w3.org/ns/activitystreams#Public')
170} 174}
171 175
172async function createActivityData (url: string, byAccount: AccountInstance, object: any, raw = false) { 176async function createActivityData (url: string, byAccount: AccountInstance, object: any) {
173 const to = await getPublicActivityTo(byAccount) 177 const to = await getPublicActivityTo(byAccount)
174 const base = { 178 const activity: ActivityCreate = {
175 type: 'Create', 179 type: 'Create',
176 id: url, 180 id: url,
177 actor: byAccount.url, 181 actor: byAccount.url,
@@ -179,14 +183,12 @@ async function createActivityData (url: string, byAccount: AccountInstance, obje
179 object 183 object
180 } 184 }
181 185
182 if (raw === true) return base 186 return activity
183
184 return buildSignedActivity(byAccount, base)
185} 187}
186 188
187async function updateActivityData (url: string, byAccount: AccountInstance, object: any) { 189async function updateActivityData (url: string, byAccount: AccountInstance, object: any) {
188 const to = await getPublicActivityTo(byAccount) 190 const to = await getPublicActivityTo(byAccount)
189 const base = { 191 const activity: ActivityUpdate = {
190 type: 'Update', 192 type: 'Update',
191 id: url, 193 id: url,
192 actor: byAccount.url, 194 actor: byAccount.url,
@@ -194,22 +196,22 @@ async function updateActivityData (url: string, byAccount: AccountInstance, obje
194 object 196 object
195 } 197 }
196 198
197 return buildSignedActivity(byAccount, base) 199 return activity
198} 200}
199 201
200async function deleteActivityData (url: string, byAccount: AccountInstance) { 202async function deleteActivityData (url: string, byAccount: AccountInstance) {
201 const base = { 203 const activity: ActivityDelete = {
202 type: 'Delete', 204 type: 'Delete',
203 id: url, 205 id: url,
204 actor: byAccount.url 206 actor: byAccount.url
205 } 207 }
206 208
207 return buildSignedActivity(byAccount, base) 209 return activity
208} 210}
209 211
210async function addActivityData (url: string, byAccount: AccountInstance, target: string, object: any, raw = false) { 212async function addActivityData (url: string, byAccount: AccountInstance, target: string, object: any) {
211 const to = await getPublicActivityTo(byAccount) 213 const to = await getPublicActivityTo(byAccount)
212 const base = { 214 const activity: ActivityAdd = {
213 type: 'Add', 215 type: 'Add',
214 id: url, 216 id: url,
215 actor: byAccount.url, 217 actor: byAccount.url,
@@ -218,39 +220,37 @@ async function addActivityData (url: string, byAccount: AccountInstance, target:
218 target 220 target
219 } 221 }
220 222
221 if (raw === true) return base 223 return activity
222
223 return buildSignedActivity(byAccount, base)
224} 224}
225 225
226async function announceActivityData (url: string, byAccount: AccountInstance, object: any) { 226async function announceActivityData (url: string, byAccount: AccountInstance, object: any) {
227 const base = { 227 const activity = {
228 type: 'Announce', 228 type: 'Announce',
229 id: url, 229 id: url,
230 actor: byAccount.url, 230 actor: byAccount.url,
231 object 231 object
232 } 232 }
233 233
234 return buildSignedActivity(byAccount, base) 234 return activity
235} 235}
236 236
237async function followActivityData (url: string, byAccount: AccountInstance) { 237async function followActivityData (url: string, byAccount: AccountInstance) {
238 const base = { 238 const activity: ActivityFollow = {
239 type: 'Follow', 239 type: 'Follow',
240 id: byAccount.url, 240 id: byAccount.url,
241 actor: byAccount.url, 241 actor: byAccount.url,
242 object: url 242 object: url
243 } 243 }
244 244
245 return buildSignedActivity(byAccount, base) 245 return activity
246} 246}
247 247
248async function acceptActivityData (byAccount: AccountInstance) { 248async function acceptActivityData (byAccount: AccountInstance) {
249 const base = { 249 const activity: ActivityAccept = {
250 type: 'Accept', 250 type: 'Accept',
251 id: byAccount.url, 251 id: byAccount.url,
252 actor: byAccount.url 252 actor: byAccount.url
253 } 253 }
254 254
255 return buildSignedActivity(byAccount, base) 255 return activity
256} 256}
diff --git a/server/lib/jobs/activitypub-http-job-scheduler/activitypub-http-broadcast-handler.ts b/server/lib/jobs/activitypub-http-job-scheduler/activitypub-http-broadcast-handler.ts
new file mode 100644
index 000000000..111fc88a4
--- /dev/null
+++ b/server/lib/jobs/activitypub-http-job-scheduler/activitypub-http-broadcast-handler.ts
@@ -0,0 +1,43 @@
1import { logger } from '../../../helpers'
2import { buildSignedActivity } from '../../../helpers/activitypub'
3import { doRequest } from '../../../helpers/requests'
4import { database as db } from '../../../initializers'
5import { ActivityPubHttpPayload } from './activitypub-http-job-scheduler'
6
7async function process (payload: ActivityPubHttpPayload, jobId: number) {
8 logger.info('Processing ActivityPub broadcast in job %d.', jobId)
9
10 const accountSignature = await db.Account.load(payload.signatureAccountId)
11 if (!accountSignature) throw new Error('Unknown signature account id.')
12
13 const signedBody = await buildSignedActivity(accountSignature, payload.body)
14
15 const options = {
16 method: 'POST',
17 uri: '',
18 json: signedBody
19 }
20
21 for (const uri of payload.uris) {
22 options.uri = uri
23 await doRequest(options)
24 }
25}
26
27function onError (err: Error, jobId: number) {
28 logger.error('Error when broadcasting ActivityPub request in job %d.', jobId, err)
29 return Promise.resolve()
30}
31
32function onSuccess (jobId: number) {
33 logger.info('Job %d is a success.', jobId)
34 return Promise.resolve()
35}
36
37// ---------------------------------------------------------------------------
38
39export {
40 process,
41 onError,
42 onSuccess
43}
diff --git a/server/lib/jobs/activitypub-http-job-scheduler/activitypub-http-job-scheduler.ts b/server/lib/jobs/activitypub-http-job-scheduler/activitypub-http-job-scheduler.ts
new file mode 100644
index 000000000..e4f6c94a5
--- /dev/null
+++ b/server/lib/jobs/activitypub-http-job-scheduler/activitypub-http-job-scheduler.ts
@@ -0,0 +1,23 @@
1import { JobScheduler, JobHandler } from '../job-scheduler'
2
3import * as activitypubHttpBroadcastHandler from './activitypub-http-broadcast-handler'
4import * as activitypubHttpUnicastHandler from './activitypub-http-unicast-handler'
5import { JobCategory } from '../../../../shared'
6
7type ActivityPubHttpPayload = {
8 uris: string[]
9 signatureAccountId: number
10 body: any
11}
12const jobHandlers: { [ handlerName: string ]: JobHandler<ActivityPubHttpPayload, void> } = {
13 activitypubHttpBroadcastHandler,
14 activitypubHttpUnicastHandler
15}
16const jobCategory: JobCategory = 'activitypub-http'
17
18const activitypubHttpJobScheduler = new JobScheduler(jobCategory, jobHandlers)
19
20export {
21 ActivityPubHttpPayload,
22 activitypubHttpJobScheduler
23}
diff --git a/server/lib/jobs/activitypub-http-job-scheduler/activitypub-http-unicast-handler.ts b/server/lib/jobs/activitypub-http-job-scheduler/activitypub-http-unicast-handler.ts
new file mode 100644
index 000000000..8d3b755ad
--- /dev/null
+++ b/server/lib/jobs/activitypub-http-job-scheduler/activitypub-http-unicast-handler.ts
@@ -0,0 +1,40 @@
1import { logger } from '../../../helpers'
2import { doRequest } from '../../../helpers/requests'
3import { ActivityPubHttpPayload } from './activitypub-http-job-scheduler'
4import { database as db } from '../../../initializers/database'
5import { buildSignedActivity } from '../../../helpers/activitypub'
6
7async function process (payload: ActivityPubHttpPayload, jobId: number) {
8 logger.info('Processing ActivityPub unicast in job %d.', jobId)
9
10 const accountSignature = await db.Account.load(payload.signatureAccountId)
11 if (!accountSignature) throw new Error('Unknown signature account id.')
12
13 const signedBody = await buildSignedActivity(accountSignature, payload.body)
14 const uri = payload.uris[0]
15 const options = {
16 method: 'POST',
17 uri,
18 json: signedBody
19 }
20
21 await doRequest(options)
22}
23
24function onError (err: Error, jobId: number) {
25 logger.error('Error when sending ActivityPub request in job %d.', jobId, err)
26 return Promise.resolve()
27}
28
29function onSuccess (jobId: number) {
30 logger.info('Job %d is a success.', jobId)
31 return Promise.resolve()
32}
33
34// ---------------------------------------------------------------------------
35
36export {
37 process,
38 onError,
39 onSuccess
40}
diff --git a/server/lib/jobs/activitypub-http-job-scheduler/index.ts b/server/lib/jobs/activitypub-http-job-scheduler/index.ts
new file mode 100644
index 000000000..ad8f527b4
--- /dev/null
+++ b/server/lib/jobs/activitypub-http-job-scheduler/index.ts
@@ -0,0 +1 @@
export * from './activitypub-http-job-scheduler'
diff --git a/server/lib/jobs/http-request-job-scheduler/http-request-broadcast-handler.ts b/server/lib/jobs/http-request-job-scheduler/http-request-broadcast-handler.ts
deleted file mode 100644
index ccb008e4d..000000000
--- a/server/lib/jobs/http-request-job-scheduler/http-request-broadcast-handler.ts
+++ /dev/null
@@ -1,36 +0,0 @@
1import { logger } from '../../../helpers'
2import { doRequest } from '../../../helpers/requests'
3import { HTTPRequestPayload } from './http-request-job-scheduler'
4
5async function process (payload: HTTPRequestPayload, jobId: number) {
6 logger.info('Processing broadcast in job %d.', jobId)
7
8 const options = {
9 method: 'POST',
10 uri: '',
11 json: payload.body
12 }
13
14 for (const uri of payload.uris) {
15 options.uri = uri
16 await doRequest(options)
17 }
18}
19
20function onError (err: Error, jobId: number) {
21 logger.error('Error when broadcasting request in job %d.', jobId, err)
22 return Promise.resolve()
23}
24
25function onSuccess (jobId: number) {
26 logger.info('Job %d is a success.', jobId)
27 return Promise.resolve()
28}
29
30// ---------------------------------------------------------------------------
31
32export {
33 process,
34 onError,
35 onSuccess
36}
diff --git a/server/lib/jobs/http-request-job-scheduler/http-request-job-scheduler.ts b/server/lib/jobs/http-request-job-scheduler/http-request-job-scheduler.ts
deleted file mode 100644
index ad3349866..000000000
--- a/server/lib/jobs/http-request-job-scheduler/http-request-job-scheduler.ts
+++ /dev/null
@@ -1,22 +0,0 @@
1import { JobScheduler, JobHandler } from '../job-scheduler'
2
3import * as httpRequestBroadcastHandler from './http-request-broadcast-handler'
4import * as httpRequestUnicastHandler from './http-request-unicast-handler'
5import { JobCategory } from '../../../../shared'
6
7type HTTPRequestPayload = {
8 uris: string[]
9 body: any
10}
11const jobHandlers: { [ handlerName: string ]: JobHandler<HTTPRequestPayload, void> } = {
12 httpRequestBroadcastHandler,
13 httpRequestUnicastHandler
14}
15const jobCategory: JobCategory = 'http-request'
16
17const httpRequestJobScheduler = new JobScheduler(jobCategory, jobHandlers)
18
19export {
20 HTTPRequestPayload,
21 httpRequestJobScheduler
22}
diff --git a/server/lib/jobs/http-request-job-scheduler/http-request-unicast-handler.ts b/server/lib/jobs/http-request-job-scheduler/http-request-unicast-handler.ts
deleted file mode 100644
index 9e4e73891..000000000
--- a/server/lib/jobs/http-request-job-scheduler/http-request-unicast-handler.ts
+++ /dev/null
@@ -1,34 +0,0 @@
1import { logger } from '../../../helpers'
2import { doRequest } from '../../../helpers/requests'
3import { HTTPRequestPayload } from './http-request-job-scheduler'
4
5async function process (payload: HTTPRequestPayload, jobId: number) {
6 logger.info('Processing unicast in job %d.', jobId)
7
8 const uri = payload.uris[0]
9 const options = {
10 method: 'POST',
11 uri,
12 json: payload.body
13 }
14
15 await doRequest(options)
16}
17
18function onError (err: Error, jobId: number) {
19 logger.error('Error when sending request in job %d.', jobId, err)
20 return Promise.resolve()
21}
22
23function onSuccess (jobId: number) {
24 logger.info('Job %d is a success.', jobId)
25 return Promise.resolve()
26}
27
28// ---------------------------------------------------------------------------
29
30export {
31 process,
32 onError,
33 onSuccess
34}
diff --git a/server/lib/jobs/http-request-job-scheduler/index.ts b/server/lib/jobs/http-request-job-scheduler/index.ts
deleted file mode 100644
index 4d2573296..000000000
--- a/server/lib/jobs/http-request-job-scheduler/index.ts
+++ /dev/null
@@ -1 +0,0 @@
1export * from './http-request-job-scheduler'
diff --git a/server/lib/jobs/index.ts b/server/lib/jobs/index.ts
index a92743707..394264ec1 100644
--- a/server/lib/jobs/index.ts
+++ b/server/lib/jobs/index.ts
@@ -1,2 +1,2 @@
1export * from './http-request-job-scheduler' 1export * from './activitypub-http-job-scheduler'
2export * from './transcoding-job-scheduler' 2export * from './transcoding-job-scheduler'
diff --git a/server/tests/api/index-fast.ts b/server/tests/api/index-fast.ts
index f13d8155d..ced973bc2 100644
--- a/server/tests/api/index-fast.ts
+++ b/server/tests/api/index-fast.ts
@@ -10,4 +10,3 @@ import './video-blacklist-management'
10import './video-description' 10import './video-description'
11import './video-privacy' 11import './video-privacy'
12import './services' 12import './services'
13import './request-schedulers'
diff --git a/server/tests/api/multiple-pods.ts b/server/tests/api/multiple-pods.ts
index 8e89da97a..3c6b3f650 100644
--- a/server/tests/api/multiple-pods.ts
+++ b/server/tests/api/multiple-pods.ts
@@ -113,7 +113,7 @@ describe('Test multiple pods', function () {
113 expect(video.tags).to.deep.equal([ 'tag1p1', 'tag2p1' ]) 113 expect(video.tags).to.deep.equal([ 'tag1p1', 'tag2p1' ])
114 expect(dateIsValid(video.createdAt)).to.be.true 114 expect(dateIsValid(video.createdAt)).to.be.true
115 expect(dateIsValid(video.updatedAt)).to.be.true 115 expect(dateIsValid(video.updatedAt)).to.be.true
116 expect(video.author).to.equal('root') 116 expect(video.account).to.equal('root')
117 117
118 const res2 = await getVideo(server.url, video.uuid) 118 const res2 = await getVideo(server.url, video.uuid)
119 const videoDetails = res2.body 119 const videoDetails = res2.body
@@ -202,7 +202,7 @@ describe('Test multiple pods', function () {
202 expect(video.tags).to.deep.equal([ 'tag1p2', 'tag2p2', 'tag3p2' ]) 202 expect(video.tags).to.deep.equal([ 'tag1p2', 'tag2p2', 'tag3p2' ])
203 expect(dateIsValid(video.createdAt)).to.be.true 203 expect(dateIsValid(video.createdAt)).to.be.true
204 expect(dateIsValid(video.updatedAt)).to.be.true 204 expect(dateIsValid(video.updatedAt)).to.be.true
205 expect(video.author).to.equal('user1') 205 expect(video.account).to.equal('user1')
206 206
207 if (server.url !== 'http://localhost:9002') { 207 if (server.url !== 'http://localhost:9002') {
208 expect(video.isLocal).to.be.false 208 expect(video.isLocal).to.be.false
@@ -696,7 +696,7 @@ describe('Test multiple pods', function () {
696 expect(baseVideo.licence).to.equal(video.licence) 696 expect(baseVideo.licence).to.equal(video.licence)
697 expect(baseVideo.category).to.equal(video.category) 697 expect(baseVideo.category).to.equal(video.category)
698 expect(baseVideo.nsfw).to.equal(video.nsfw) 698 expect(baseVideo.nsfw).to.equal(video.nsfw)
699 expect(baseVideo.author).to.equal(video.author) 699 expect(baseVideo.author).to.equal(video.account)
700 expect(baseVideo.tags).to.deep.equal(video.tags) 700 expect(baseVideo.tags).to.deep.equal(video.tags)
701 } 701 }
702 }) 702 })
diff --git a/server/tests/api/request-schedulers.ts b/server/tests/api/request-schedulers.ts
deleted file mode 100644
index c136d1cea..000000000
--- a/server/tests/api/request-schedulers.ts
+++ /dev/null
@@ -1,82 +0,0 @@
1/* tslint:disable:no-unused-expression */
2
3import 'mocha'
4import * as chai from 'chai'
5const expect = chai.expect
6
7import {
8 ServerInfo,
9 flushTests,
10 uploadVideo,
11 makeFriends,
12 wait,
13 setAccessTokensToServers,
14 flushAndRunMultipleServers,
15 getRequestsStats,
16 killallServers
17} from '../utils'
18
19describe('Test requests schedulers stats', function () {
20 const requestSchedulerNames = [ 'requestScheduler', 'requestVideoQaduScheduler', 'requestVideoEventScheduler' ]
21 let servers: ServerInfo[] = []
22
23 function uploadVideoWrapper (server: ServerInfo) {
24 const videoAttributes = {
25 tags: [ 'tag1', 'tag2' ]
26 }
27
28 return uploadVideo(server.url, server.accessToken, videoAttributes)
29 }
30
31 // ---------------------------------------------------------------
32
33 before(async function () {
34 this.timeout(120000)
35
36 servers = await flushAndRunMultipleServers(2)
37
38 await setAccessTokensToServers(servers)
39
40 await makeFriends(servers[0].url, servers[0].accessToken)
41 })
42
43 it('Should have a correct timer', async function () {
44 const server = servers[0]
45
46 const res = await getRequestsStats(server)
47
48 const requestSchedulers = res.body
49 for (const requestSchedulerName of requestSchedulerNames) {
50 const requestScheduler = requestSchedulers[requestSchedulerName]
51
52 expect(requestScheduler.remainingMilliSeconds).to.be.at.least(0)
53 expect(requestScheduler.remainingMilliSeconds).to.be.at.most(10000)
54 }
55 })
56
57 it('Should have the correct total request', async function () {
58 this.timeout(15000)
59
60 const server = servers[0]
61 // Ensure the requests of pod 1 won't be made
62 servers[1].app.kill()
63
64 await uploadVideoWrapper(server)
65
66 await wait(1000)
67
68 const res = await getRequestsStats(server)
69 const requestSchedulers = res.body
70 const requestScheduler = requestSchedulers.requestScheduler
71 expect(requestScheduler.totalRequests).to.equal(3)
72 })
73
74 after(async function () {
75 // Server 1 has already been killed
76 killallServers([ servers[0] ])
77
78 if (this['ok']) {
79 await flushTests()
80 }
81 })
82})
diff --git a/server/tests/api/services.ts b/server/tests/api/services.ts
index 76911fdc5..c34c51f66 100644
--- a/server/tests/api/services.ts
+++ b/server/tests/api/services.ts
@@ -14,6 +14,7 @@ import {
14 getOEmbed 14 getOEmbed
15} from '../utils' 15} from '../utils'
16import { runServer } from '../utils/servers' 16import { runServer } from '../utils/servers'
17import { Video } from '../../../client/src/app/videos/shared/video.model'
17 18
18describe('Test services', function () { 19describe('Test services', function () {
19 let server: ServerInfo = null 20 let server: ServerInfo = null
@@ -46,7 +47,7 @@ describe('Test services', function () {
46 47
47 expect(res.body.html).to.equal(expectedHtml) 48 expect(res.body.html).to.equal(expectedHtml)
48 expect(res.body.title).to.equal(server.video.name) 49 expect(res.body.title).to.equal(server.video.name)
49 expect(res.body.author_name).to.equal(server.video.author) 50 expect(res.body.author_name).to.equal(server.video.account)
50 expect(res.body.width).to.equal(560) 51 expect(res.body.width).to.equal(560)
51 expect(res.body.height).to.equal(315) 52 expect(res.body.height).to.equal(315)
52 expect(res.body.thumbnail_url).to.equal(expectedThumbnailUrl) 53 expect(res.body.thumbnail_url).to.equal(expectedThumbnailUrl)
@@ -66,7 +67,7 @@ describe('Test services', function () {
66 67
67 expect(res.body.html).to.equal(expectedHtml) 68 expect(res.body.html).to.equal(expectedHtml)
68 expect(res.body.title).to.equal(server.video.name) 69 expect(res.body.title).to.equal(server.video.name)
69 expect(res.body.author_name).to.equal(server.video.author) 70 expect(res.body.author_name).to.equal(server.video.account)
70 expect(res.body.height).to.equal(50) 71 expect(res.body.height).to.equal(50)
71 expect(res.body.width).to.equal(50) 72 expect(res.body.width).to.equal(50)
72 expect(res.body).to.not.have.property('thumbnail_url') 73 expect(res.body).to.not.have.property('thumbnail_url')
diff --git a/server/tests/api/single-pod.ts b/server/tests/api/single-pod.ts
index 3a05d0727..0a917f2ae 100644
--- a/server/tests/api/single-pod.ts
+++ b/server/tests/api/single-pod.ts
@@ -125,8 +125,8 @@ describe('Test a single pod', function () {
125 expect(video.languageLabel).to.equal('Mandarin') 125 expect(video.languageLabel).to.equal('Mandarin')
126 expect(video.nsfw).to.be.ok 126 expect(video.nsfw).to.be.ok
127 expect(video.description).to.equal('my super description') 127 expect(video.description).to.equal('my super description')
128 expect(video.podHost).to.equal('localhost:9001') 128 expect(video.serverHost).to.equal('localhost:9001')
129 expect(video.author).to.equal('root') 129 expect(video.account).to.equal('root')
130 expect(video.isLocal).to.be.true 130 expect(video.isLocal).to.be.true
131 expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'tag3' ]) 131 expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'tag3' ])
132 expect(dateIsValid(video.createdAt)).to.be.true 132 expect(dateIsValid(video.createdAt)).to.be.true
@@ -174,8 +174,8 @@ describe('Test a single pod', function () {
174 expect(video.languageLabel).to.equal('Mandarin') 174 expect(video.languageLabel).to.equal('Mandarin')
175 expect(video.nsfw).to.be.ok 175 expect(video.nsfw).to.be.ok
176 expect(video.description).to.equal('my super description') 176 expect(video.description).to.equal('my super description')
177 expect(video.podHost).to.equal('localhost:9001') 177 expect(video.serverHost).to.equal('localhost:9001')
178 expect(video.author).to.equal('root') 178 expect(video.account).to.equal('root')
179 expect(video.isLocal).to.be.true 179 expect(video.isLocal).to.be.true
180 expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'tag3' ]) 180 expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'tag3' ])
181 expect(dateIsValid(video.createdAt)).to.be.true 181 expect(dateIsValid(video.createdAt)).to.be.true
@@ -237,8 +237,8 @@ describe('Test a single pod', function () {
237 expect(video.languageLabel).to.equal('Mandarin') 237 expect(video.languageLabel).to.equal('Mandarin')
238 expect(video.nsfw).to.be.ok 238 expect(video.nsfw).to.be.ok
239 expect(video.description).to.equal('my super description') 239 expect(video.description).to.equal('my super description')
240 expect(video.podHost).to.equal('localhost:9001') 240 expect(video.serverHost).to.equal('localhost:9001')
241 expect(video.author).to.equal('root') 241 expect(video.account).to.equal('root')
242 expect(video.isLocal).to.be.true 242 expect(video.isLocal).to.be.true
243 expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'tag3' ]) 243 expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'tag3' ])
244 expect(dateIsValid(video.createdAt)).to.be.true 244 expect(dateIsValid(video.createdAt)).to.be.true
@@ -249,7 +249,7 @@ describe('Test a single pod', function () {
249 }) 249 })
250 250
251 // Not implemented yet 251 // Not implemented yet
252 // it('Should search the video by podHost', async function () { 252 // it('Should search the video by serverHost', async function () {
253 // const res = await videosUtils.searchVideo(server.url, '9001', 'host') 253 // const res = await videosUtils.searchVideo(server.url, '9001', 'host')
254 254
255 // expect(res.body.total).to.equal(1) 255 // expect(res.body.total).to.equal(1)
@@ -259,7 +259,7 @@ describe('Test a single pod', function () {
259 // const video = res.body.data[0] 259 // const video = res.body.data[0]
260 // expect(video.name).to.equal('my super name') 260 // expect(video.name).to.equal('my super name')
261 // expect(video.description).to.equal('my super description') 261 // expect(video.description).to.equal('my super description')
262 // expect(video.podHost).to.equal('localhost:9001') 262 // expect(video.serverHost).to.equal('localhost:9001')
263 // expect(video.author).to.equal('root') 263 // expect(video.author).to.equal('root')
264 // expect(video.isLocal).to.be.true 264 // expect(video.isLocal).to.be.true
265 // expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'tag3' ]) 265 // expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'tag3' ])
@@ -291,8 +291,8 @@ describe('Test a single pod', function () {
291 expect(video.languageLabel).to.equal('Mandarin') 291 expect(video.languageLabel).to.equal('Mandarin')
292 expect(video.nsfw).to.be.ok 292 expect(video.nsfw).to.be.ok
293 expect(video.description).to.equal('my super description') 293 expect(video.description).to.equal('my super description')
294 expect(video.podHost).to.equal('localhost:9001') 294 expect(video.serverHost).to.equal('localhost:9001')
295 expect(video.author).to.equal('root') 295 expect(video.account).to.equal('root')
296 expect(video.isLocal).to.be.true 296 expect(video.isLocal).to.be.true
297 expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'tag3' ]) 297 expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'tag3' ])
298 expect(dateIsValid(video.createdAt)).to.be.true 298 expect(dateIsValid(video.createdAt)).to.be.true
@@ -311,7 +311,7 @@ describe('Test a single pod', function () {
311 }) 311 })
312 312
313 it('Should not find a search by author', async function () { 313 it('Should not find a search by author', async function () {
314 const res = await searchVideo(server.url, 'hello', 'author') 314 const res = await searchVideo(server.url, 'hello', 'account')
315 315
316 expect(res.body.total).to.equal(0) 316 expect(res.body.total).to.equal(0)
317 expect(res.body.data).to.be.an('array') 317 expect(res.body.data).to.be.an('array')
@@ -352,7 +352,7 @@ describe('Test a single pod', function () {
352 'video_short1.webm', 'video_short2.webm', 'video_short3.webm' 352 'video_short1.webm', 'video_short2.webm', 'video_short3.webm'
353 ] 353 ]
354 354
355 const tasks: Promise<any>[] = [] 355 // const tasks: Promise<any>[] = []
356 for (const video of videos) { 356 for (const video of videos) {
357 const videoAttributes = { 357 const videoAttributes = {
358 name: video + ' name', 358 name: video + ' name',
@@ -366,10 +366,13 @@ describe('Test a single pod', function () {
366 } 366 }
367 367
368 const p = uploadVideo(server.url, server.accessToken, videoAttributes) 368 const p = uploadVideo(server.url, server.accessToken, videoAttributes)
369 tasks.push(p) 369 await p
370 } 370 }
371 371 // FIXME: concurrent uploads does not work :(
372 await Promise.all(tasks) 372 // tasks.push(p)
373 // }
374 //
375 // await Promise.all(tasks)
373 }) 376 })
374 377
375 it('Should have the correct durations', async function () { 378 it('Should have the correct durations', async function () {
@@ -462,7 +465,7 @@ describe('Test a single pod', function () {
462 }) 465 })
463 466
464 it('Should search all the root author videos', async function () { 467 it('Should search all the root author videos', async function () {
465 const res = await searchVideoWithPagination(server.url, 'root', 'author', 0, 15) 468 const res = await searchVideoWithPagination(server.url, 'root', 'account', 0, 15)
466 469
467 const videos = res.body.data 470 const videos = res.body.data
468 expect(res.body.total).to.equal(6) 471 expect(res.body.total).to.equal(6)
@@ -550,8 +553,8 @@ describe('Test a single pod', function () {
550 expect(video.languageLabel).to.equal('Arabic') 553 expect(video.languageLabel).to.equal('Arabic')
551 expect(video.nsfw).to.be.ok 554 expect(video.nsfw).to.be.ok
552 expect(video.description).to.equal('my super description updated') 555 expect(video.description).to.equal('my super description updated')
553 expect(video.podHost).to.equal('localhost:9001') 556 expect(video.serverHost).to.equal('localhost:9001')
554 expect(video.author).to.equal('root') 557 expect(video.account).to.equal('root')
555 expect(video.isLocal).to.be.true 558 expect(video.isLocal).to.be.true
556 expect(video.tags).to.deep.equal([ 'tagup1', 'tagup2' ]) 559 expect(video.tags).to.deep.equal([ 'tagup1', 'tagup2' ])
557 expect(dateIsValid(video.createdAt)).to.be.true 560 expect(dateIsValid(video.createdAt)).to.be.true
@@ -599,8 +602,8 @@ describe('Test a single pod', function () {
599 expect(video.languageLabel).to.equal('Arabic') 602 expect(video.languageLabel).to.equal('Arabic')
600 expect(video.nsfw).to.be.ok 603 expect(video.nsfw).to.be.ok
601 expect(video.description).to.equal('my super description updated') 604 expect(video.description).to.equal('my super description updated')
602 expect(video.podHost).to.equal('localhost:9001') 605 expect(video.serverHost).to.equal('localhost:9001')
603 expect(video.author).to.equal('root') 606 expect(video.account).to.equal('root')
604 expect(video.isLocal).to.be.true 607 expect(video.isLocal).to.be.true
605 expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'supertag' ]) 608 expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'supertag' ])
606 expect(dateIsValid(video.createdAt)).to.be.true 609 expect(dateIsValid(video.createdAt)).to.be.true
@@ -639,8 +642,8 @@ describe('Test a single pod', function () {
639 expect(video.languageLabel).to.equal('Arabic') 642 expect(video.languageLabel).to.equal('Arabic')
640 expect(video.nsfw).to.be.ok 643 expect(video.nsfw).to.be.ok
641 expect(video.description).to.equal('hello everybody') 644 expect(video.description).to.equal('hello everybody')
642 expect(video.podHost).to.equal('localhost:9001') 645 expect(video.serverHost).to.equal('localhost:9001')
643 expect(video.author).to.equal('root') 646 expect(video.account).to.equal('root')
644 expect(video.isLocal).to.be.true 647 expect(video.isLocal).to.be.true
645 expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'supertag' ]) 648 expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'supertag' ])
646 expect(dateIsValid(video.createdAt)).to.be.true 649 expect(dateIsValid(video.createdAt)).to.be.true
diff --git a/server/tests/api/users.ts b/server/tests/api/users.ts
index 6f40ca3c9..055dade04 100644
--- a/server/tests/api/users.ts
+++ b/server/tests/api/users.ts
@@ -1,38 +1,36 @@
1/* tslint:disable:no-unused-expression */ 1/* tslint:disable:no-unused-expression */
2
3import 'mocha'
4import * as chai from 'chai' 2import * as chai from 'chai'
5const expect = chai.expect 3import 'mocha'
6 4import { UserRole } from '../../../shared'
7import { 5import {
8 ServerInfo,
9 flushTests,
10 runServer,
11 login,
12 uploadVideo,
13 makeFriends,
14 quitFriends,
15 getVideosList,
16 rateVideo,
17 getUserVideoRating,
18 removeVideo,
19 makePutBodyRequest,
20 createUser, 6 createUser,
21 loginAndGetAccessToken, 7 flushTests,
8 getBlacklistedVideosList,
22 getMyUserInformation, 9 getMyUserInformation,
10 getUserInformation,
23 getUsersList, 11 getUsersList,
24 getUsersListPaginationAndSort, 12 getUsersListPaginationAndSort,
25 updateUser, 13 getUserVideoRating,
26 updateMyUser, 14 getVideosList,
15 killallServers,
16 login,
17 loginAndGetAccessToken,
18 makePutBodyRequest,
19 rateVideo,
27 registerUser, 20 registerUser,
28 removeUser, 21 removeUser,
29 killallServers, 22 removeVideo,
30 getUserInformation, 23 runServer,
31 getBlacklistedVideosList 24 ServerInfo,
25 updateMyUser,
26 updateUser,
27 uploadVideo
32} from '../utils' 28} from '../utils'
33import { UserRole } from '../../../shared' 29import { follow } from '../utils/follows'
34import { getMyVideos } from '../utils/videos' 30import { getMyVideos } from '../utils/videos'
35 31
32const expect = chai.expect
33
36describe('Test users', function () { 34describe('Test users', function () {
37 let server: ServerInfo 35 let server: ServerInfo
38 let accessToken: string 36 let accessToken: string
@@ -57,28 +55,36 @@ describe('Test users', function () {
57 const client = { id: 'client', secret: server.client.secret } 55 const client = { id: 'client', secret: server.client.secret }
58 const res = await login(server.url, client, server.user, 400) 56 const res = await login(server.url, client, server.user, 400)
59 57
60 expect(res.body.error).to.equal('invalid_client') 58 expect(res.body.error)
59 .to
60 .equal('invalid_client')
61 }) 61 })
62 62
63 it('Should not login with an invalid client secret', async function () { 63 it('Should not login with an invalid client secret', async function () {
64 const client = { id: server.client.id, secret: 'coucou' } 64 const client = { id: server.client.id, secret: 'coucou' }
65 const res = await login(server.url, client, server.user, 400) 65 const res = await login(server.url, client, server.user, 400)
66 66
67 expect(res.body.error).to.equal('invalid_client') 67 expect(res.body.error)
68 .to
69 .equal('invalid_client')
68 }) 70 })
69 71
70 it('Should not login with an invalid username', async function () { 72 it('Should not login with an invalid username', async function () {
71 const user = { username: 'captain crochet', password: server.user.password } 73 const user = { username: 'captain crochet', password: server.user.password }
72 const res = await login(server.url, server.client, user, 400) 74 const res = await login(server.url, server.client, user, 400)
73 75
74 expect(res.body.error).to.equal('invalid_grant') 76 expect(res.body.error)
77 .to
78 .equal('invalid_grant')
75 }) 79 })
76 80
77 it('Should not login with an invalid password', async function () { 81 it('Should not login with an invalid password', async function () {
78 const user = { username: server.user.username, password: 'mew_three' } 82 const user = { username: server.user.username, password: 'mew_three' }
79 const res = await login(server.url, server.client, user, 400) 83 const res = await login(server.url, server.client, user, 400)
80 84
81 expect(res.body.error).to.equal('invalid_grant') 85 expect(res.body.error)
86 .to
87 .equal('invalid_grant')
82 }) 88 })
83 89
84 it('Should not be able to upload a video', async function () { 90 it('Should not be able to upload a video', async function () {
@@ -88,15 +94,12 @@ describe('Test users', function () {
88 await uploadVideo(server.url, accessToken, videoAttributes, 401) 94 await uploadVideo(server.url, accessToken, videoAttributes, 401)
89 }) 95 })
90 96
91 it('Should not be able to make friends', async function () { 97 it('Should not be able to follow', async function () {
92 accessToken = 'my_super_token' 98 accessToken = 'my_super_token'
93 await makeFriends(server.url, accessToken, 401) 99 await follow(server.url, [ 'http://example.com' ], accessToken, 401)
94 }) 100 })
95 101
96 it('Should not be able to quit friends', async function () { 102 it('Should not be able to unfollow')
97 accessToken = 'my_super_token'
98 await quitFriends(server.url, accessToken, 401)
99 })
100 103
101 it('Should be able to login', async function () { 104 it('Should be able to login', async function () {
102 const res = await login(server.url, server.client, server.user, 200) 105 const res = await login(server.url, server.client, server.user, 200)
@@ -108,9 +111,11 @@ describe('Test users', function () {
108 const videoAttributes = {} 111 const videoAttributes = {}
109 await uploadVideo(server.url, accessToken, videoAttributes, 204) 112 await uploadVideo(server.url, accessToken, videoAttributes, 204)
110 const res = await getVideosList(server.url) 113 const res = await getVideosList(server.url)
111 const video = res.body.data[0] 114 const video = res.body.data[ 0 ]
112 115
113 expect(video.author).to.equal('root') 116 expect(video.account)
117 .to
118 .equal('root')
114 videoId = video.id 119 videoId = video.id
115 }) 120 })
116 121
@@ -124,8 +129,12 @@ describe('Test users', function () {
124 const res = await getUserVideoRating(server.url, accessToken, videoId) 129 const res = await getUserVideoRating(server.url, accessToken, videoId)
125 const rating = res.body 130 const rating = res.body
126 131
127 expect(rating.videoId).to.equal(videoId) 132 expect(rating.videoId)
128 expect(rating.rating).to.equal('like') 133 .to
134 .equal(videoId)
135 expect(rating.rating)
136 .to
137 .equal('like')
129 }) 138 })
130 139
131 it('Should not be able to remove the video with an incorrect token', async function () { 140 it('Should not be able to remove the video with an incorrect token', async function () {
@@ -187,12 +196,23 @@ describe('Test users', function () {
187 const res = await getMyUserInformation(server.url, accessTokenUser) 196 const res = await getMyUserInformation(server.url, accessTokenUser)
188 const user = res.body 197 const user = res.body
189 198
190 expect(user.username).to.equal('user_1') 199 expect(user.username)
191 expect(user.email).to.equal('user_1@example.com') 200 .to
201 .equal('user_1')
202 expect(user.email)
203 .to
204 .equal('user_1@example.com')
192 expect(user.displayNSFW).to.be.false 205 expect(user.displayNSFW).to.be.false
193 expect(user.videoQuota).to.equal(2 * 1024 * 1024) 206 expect(user.videoQuota)
194 expect(user.roleLabel).to.equal('User') 207 .to
195 expect(user.id).to.be.a('number') 208 .equal(2 * 1024 * 1024)
209 expect(user.roleLabel)
210 .to
211 .equal('User')
212 expect(user.id)
213 .to
214 .be
215 .a('number')
196 }) 216 })
197 217
198 it('Should be able to upload a video with this user', async function () { 218 it('Should be able to upload a video with this user', async function () {
@@ -206,12 +226,19 @@ describe('Test users', function () {
206 226
207 it('Should be able to list my videos', async function () { 227 it('Should be able to list my videos', async function () {
208 const res = await getMyVideos(server.url, accessTokenUser, 0, 5) 228 const res = await getMyVideos(server.url, accessTokenUser, 0, 5)
209 expect(res.body.total).to.equal(1) 229 expect(res.body.total)
230 .to
231 .equal(1)
210 232
211 const videos = res.body.data 233 const videos = res.body.data
212 expect(videos).to.have.lengthOf(1) 234 expect(videos)
235 .to
236 .have
237 .lengthOf(1)
213 238
214 expect(videos[0].name).to.equal('super user video') 239 expect(videos[ 0 ].name)
240 .to
241 .equal('super user video')
215 }) 242 })
216 243
217 it('Should list all the users', async function () { 244 it('Should list all the users', async function () {
@@ -220,18 +247,33 @@ describe('Test users', function () {
220 const total = result.total 247 const total = result.total
221 const users = result.data 248 const users = result.data
222 249
223 expect(total).to.equal(2) 250 expect(total)
224 expect(users).to.be.an('array') 251 .to
225 expect(users.length).to.equal(2) 252 .equal(2)
226 253 expect(users)
227 const user = users[0] 254 .to
228 expect(user.username).to.equal('user_1') 255 .be
229 expect(user.email).to.equal('user_1@example.com') 256 .an('array')
257 expect(users.length)
258 .to
259 .equal(2)
260
261 const user = users[ 0 ]
262 expect(user.username)
263 .to
264 .equal('user_1')
265 expect(user.email)
266 .to
267 .equal('user_1@example.com')
230 expect(user.displayNSFW).to.be.false 268 expect(user.displayNSFW).to.be.false
231 269
232 const rootUser = users[1] 270 const rootUser = users[ 1 ]
233 expect(rootUser.username).to.equal('root') 271 expect(rootUser.username)
234 expect(rootUser.email).to.equal('admin1@example.com') 272 .to
273 .equal('root')
274 expect(rootUser.email)
275 .to
276 .equal('admin1@example.com')
235 expect(rootUser.displayNSFW).to.be.false 277 expect(rootUser.displayNSFW).to.be.false
236 278
237 userId = user.id 279 userId = user.id
@@ -244,13 +286,23 @@ describe('Test users', function () {
244 const total = result.total 286 const total = result.total
245 const users = result.data 287 const users = result.data
246 288
247 expect(total).to.equal(2) 289 expect(total)
248 expect(users.length).to.equal(1) 290 .to
249 291 .equal(2)
250 const user = users[0] 292 expect(users.length)
251 expect(user.username).to.equal('root') 293 .to
252 expect(user.email).to.equal('admin1@example.com') 294 .equal(1)
253 expect(user.roleLabel).to.equal('Administrator') 295
296 const user = users[ 0 ]
297 expect(user.username)
298 .to
299 .equal('root')
300 expect(user.email)
301 .to
302 .equal('admin1@example.com')
303 expect(user.roleLabel)
304 .to
305 .equal('Administrator')
254 expect(user.displayNSFW).to.be.false 306 expect(user.displayNSFW).to.be.false
255 }) 307 })
256 308
@@ -260,12 +312,20 @@ describe('Test users', function () {
260 const total = result.total 312 const total = result.total
261 const users = result.data 313 const users = result.data
262 314
263 expect(total).to.equal(2) 315 expect(total)
264 expect(users.length).to.equal(1) 316 .to
265 317 .equal(2)
266 const user = users[0] 318 expect(users.length)
267 expect(user.username).to.equal('user_1') 319 .to
268 expect(user.email).to.equal('user_1@example.com') 320 .equal(1)
321
322 const user = users[ 0 ]
323 expect(user.username)
324 .to
325 .equal('user_1')
326 expect(user.email)
327 .to
328 .equal('user_1@example.com')
269 expect(user.displayNSFW).to.be.false 329 expect(user.displayNSFW).to.be.false
270 }) 330 })
271 331
@@ -275,12 +335,20 @@ describe('Test users', function () {
275 const total = result.total 335 const total = result.total
276 const users = result.data 336 const users = result.data
277 337
278 expect(total).to.equal(2) 338 expect(total)
279 expect(users.length).to.equal(1) 339 .to
280 340 .equal(2)
281 const user = users[0] 341 expect(users.length)
282 expect(user.username).to.equal('user_1') 342 .to
283 expect(user.email).to.equal('user_1@example.com') 343 .equal(1)
344
345 const user = users[ 0 ]
346 expect(user.username)
347 .to
348 .equal('user_1')
349 expect(user.email)
350 .to
351 .equal('user_1@example.com')
284 expect(user.displayNSFW).to.be.false 352 expect(user.displayNSFW).to.be.false
285 }) 353 })
286 354
@@ -290,16 +358,28 @@ describe('Test users', function () {
290 const total = result.total 358 const total = result.total
291 const users = result.data 359 const users = result.data
292 360
293 expect(total).to.equal(2) 361 expect(total)
294 expect(users.length).to.equal(2) 362 .to
295 363 .equal(2)
296 expect(users[0].username).to.equal('root') 364 expect(users.length)
297 expect(users[0].email).to.equal('admin1@example.com') 365 .to
298 expect(users[0].displayNSFW).to.be.false 366 .equal(2)
299 367
300 expect(users[1].username).to.equal('user_1') 368 expect(users[ 0 ].username)
301 expect(users[1].email).to.equal('user_1@example.com') 369 .to
302 expect(users[1].displayNSFW).to.be.false 370 .equal('root')
371 expect(users[ 0 ].email)
372 .to
373 .equal('admin1@example.com')
374 expect(users[ 0 ].displayNSFW).to.be.false
375
376 expect(users[ 1 ].username)
377 .to
378 .equal('user_1')
379 expect(users[ 1 ].email)
380 .to
381 .equal('user_1@example.com')
382 expect(users[ 1 ].displayNSFW).to.be.false
303 }) 383 })
304 384
305 it('Should update my password', async function () { 385 it('Should update my password', async function () {
@@ -315,11 +395,20 @@ describe('Test users', function () {
315 const res = await getMyUserInformation(server.url, accessTokenUser) 395 const res = await getMyUserInformation(server.url, accessTokenUser)
316 const user = res.body 396 const user = res.body
317 397
318 expect(user.username).to.equal('user_1') 398 expect(user.username)
319 expect(user.email).to.equal('user_1@example.com') 399 .to
400 .equal('user_1')
401 expect(user.email)
402 .to
403 .equal('user_1@example.com')
320 expect(user.displayNSFW).to.be.ok 404 expect(user.displayNSFW).to.be.ok
321 expect(user.videoQuota).to.equal(2 * 1024 * 1024) 405 expect(user.videoQuota)
322 expect(user.id).to.be.a('number') 406 .to
407 .equal(2 * 1024 * 1024)
408 expect(user.id)
409 .to
410 .be
411 .a('number')
323 }) 412 })
324 413
325 it('Should be able to change the email display attribute', async function () { 414 it('Should be able to change the email display attribute', async function () {
@@ -328,11 +417,20 @@ describe('Test users', function () {
328 const res = await getMyUserInformation(server.url, accessTokenUser) 417 const res = await getMyUserInformation(server.url, accessTokenUser)
329 const user = res.body 418 const user = res.body
330 419
331 expect(user.username).to.equal('user_1') 420 expect(user.username)
332 expect(user.email).to.equal('updated@example.com') 421 .to
422 .equal('user_1')
423 expect(user.email)
424 .to
425 .equal('updated@example.com')
333 expect(user.displayNSFW).to.be.ok 426 expect(user.displayNSFW).to.be.ok
334 expect(user.videoQuota).to.equal(2 * 1024 * 1024) 427 expect(user.videoQuota)
335 expect(user.id).to.be.a('number') 428 .to
429 .equal(2 * 1024 * 1024)
430 expect(user.id)
431 .to
432 .be
433 .a('number')
336 }) 434 })
337 435
338 it('Should be able to update another user', async function () { 436 it('Should be able to update another user', async function () {
@@ -341,12 +439,23 @@ describe('Test users', function () {
341 const res = await getUserInformation(server.url, accessToken, userId) 439 const res = await getUserInformation(server.url, accessToken, userId)
342 const user = res.body 440 const user = res.body
343 441
344 expect(user.username).to.equal('user_1') 442 expect(user.username)
345 expect(user.email).to.equal('updated2@example.com') 443 .to
444 .equal('user_1')
445 expect(user.email)
446 .to
447 .equal('updated2@example.com')
346 expect(user.displayNSFW).to.be.ok 448 expect(user.displayNSFW).to.be.ok
347 expect(user.videoQuota).to.equal(42) 449 expect(user.videoQuota)
348 expect(user.roleLabel).to.equal('Moderator') 450 .to
349 expect(user.id).to.be.a('number') 451 .equal(42)
452 expect(user.roleLabel)
453 .to
454 .equal('Moderator')
455 expect(user.id)
456 .to
457 .be
458 .a('number')
350 }) 459 })
351 460
352 it('Should not be able to delete a user by a moderator', async function () { 461 it('Should not be able to delete a user by a moderator', async function () {
@@ -369,10 +478,14 @@ describe('Test users', function () {
369 it('Should not have videos of this user', async function () { 478 it('Should not have videos of this user', async function () {
370 const res = await getVideosList(server.url) 479 const res = await getVideosList(server.url)
371 480
372 expect(res.body.total).to.equal(1) 481 expect(res.body.total)
482 .to
483 .equal(1)
373 484
374 const video = res.body.data[0] 485 const video = res.body.data[ 0 ]
375 expect(video.author).to.equal('root') 486 expect(video.account)
487 .to
488 .equal('root')
376 }) 489 })
377 490
378 it('Should register a new user', async function () { 491 it('Should register a new user', async function () {
@@ -392,14 +505,16 @@ describe('Test users', function () {
392 const res = await getMyUserInformation(server.url, accessToken) 505 const res = await getMyUserInformation(server.url, accessToken)
393 const user = res.body 506 const user = res.body
394 507
395 expect(user.videoQuota).to.equal(5 * 1024 * 1024) 508 expect(user.videoQuota)
509 .to
510 .equal(5 * 1024 * 1024)
396 }) 511 })
397 512
398 after(async function () { 513 after(async function () {
399 killallServers([ server ]) 514 killallServers([ server ])
400 515
401 // Keep the logs if the test failed 516 // Keep the logs if the test failed
402 if (this['ok']) { 517 if (this[ 'ok' ]) {
403 await flushTests() 518 await flushTests()
404 } 519 }
405 }) 520 })
diff --git a/server/tests/api/video-abuse.ts b/server/tests/api/video-abuse.ts
index f2a2c322a..bc21ee59b 100644
--- a/server/tests/api/video-abuse.ts
+++ b/server/tests/api/video-abuse.ts
@@ -1,22 +1,22 @@
1/* tslint:disable:no-unused-expression */ 1/* tslint:disable:no-unused-expression */
2 2
3import 'mocha'
4import * as chai from 'chai' 3import * as chai from 'chai'
5const expect = chai.expect 4import 'mocha'
6
7import { 5import {
8 ServerInfo,
9 flushAndRunMultipleServers, 6 flushAndRunMultipleServers,
10 uploadVideo, 7 flushTests,
11 makeFriends,
12 getVideosList,
13 wait,
14 setAccessTokensToServers,
15 getVideoAbusesList, 8 getVideoAbusesList,
16 reportVideoAbuse, 9 getVideosList,
17 killallServers, 10 killallServers,
18 flushTests 11 reportVideoAbuse,
12 ServerInfo,
13 setAccessTokensToServers,
14 uploadVideo,
15 wait
19} from '../utils' 16} from '../utils'
17import { doubleFollow } from '../utils/follows'
18
19const expect = chai.expect
20 20
21describe('Test video abuses', function () { 21describe('Test video abuses', function () {
22 let servers: ServerInfo[] = [] 22 let servers: ServerInfo[] = []
@@ -30,32 +30,32 @@ describe('Test video abuses', function () {
30 // Get the access tokens 30 // Get the access tokens
31 await setAccessTokensToServers(servers) 31 await setAccessTokensToServers(servers)
32 32
33 // Pod 1 makes friend with pod 2 33 // Server 1 and server 2 follow each other
34 await makeFriends(servers[0].url, servers[0].accessToken) 34 await doubleFollow(servers[0], servers[1])
35 35
36 // Upload some videos on each pods 36 // Upload some videos on each servers
37 const video1Attributes = { 37 const video1Attributes = {
38 name: 'my super name for pod 1', 38 name: 'my super name for server 1',
39 description: 'my super description for pod 1' 39 description: 'my super description for server 1'
40 } 40 }
41 await uploadVideo(servers[0].url, servers[0].accessToken, video1Attributes) 41 await uploadVideo(servers[0].url, servers[0].accessToken, video1Attributes)
42 42
43 const video2Attributes = { 43 const video2Attributes = {
44 name: 'my super name for pod 2', 44 name: 'my super name for server 2',
45 description: 'my super description for pod 2' 45 description: 'my super description for server 2'
46 } 46 }
47 await uploadVideo(servers[1].url, servers[1].accessToken, video2Attributes) 47 await uploadVideo(servers[1].url, servers[1].accessToken, video2Attributes)
48 48
49 // Wait videos propagation 49 // Wait videos propagation
50 await wait(22000) 50 await wait(25000)
51 51
52 const res = await getVideosList(servers[0].url) 52 const res = await getVideosList(servers[0].url)
53 const videos = res.body.data 53 const videos = res.body.data
54 54
55 expect(videos.length).to.equal(2) 55 expect(videos.length).to.equal(2)
56 56
57 servers[0].video = videos.find(video => video.name === 'my super name for pod 1') 57 servers[0].video = videos.find(video => video.name === 'my super name for server 1')
58 servers[1].video = videos.find(video => video.name === 'my super name for pod 2') 58 servers[1].video = videos.find(video => video.name === 'my super name for server 2')
59 }) 59 })
60 60
61 it('Should not have video abuses', async function () { 61 it('Should not have video abuses', async function () {
@@ -72,11 +72,11 @@ describe('Test video abuses', function () {
72 const reason = 'my super bad reason' 72 const reason = 'my super bad reason'
73 await reportVideoAbuse(servers[0].url, servers[0].accessToken, servers[0].video.id, reason) 73 await reportVideoAbuse(servers[0].url, servers[0].accessToken, servers[0].video.id, reason)
74 74
75 // We wait requests propagation, even if the pod 1 is not supposed to make a request to pod 2 75 // We wait requests propagation, even if the server 1 is not supposed to make a request to server 2
76 await wait(11000) 76 await wait(11000)
77 }) 77 })
78 78
79 it('Should have 1 video abuses on pod 1 and 0 on pod 2', async function () { 79 it('Should have 1 video abuses on server 1 and 0 on server 2', async function () {
80 const res1 = await getVideoAbusesList(servers[0].url, servers[0].accessToken) 80 const res1 = await getVideoAbusesList(servers[0].url, servers[0].accessToken)
81 81
82 expect(res1.body.total).to.equal(1) 82 expect(res1.body.total).to.equal(1)
@@ -86,7 +86,7 @@ describe('Test video abuses', function () {
86 const abuse = res1.body.data[0] 86 const abuse = res1.body.data[0]
87 expect(abuse.reason).to.equal('my super bad reason') 87 expect(abuse.reason).to.equal('my super bad reason')
88 expect(abuse.reporterUsername).to.equal('root') 88 expect(abuse.reporterUsername).to.equal('root')
89 expect(abuse.reporterPodHost).to.equal('localhost:9001') 89 expect(abuse.reporterServerHost).to.equal('localhost:9001')
90 expect(abuse.videoId).to.equal(servers[0].video.id) 90 expect(abuse.videoId).to.equal(servers[0].video.id)
91 91
92 const res2 = await getVideoAbusesList(servers[1].url, servers[1].accessToken) 92 const res2 = await getVideoAbusesList(servers[1].url, servers[1].accessToken)
@@ -96,16 +96,16 @@ describe('Test video abuses', function () {
96 }) 96 })
97 97
98 it('Should report abuse on a remote video', async function () { 98 it('Should report abuse on a remote video', async function () {
99 this.timeout(15000) 99 this.timeout(25000)
100 100
101 const reason = 'my super bad reason 2' 101 const reason = 'my super bad reason 2'
102 await reportVideoAbuse(servers[0].url, servers[0].accessToken, servers[1].video.id, reason) 102 await reportVideoAbuse(servers[0].url, servers[0].accessToken, servers[1].video.id, reason)
103 103
104 // We wait requests propagation 104 // We wait requests propagation
105 await wait(11000) 105 await wait(15000)
106 }) 106 })
107 107
108 it('Should have 2 video abuse on pod 1 and 1 on pod 2', async function () { 108 it('Should have 2 video abuse on server 1 and 1 on server 2', async function () {
109 const res1 = await getVideoAbusesList(servers[0].url, servers[0].accessToken) 109 const res1 = await getVideoAbusesList(servers[0].url, servers[0].accessToken)
110 expect(res1.body.total).to.equal(2) 110 expect(res1.body.total).to.equal(2)
111 expect(res1.body.data).to.be.an('array') 111 expect(res1.body.data).to.be.an('array')
@@ -114,13 +114,13 @@ describe('Test video abuses', function () {
114 const abuse1 = res1.body.data[0] 114 const abuse1 = res1.body.data[0]
115 expect(abuse1.reason).to.equal('my super bad reason') 115 expect(abuse1.reason).to.equal('my super bad reason')
116 expect(abuse1.reporterUsername).to.equal('root') 116 expect(abuse1.reporterUsername).to.equal('root')
117 expect(abuse1.reporterPodHost).to.equal('localhost:9001') 117 expect(abuse1.reporterServerHost).to.equal('localhost:9001')
118 expect(abuse1.videoId).to.equal(servers[0].video.id) 118 expect(abuse1.videoId).to.equal(servers[0].video.id)
119 119
120 const abuse2 = res1.body.data[1] 120 const abuse2 = res1.body.data[1]
121 expect(abuse2.reason).to.equal('my super bad reason 2') 121 expect(abuse2.reason).to.equal('my super bad reason 2')
122 expect(abuse2.reporterUsername).to.equal('root') 122 expect(abuse2.reporterUsername).to.equal('root')
123 expect(abuse2.reporterPodHost).to.equal('localhost:9001') 123 expect(abuse2.reporterServerHost).to.equal('localhost:9001')
124 expect(abuse2.videoId).to.equal(servers[1].video.id) 124 expect(abuse2.videoId).to.equal(servers[1].video.id)
125 125
126 const res2 = await getVideoAbusesList(servers[1].url, servers[1].accessToken) 126 const res2 = await getVideoAbusesList(servers[1].url, servers[1].accessToken)
@@ -131,7 +131,7 @@ describe('Test video abuses', function () {
131 const abuse3 = res2.body.data[0] 131 const abuse3 = res2.body.data[0]
132 expect(abuse3.reason).to.equal('my super bad reason 2') 132 expect(abuse3.reason).to.equal('my super bad reason 2')
133 expect(abuse3.reporterUsername).to.equal('root') 133 expect(abuse3.reporterUsername).to.equal('root')
134 expect(abuse3.reporterPodHost).to.equal('localhost:9001') 134 expect(abuse3.reporterServerHost).to.equal('localhost:9001')
135 }) 135 })
136 136
137 after(async function () { 137 after(async function () {
diff --git a/server/tests/utils/follows.ts b/server/tests/utils/follows.ts
index 9ad1ca7f4..b454fe2f8 100644
--- a/server/tests/utils/follows.ts
+++ b/server/tests/utils/follows.ts
@@ -1,9 +1,9 @@
1import * as request from 'supertest' 1import * as request from 'supertest'
2
3import { wait } from './miscs' 2import { wait } from './miscs'
3import { ServerInfo } from './servers'
4 4
5function getFollowersListPaginationAndSort (url: string, start: number, count: number, sort: string) { 5function getFollowersListPaginationAndSort (url: string, start: number, count: number, sort: string) {
6 const path = '/api/v1/servers/followers' 6 const path = '/api/v1/server/followers'
7 7
8 return request(url) 8 return request(url)
9 .get(path) 9 .get(path)
@@ -16,7 +16,7 @@ function getFollowersListPaginationAndSort (url: string, start: number, count: n
16} 16}
17 17
18function getFollowingListPaginationAndSort (url: string, start: number, count: number, sort: string) { 18function getFollowingListPaginationAndSort (url: string, start: number, count: number, sort: string) {
19 const path = '/api/v1/servers/following' 19 const path = '/api/v1/server/following'
20 20
21 return request(url) 21 return request(url)
22 .get(path) 22 .get(path)
@@ -29,25 +29,36 @@ function getFollowingListPaginationAndSort (url: string, start: number, count: n
29} 29}
30 30
31async function follow (follower: string, following: string[], accessToken: string, expectedStatus = 204) { 31async function follow (follower: string, following: string[], accessToken: string, expectedStatus = 204) {
32 const path = '/api/v1/servers/follow' 32 const path = '/api/v1/server/follow'
33 33
34 const followingHosts = following.map(f => f.replace(/^http:\/\//, ''))
34 const res = await request(follower) 35 const res = await request(follower)
35 .post(path) 36 .post(path)
36 .set('Accept', 'application/json') 37 .set('Accept', 'application/json')
37 .set('Authorization', 'Bearer ' + accessToken) 38 .set('Authorization', 'Bearer ' + accessToken)
38 .send({ 'hosts': following }) 39 .send({ 'hosts': followingHosts })
39 .expect(expectedStatus) 40 .expect(expectedStatus)
40 41
41 // Wait request propagation 42 // Wait request propagation
42 await wait(1000) 43 await wait(20000)
43 44
44 return res 45 return res
45} 46}
46 47
48async function doubleFollow (server1: ServerInfo, server2: ServerInfo) {
49 await Promise.all([
50 follow(server1.url, [ server2.url ], server1.accessToken),
51 follow(server2.url, [ server1.url ], server2.accessToken)
52 ])
53
54 return true
55}
56
47// --------------------------------------------------------------------------- 57// ---------------------------------------------------------------------------
48 58
49export { 59export {
50 getFollowersListPaginationAndSort, 60 getFollowersListPaginationAndSort,
51 getFollowingListPaginationAndSort, 61 getFollowingListPaginationAndSort,
52 follow 62 follow,
63 doubleFollow
53} 64}
diff --git a/server/tests/utils/servers.ts b/server/tests/utils/servers.ts
index f042a9e53..faa2f19ff 100644
--- a/server/tests/utils/servers.ts
+++ b/server/tests/utils/servers.ts
@@ -24,7 +24,7 @@ interface ServerInfo {
24 id: number 24 id: number
25 uuid: string 25 uuid: string
26 name: string 26 name: string
27 author: string 27 account: string
28 } 28 }
29 29
30 remoteVideo?: { 30 remoteVideo?: {
diff --git a/shared/models/activitypub/activity.ts b/shared/models/activitypub/activity.ts
index f8e982fbb..6a05a1c39 100644
--- a/shared/models/activitypub/activity.ts
+++ b/shared/models/activitypub/activity.ts
@@ -11,10 +11,10 @@ export type ActivityType = 'Create' | 'Add' | 'Update' | 'Flag' | 'Delete' | 'Fo
11export interface BaseActivity { 11export interface BaseActivity {
12 '@context'?: any[] 12 '@context'?: any[]
13 id: string 13 id: string
14 to: string[] 14 to?: string[]
15 actor: string 15 actor: string
16 type: ActivityType 16 type: ActivityType
17 signature: ActivityPubSignature 17 signature?: ActivityPubSignature
18} 18}
19 19
20export interface ActivityCreate extends BaseActivity { 20export interface ActivityCreate extends BaseActivity {
diff --git a/shared/models/job.model.ts b/shared/models/job.model.ts
index ab723084a..10696e3f8 100644
--- a/shared/models/job.model.ts
+++ b/shared/models/job.model.ts
@@ -1,2 +1,2 @@
1export type JobState = 'pending' | 'processing' | 'error' | 'success' 1export type JobState = 'pending' | 'processing' | 'error' | 'success'
2export type JobCategory = 'transcoding' | 'http-request' 2export type JobCategory = 'transcoding' | 'activitypub-http'
diff --git a/yarn.lock b/yarn.lock
index 773ff7350..695a610d7 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -107,7 +107,11 @@
107 dependencies: 107 dependencies:
108 "@types/express" "*" 108 "@types/express" "*"
109 109
110"@types/node@*", "@types/node@^8.0.3": 110"@types/node@*":
111 version "8.0.53"
112 resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.53.tgz#396b35af826fa66aad472c8cb7b8d5e277f4e6d8"
113
114"@types/node@^8.0.3":
111 version "8.0.47" 115 version "8.0.47"
112 resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.47.tgz#968e596f91acd59069054558a00708c445ca30c2" 116 resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.47.tgz#968e596f91acd59069054558a00708c445ca30c2"
113 117
@@ -2717,8 +2721,8 @@ moment-timezone@^0.5.4:
2717 moment ">= 2.9.0" 2721 moment ">= 2.9.0"
2718 2722
2719"moment@>= 2.9.0", moment@^2.13.0: 2723"moment@>= 2.9.0", moment@^2.13.0:
2720 version "2.19.1" 2724 version "2.19.2"
2721 resolved "https://registry.yarnpkg.com/moment/-/moment-2.19.1.tgz#56da1a2d1cbf01d38b7e1afc31c10bcfa1929167" 2725 resolved "https://registry.yarnpkg.com/moment/-/moment-2.19.2.tgz#8a7f774c95a64550b4c7ebd496683908f9419dbe"
2722 2726
2723morgan@^1.5.3: 2727morgan@^1.5.3:
2724 version "1.9.0" 2728 version "1.9.0"
@@ -3647,8 +3651,8 @@ send@0.16.1:
3647 statuses "~1.3.1" 3651 statuses "~1.3.1"
3648 3652
3649sequelize@^4.7.5: 3653sequelize@^4.7.5:
3650 version "4.22.5" 3654 version "4.22.7"
3651 resolved "https://registry.yarnpkg.com/sequelize/-/sequelize-4.22.5.tgz#5771f8dc2173c61366d77b9fb89aeb34b0522435" 3655 resolved "https://registry.yarnpkg.com/sequelize/-/sequelize-4.22.7.tgz#9425ad640f9813455cdc49cbeaf54aece141d76e"
3652 dependencies: 3656 dependencies:
3653 bluebird "^3.4.6" 3657 bluebird "^3.4.6"
3654 cls-bluebird "^2.0.1" 3658 cls-bluebird "^2.0.1"