]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/tests/api/videos/multiple-servers.ts
We don't need to import mocha
[github/Chocobozzz/PeerTube.git] / server / tests / api / videos / multiple-servers.ts
CommitLineData
a1587156 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
0e1dc3e7 2
2b02c520 3import * as chai from 'chai'
41fb13c3 4import request from 'supertest'
0e1dc3e7 5import {
89231874 6 checkTmpIsEmpty,
7243f84d 7 checkVideoFilesWereRemoved,
c55e3d72
C
8 completeVideoCheck,
9 dateIsValid,
10 saveVideoInServers,
11 testImage
12} from '@server/tests/shared'
13import { buildAbsoluteFixturePath, wait } from '@shared/core-utils'
14import { HttpStatusCode, VideoCommentThreadTree, VideoPrivacy } from '@shared/models'
15import {
7243f84d 16 cleanupTests,
4c7e60bc 17 createMultipleServers,
b64c950a 18 doubleFollow,
242f5225 19 makeGetRequest,
254d3579 20 PeerTubeServer,
b64c950a 21 setAccessTokensToServers,
d0800f76 22 setDefaultAccountAvatar,
23 setDefaultChannelAvatar,
12edc149 24 waitJobs,
b64c950a 25 webtorrentAdd
bf54587a 26} from '@shared/server-commands'
0e1dc3e7
C
27
28const expect = chai.expect
29
9a27cdc2 30describe('Test multiple servers', function () {
254d3579 31 let servers: PeerTubeServer[] = []
0e1dc3e7
C
32 const toRemove = []
33 let videoUUID = ''
5f04dd2f 34 let videoChannelId: number
0e1dc3e7
C
35
36 before(async function () {
37 this.timeout(120000)
38
254d3579 39 servers = await createMultipleServers(3)
0e1dc3e7
C
40
41 // Get the access tokens
42 await setAccessTokensToServers(servers)
43
48dce1c9
C
44 {
45 const videoChannel = {
8a19bee1 46 name: 'super_channel_name',
08c1efbe 47 displayName: 'my channel',
48dce1c9
C
48 description: 'super channel'
49 }
89d241a7 50 await servers[0].channels.create({ attributes: videoChannel })
d0800f76 51 await setDefaultChannelAvatar(servers[0], videoChannel.name)
52 await setDefaultAccountAvatar(servers)
53
89d241a7 54 const { data } = await servers[0].channels.list({ start: 0, count: 1 })
a5461888 55 videoChannelId = data[0].id
5f04dd2f 56 }
5f04dd2f 57
9a27cdc2
C
58 // Server 1 and server 2 follow each other
59 await doubleFollow(servers[0], servers[1])
60 // Server 1 and server 3 follow each other
61 await doubleFollow(servers[0], servers[2])
62 // Server 2 and server 3 follow each other
63 await doubleFollow(servers[1], servers[2])
0e1dc3e7
C
64 })
65
9a27cdc2 66 it('Should not have videos for all servers', async function () {
0e1dc3e7 67 for (const server of servers) {
89d241a7 68 const { data } = await server.videos.list()
d23dd9fb
C
69 expect(data).to.be.an('array')
70 expect(data.length).to.equal(0)
0e1dc3e7
C
71 }
72 })
73
9a27cdc2
C
74 describe('Should upload the video and propagate on each server', function () {
75 it('Should upload the video on server 1 and propagate on each server', async function () {
652b3056 76 this.timeout(25000)
0e1dc3e7 77
d23dd9fb 78 const attributes = {
9a27cdc2 79 name: 'my super name for server 1',
0e1dc3e7
C
80 category: 5,
81 licence: 4,
9d3ef9fe 82 language: 'ja',
0e1dc3e7 83 nsfw: true,
9a27cdc2 84 description: 'my super description for server 1',
2422c46b 85 support: 'my super support text for server 1',
7519127b 86 originallyPublishedAt: '2019-02-10T13:38:14.449Z',
0e1dc3e7 87 tags: [ 'tag1p1', 'tag2p1' ],
5f04dd2f 88 channelId: videoChannelId,
0e1dc3e7
C
89 fixture: 'video_short1.webm'
90 }
89d241a7 91 await servers[0].videos.upload({ attributes })
0e1dc3e7 92
3cd0734f 93 await waitJobs(servers)
0e1dc3e7 94
9a27cdc2 95 // All servers should have this video
53a61317 96 let publishedAt: string = null
0e1dc3e7 97 for (const server of servers) {
48f07b4a 98 const isLocal = server.port === servers[0].port
b1f5b93e
C
99 const checkAttributes = {
100 name: 'my super name for server 1',
101 category: 5,
102 licence: 4,
9d3ef9fe 103 language: 'ja',
b1f5b93e
C
104 nsfw: true,
105 description: 'my super description for server 1',
2422c46b 106 support: 'my super support text for server 1',
7519127b 107 originallyPublishedAt: '2019-02-10T13:38:14.449Z',
b64c950a
C
108 account: {
109 name: 'root',
7243f84d 110 host: 'localhost:' + servers[0].port
b64c950a 111 },
b1f5b93e 112 isLocal,
53a61317 113 publishedAt,
b1f5b93e
C
114 duration: 10,
115 tags: [ 'tag1p1', 'tag2p1' ],
116 privacy: VideoPrivacy.PUBLIC,
47564bbe 117 commentsEnabled: true,
7f2cfe3a 118 downloadEnabled: true,
b1f5b93e 119 channel: {
f6eebcb3
C
120 displayName: 'my channel',
121 name: 'super_channel_name',
b1f5b93e
C
122 description: 'super channel',
123 isLocal
124 },
8b0d42ee 125 fixture: 'video_short1.webm',
b1f5b93e
C
126 files: [
127 {
128 resolution: 720,
129 size: 572456
130 }
131 ]
132 }
0e1dc3e7 133
89d241a7 134 const { data } = await server.videos.list()
d23dd9fb
C
135 expect(data).to.be.an('array')
136 expect(data.length).to.equal(1)
137 const video = data[0]
0e1dc3e7 138
d23dd9fb
C
139 await completeVideoCheck(server, video, checkAttributes)
140 publishedAt = video.publishedAt as string
242f5225
C
141
142 expect(video.channel.avatars).to.have.lengthOf(2)
143 expect(video.account.avatars).to.have.lengthOf(2)
144
145 for (const image of [ ...video.channel.avatars, ...video.account.avatars ]) {
146 expect(image.createdAt).to.exist
147 expect(image.updatedAt).to.exist
148 expect(image.width).to.be.above(20).and.below(1000)
149 expect(image.path).to.exist
150
151 await makeGetRequest({
152 url: server.url,
153 path: image.path,
154 expectedStatus: HttpStatusCode.OK_200
155 })
156 }
0e1dc3e7
C
157 }
158 })
159
9a27cdc2 160 it('Should upload the video on server 2 and propagate on each server', async function () {
f1273314 161 this.timeout(100000)
0e1dc3e7 162
5f04dd2f
C
163 const user = {
164 username: 'user1',
165 password: 'super_password'
166 }
89d241a7
C
167 await servers[1].users.create({ username: user.username, password: user.password })
168 const userAccessToken = await servers[1].login.getAccessToken(user)
5f04dd2f 169
d23dd9fb 170 const attributes = {
9a27cdc2 171 name: 'my super name for server 2',
0e1dc3e7
C
172 category: 4,
173 licence: 3,
9d3ef9fe 174 language: 'de',
0e1dc3e7 175 nsfw: true,
9a27cdc2 176 description: 'my super description for server 2',
2422c46b 177 support: 'my super support text for server 2',
0e1dc3e7 178 tags: [ 'tag1p2', 'tag2p2', 'tag3p2' ],
ac81d1a0
C
179 fixture: 'video_short2.webm',
180 thumbnailfile: 'thumbnail.jpg',
181 previewfile: 'preview.jpg'
0e1dc3e7 182 }
89d241a7 183 await servers[1].videos.upload({ token: userAccessToken, attributes, mode: 'resumable' })
0e1dc3e7 184
572f8d3d 185 // Transcoding
3cd0734f 186 await waitJobs(servers)
0e1dc3e7 187
9a27cdc2 188 // All servers should have this video
0e1dc3e7 189 for (const server of servers) {
7243f84d 190 const isLocal = server.url === 'http://localhost:' + servers[1].port
b1f5b93e
C
191 const checkAttributes = {
192 name: 'my super name for server 2',
193 category: 4,
194 licence: 3,
9d3ef9fe 195 language: 'de',
b1f5b93e
C
196 nsfw: true,
197 description: 'my super description for server 2',
2422c46b 198 support: 'my super support text for server 2',
b64c950a
C
199 account: {
200 name: 'user1',
7243f84d 201 host: 'localhost:' + servers[1].port
b64c950a 202 },
b1f5b93e 203 isLocal,
47564bbe 204 commentsEnabled: true,
7f2cfe3a 205 downloadEnabled: true,
b1f5b93e
C
206 duration: 5,
207 tags: [ 'tag1p2', 'tag2p2', 'tag3p2' ],
208 privacy: VideoPrivacy.PUBLIC,
209 channel: {
f6eebcb3
C
210 displayName: 'Main user1 channel',
211 name: 'user1_channel',
b1f5b93e
C
212 description: 'super channel',
213 isLocal
214 },
215 fixture: 'video_short2.webm',
216 files: [
217 {
218 resolution: 240,
33ff70ba 219 size: 270000
b1f5b93e
C
220 },
221 {
222 resolution: 360,
33ff70ba 223 size: 359000
b1f5b93e
C
224 },
225 {
226 resolution: 480,
33ff70ba 227 size: 465000
b1f5b93e
C
228 },
229 {
230 resolution: 720,
d0800f76 231 size: 750000
b1f5b93e 232 }
ac81d1a0
C
233 ],
234 thumbnailfile: 'thumbnail',
235 previewfile: 'preview'
b1f5b93e 236 }
0e1dc3e7 237
89d241a7 238 const { data } = await server.videos.list()
d23dd9fb
C
239 expect(data).to.be.an('array')
240 expect(data.length).to.equal(2)
241 const video = data[1]
0e1dc3e7 242
d23dd9fb 243 await completeVideoCheck(server, video, checkAttributes)
0e1dc3e7
C
244 }
245 })
246
9a27cdc2 247 it('Should upload two videos on server 3 and propagate on each server', async function () {
0e1dc3e7
C
248 this.timeout(45000)
249
d23dd9fb
C
250 {
251 const attributes = {
252 name: 'my super name for server 3',
253 category: 6,
254 licence: 5,
255 language: 'de',
256 nsfw: true,
257 description: 'my super description for server 3',
258 support: 'my super support text for server 3',
259 tags: [ 'tag1p3' ],
260 fixture: 'video_short3.webm'
261 }
89d241a7 262 await servers[2].videos.upload({ attributes })
0e1dc3e7 263 }
d23dd9fb
C
264
265 {
266 const attributes = {
267 name: 'my super name for server 3-2',
268 category: 7,
269 licence: 6,
270 language: 'ko',
271 nsfw: false,
272 description: 'my super description for server 3-2',
273 support: 'my super support text for server 3-2',
274 tags: [ 'tag2p3', 'tag3p3', 'tag4p3' ],
275 fixture: 'video_short.webm'
276 }
89d241a7 277 await servers[2].videos.upload({ attributes })
0e1dc3e7 278 }
0e1dc3e7 279
3cd0734f 280 await waitJobs(servers)
0e1dc3e7 281
9a27cdc2 282 // All servers should have this video
0e1dc3e7 283 for (const server of servers) {
7243f84d 284 const isLocal = server.url === 'http://localhost:' + servers[2].port
89d241a7 285 const { data } = await server.videos.list()
0e1dc3e7 286
d23dd9fb
C
287 expect(data).to.be.an('array')
288 expect(data.length).to.equal(4)
0e1dc3e7
C
289
290 // We not sure about the order of the two last uploads
291 let video1 = null
292 let video2 = null
d23dd9fb
C
293 if (data[2].name === 'my super name for server 3') {
294 video1 = data[2]
295 video2 = data[3]
0e1dc3e7 296 } else {
d23dd9fb
C
297 video1 = data[3]
298 video2 = data[2]
0e1dc3e7
C
299 }
300
b1f5b93e
C
301 const checkAttributesVideo1 = {
302 name: 'my super name for server 3',
303 category: 6,
304 licence: 5,
9d3ef9fe 305 language: 'de',
b1f5b93e
C
306 nsfw: true,
307 description: 'my super description for server 3',
2422c46b 308 support: 'my super support text for server 3',
b64c950a
C
309 account: {
310 name: 'root',
7243f84d 311 host: 'localhost:' + servers[2].port
b64c950a 312 },
b1f5b93e
C
313 isLocal,
314 duration: 5,
47564bbe 315 commentsEnabled: true,
7f2cfe3a 316 downloadEnabled: true,
b1f5b93e
C
317 tags: [ 'tag1p3' ],
318 privacy: VideoPrivacy.PUBLIC,
319 channel: {
f6eebcb3
C
320 displayName: 'Main root channel',
321 name: 'root_channel',
b1f5b93e
C
322 description: '',
323 isLocal
324 },
325 fixture: 'video_short3.webm',
326 files: [
327 {
328 resolution: 720,
329 size: 292677
330 }
331 ]
0e1dc3e7 332 }
d23dd9fb 333 await completeVideoCheck(server, video1, checkAttributesVideo1)
b1f5b93e
C
334
335 const checkAttributesVideo2 = {
336 name: 'my super name for server 3-2',
337 category: 7,
338 licence: 6,
9d3ef9fe 339 language: 'ko',
b1f5b93e
C
340 nsfw: false,
341 description: 'my super description for server 3-2',
2422c46b 342 support: 'my super support text for server 3-2',
b64c950a
C
343 account: {
344 name: 'root',
7243f84d 345 host: 'localhost:' + servers[2].port
b64c950a 346 },
47564bbe 347 commentsEnabled: true,
7f2cfe3a 348 downloadEnabled: true,
b1f5b93e
C
349 isLocal,
350 duration: 5,
351 tags: [ 'tag2p3', 'tag3p3', 'tag4p3' ],
352 privacy: VideoPrivacy.PUBLIC,
353 channel: {
f6eebcb3
C
354 displayName: 'Main root channel',
355 name: 'root_channel',
b1f5b93e
C
356 description: '',
357 isLocal
358 },
8b0d42ee 359 fixture: 'video_short.webm',
b1f5b93e
C
360 files: [
361 {
362 resolution: 720,
363 size: 218910
364 }
365 ]
0e1dc3e7 366 }
d23dd9fb 367 await completeVideoCheck(server, video2, checkAttributesVideo2)
0e1dc3e7
C
368 }
369 })
370 })
371
066e94c5
C
372 describe('It should list local videos', function () {
373 it('Should list only local videos on server 1', async function () {
2760b454 374 const { data, total } = await servers[0].videos.list({ isLocal: true })
066e94c5 375
d23dd9fb
C
376 expect(total).to.equal(1)
377 expect(data).to.be.an('array')
378 expect(data.length).to.equal(1)
379 expect(data[0].name).to.equal('my super name for server 1')
066e94c5
C
380 })
381
382 it('Should list only local videos on server 2', async function () {
2760b454 383 const { data, total } = await servers[1].videos.list({ isLocal: true })
066e94c5 384
d23dd9fb
C
385 expect(total).to.equal(1)
386 expect(data).to.be.an('array')
387 expect(data.length).to.equal(1)
388 expect(data[0].name).to.equal('my super name for server 2')
066e94c5
C
389 })
390
391 it('Should list only local videos on server 3', async function () {
2760b454 392 const { data, total } = await servers[2].videos.list({ isLocal: true })
066e94c5 393
d23dd9fb
C
394 expect(total).to.equal(2)
395 expect(data).to.be.an('array')
396 expect(data.length).to.equal(2)
397 expect(data[0].name).to.equal('my super name for server 3')
398 expect(data[1].name).to.equal('my super name for server 3-2')
066e94c5
C
399 })
400 })
401
0e1dc3e7 402 describe('Should seed the uploaded video', function () {
9a27cdc2 403 it('Should add the file 1 by asking server 3', async function () {
b18a501a 404 this.timeout(30000)
0e1dc3e7 405
89d241a7 406 const { data } = await servers[2].videos.list()
0e1dc3e7 407
d23dd9fb
C
408 const video = data[0]
409 toRemove.push(data[2])
410 toRemove.push(data[3])
5f04dd2f 411
89d241a7 412 const videoDetails = await servers[2].videos.get({ id: video.id })
b1f5b93e 413 const torrent = await webtorrentAdd(videoDetails.files[0].magnetUri, true)
0e1dc3e7
C
414 expect(torrent.files).to.be.an('array')
415 expect(torrent.files.length).to.equal(1)
416 expect(torrent.files[0].path).to.exist.and.to.not.equal('')
417 })
418
9a27cdc2 419 it('Should add the file 2 by asking server 1', async function () {
b18a501a 420 this.timeout(30000)
0e1dc3e7 421
89d241a7 422 const { data } = await servers[0].videos.list()
0e1dc3e7 423
d23dd9fb 424 const video = data[1]
89d241a7 425 const videoDetails = await servers[0].videos.get({ id: video.id })
0e1dc3e7 426
b1f5b93e 427 const torrent = await webtorrentAdd(videoDetails.files[0].magnetUri, true)
0e1dc3e7
C
428 expect(torrent.files).to.be.an('array')
429 expect(torrent.files.length).to.equal(1)
430 expect(torrent.files[0].path).to.exist.and.to.not.equal('')
431 })
432
9a27cdc2 433 it('Should add the file 3 by asking server 2', async function () {
b18a501a 434 this.timeout(30000)
0e1dc3e7 435
89d241a7 436 const { data } = await servers[1].videos.list()
0e1dc3e7 437
d23dd9fb 438 const video = data[2]
89d241a7 439 const videoDetails = await servers[1].videos.get({ id: video.id })
0e1dc3e7 440
b1f5b93e 441 const torrent = await webtorrentAdd(videoDetails.files[0].magnetUri, true)
0e1dc3e7
C
442 expect(torrent.files).to.be.an('array')
443 expect(torrent.files.length).to.equal(1)
444 expect(torrent.files[0].path).to.exist.and.to.not.equal('')
445 })
446
9a27cdc2 447 it('Should add the file 3-2 by asking server 1', async function () {
b18a501a 448 this.timeout(30000)
0e1dc3e7 449
89d241a7 450 const { data } = await servers[0].videos.list()
0e1dc3e7 451
d23dd9fb 452 const video = data[3]
89d241a7 453 const videoDetails = await servers[0].videos.get({ id: video.id })
0e1dc3e7 454
5f04dd2f 455 const torrent = await webtorrentAdd(videoDetails.files[0].magnetUri)
0e1dc3e7
C
456 expect(torrent.files).to.be.an('array')
457 expect(torrent.files.length).to.equal(1)
458 expect(torrent.files[0].path).to.exist.and.to.not.equal('')
459 })
14d3270f 460
9a27cdc2 461 it('Should add the file 2 in 360p by asking server 1', async function () {
b18a501a 462 this.timeout(30000)
14d3270f 463
89d241a7 464 const { data } = await servers[0].videos.list()
14d3270f 465
d23dd9fb 466 const video = data.find(v => v.name === 'my super name for server 2')
89d241a7 467 const videoDetails = await servers[0].videos.get({ id: video.id })
5f04dd2f 468
5d00a3d7 469 const file = videoDetails.files.find(f => f.resolution.id === 360)
14d3270f
C
470 expect(file).not.to.be.undefined
471
472 const torrent = await webtorrentAdd(file.magnetUri)
473 expect(torrent.files).to.be.an('array')
474 expect(torrent.files.length).to.equal(1)
475 expect(torrent.files[0].path).to.exist.and.to.not.equal('')
476 })
0e1dc3e7
C
477 })
478
479 describe('Should update video views, likes and dislikes', function () {
9a27cdc2
C
480 let localVideosServer3 = []
481 let remoteVideosServer1 = []
482 let remoteVideosServer2 = []
483 let remoteVideosServer3 = []
0e1dc3e7
C
484
485 before(async function () {
d23dd9fb 486 {
89d241a7 487 const { data } = await servers[0].videos.list()
d23dd9fb
C
488 remoteVideosServer1 = data.filter(video => video.isLocal === false).map(video => video.uuid)
489 }
0e1dc3e7 490
d23dd9fb 491 {
89d241a7 492 const { data } = await servers[1].videos.list()
d23dd9fb
C
493 remoteVideosServer2 = data.filter(video => video.isLocal === false).map(video => video.uuid)
494 }
0e1dc3e7 495
d23dd9fb 496 {
89d241a7 497 const { data } = await servers[2].videos.list()
d23dd9fb
C
498 localVideosServer3 = data.filter(video => video.isLocal === true).map(video => video.uuid)
499 remoteVideosServer3 = data.filter(video => video.isLocal === false).map(video => video.uuid)
500 }
0e1dc3e7
C
501 })
502
503 it('Should view multiple videos on owned servers', async function () {
6b616860 504 this.timeout(30000)
0e1dc3e7 505
b2111066 506 await servers[2].views.simulateView({ id: localVideosServer3[0] })
511765c9 507 await wait(1000)
b5c0e955 508
b2111066
C
509 await servers[2].views.simulateView({ id: localVideosServer3[0] })
510 await servers[2].views.simulateView({ id: localVideosServer3[1] })
b5c0e955 511
511765c9 512 await wait(1000)
b5c0e955 513
b2111066
C
514 await servers[2].views.simulateView({ id: localVideosServer3[0] })
515 await servers[2].views.simulateView({ id: localVideosServer3[0] })
0e1dc3e7 516
3cd0734f 517 await waitJobs(servers)
0e1dc3e7 518
b2111066
C
519 for (const server of servers) {
520 await server.debug.sendCommand({ body: { command: 'process-video-views-buffer' } })
521 }
6b616860 522
c883db6d
C
523 await waitJobs(servers)
524
0e1dc3e7 525 for (const server of servers) {
89d241a7 526 const { data } = await server.videos.list()
0e1dc3e7 527
d23dd9fb
C
528 const video0 = data.find(v => v.uuid === localVideosServer3[0])
529 const video1 = data.find(v => v.uuid === localVideosServer3[1])
5f04dd2f 530
1f3e9fec
C
531 expect(video0.views).to.equal(3)
532 expect(video1.views).to.equal(1)
0e1dc3e7
C
533 }
534 })
535
536 it('Should view multiple videos on each servers', async function () {
24163420 537 this.timeout(45000)
0e1dc3e7
C
538
539 const tasks: Promise<any>[] = []
b2111066
C
540 tasks.push(servers[0].views.simulateView({ id: remoteVideosServer1[0] }))
541 tasks.push(servers[1].views.simulateView({ id: remoteVideosServer2[0] }))
542 tasks.push(servers[1].views.simulateView({ id: remoteVideosServer2[0] }))
543 tasks.push(servers[2].views.simulateView({ id: remoteVideosServer3[0] }))
544 tasks.push(servers[2].views.simulateView({ id: remoteVideosServer3[1] }))
545 tasks.push(servers[2].views.simulateView({ id: remoteVideosServer3[1] }))
546 tasks.push(servers[2].views.simulateView({ id: remoteVideosServer3[1] }))
547 tasks.push(servers[2].views.simulateView({ id: localVideosServer3[1] }))
548 tasks.push(servers[2].views.simulateView({ id: localVideosServer3[1] }))
549 tasks.push(servers[2].views.simulateView({ id: localVideosServer3[1] }))
0e1dc3e7
C
550
551 await Promise.all(tasks)
552
3cd0734f 553 await waitJobs(servers)
0e1dc3e7 554
b2111066
C
555 for (const server of servers) {
556 await server.debug.sendCommand({ body: { command: 'process-video-views-buffer' } })
557 }
6b616860 558
c883db6d
C
559 await waitJobs(servers)
560
0e1dc3e7
C
561 let baseVideos = null
562
563 for (const server of servers) {
89d241a7 564 const { data } = await server.videos.list()
0e1dc3e7
C
565
566 // Initialize base videos for future comparisons
567 if (baseVideos === null) {
d23dd9fb 568 baseVideos = data
35a097b8 569 continue
0e1dc3e7
C
570 }
571
572 for (const baseVideo of baseVideos) {
d23dd9fb 573 const sameVideo = data.find(video => video.name === baseVideo.name)
0e1dc3e7
C
574 expect(baseVideo.views).to.equal(sameVideo.views)
575 }
576 }
577 })
578
579 it('Should like and dislikes videos on different services', async function () {
185eabe1 580 this.timeout(50000)
0e1dc3e7 581
89d241a7 582 await servers[0].videos.rate({ id: remoteVideosServer1[0], rating: 'like' })
2ba92871 583 await wait(500)
89d241a7 584 await servers[0].videos.rate({ id: remoteVideosServer1[0], rating: 'dislike' })
2ba92871 585 await wait(500)
89d241a7
C
586 await servers[0].videos.rate({ id: remoteVideosServer1[0], rating: 'like' })
587 await servers[2].videos.rate({ id: localVideosServer3[1], rating: 'like' })
2ba92871 588 await wait(500)
89d241a7
C
589 await servers[2].videos.rate({ id: localVideosServer3[1], rating: 'dislike' })
590 await servers[2].videos.rate({ id: remoteVideosServer3[1], rating: 'dislike' })
2ba92871 591 await wait(500)
89d241a7 592 await servers[2].videos.rate({ id: remoteVideosServer3[0], rating: 'like' })
0e1dc3e7 593
3cd0734f 594 await waitJobs(servers)
021c4265 595 await wait(5000)
0d8ecb75 596 await waitJobs(servers)
0e1dc3e7
C
597
598 let baseVideos = null
599 for (const server of servers) {
89d241a7 600 const { data } = await server.videos.list()
0e1dc3e7
C
601
602 // Initialize base videos for future comparisons
603 if (baseVideos === null) {
d23dd9fb 604 baseVideos = data
35a097b8 605 continue
0e1dc3e7
C
606 }
607
35a097b8 608 for (const baseVideo of baseVideos) {
d23dd9fb 609 const sameVideo = data.find(video => video.name === baseVideo.name)
57e4e1c1
C
610 expect(baseVideo.likes).to.equal(sameVideo.likes, `Likes of ${sameVideo.uuid} do not correspond`)
611 expect(baseVideo.dislikes).to.equal(sameVideo.dislikes, `Dislikes of ${sameVideo.uuid} do not correspond`)
35a097b8 612 }
0e1dc3e7
C
613 }
614 })
615 })
616
617 describe('Should manipulate these videos', function () {
d78b51aa
C
618 let updatedAtMin: Date
619
620 it('Should update video 3', async function () {
b18a501a 621 this.timeout(30000)
0e1dc3e7
C
622
623 const attributes = {
624 name: 'my super video updated',
625 category: 10,
626 licence: 7,
9d3ef9fe 627 language: 'fr',
0e1dc3e7
C
628 nsfw: true,
629 description: 'my super description updated',
2422c46b 630 support: 'my super support text updated',
ac81d1a0
C
631 tags: [ 'tag_up_1', 'tag_up_2' ],
632 thumbnailfile: 'thumbnail.jpg',
7519127b 633 originallyPublishedAt: '2019-02-11T13:38:14.449Z',
ac81d1a0 634 previewfile: 'preview.jpg'
0e1dc3e7
C
635 }
636
d78b51aa 637 updatedAtMin = new Date()
89d241a7 638 await servers[2].videos.update({ id: toRemove[0].id, attributes })
0e1dc3e7 639
3cd0734f 640 await waitJobs(servers)
0e1dc3e7
C
641 })
642
9a27cdc2 643 it('Should have the video 3 updated on each server', async function () {
b18a501a 644 this.timeout(30000)
0e1dc3e7
C
645
646 for (const server of servers) {
89d241a7 647 const { data } = await server.videos.list()
0e1dc3e7 648
d23dd9fb 649 const videoUpdated = data.find(video => video.name === 'my super video updated')
0e1dc3e7 650 expect(!!videoUpdated).to.be.true
0e1dc3e7 651
d78b51aa
C
652 expect(new Date(videoUpdated.updatedAt)).to.be.greaterThan(updatedAtMin)
653
7243f84d 654 const isLocal = server.url === 'http://localhost:' + servers[2].port
b1f5b93e
C
655 const checkAttributes = {
656 name: 'my super video updated',
657 category: 10,
658 licence: 7,
9d3ef9fe 659 language: 'fr',
b1f5b93e
C
660 nsfw: true,
661 description: 'my super description updated',
2422c46b 662 support: 'my super support text updated',
7519127b 663 originallyPublishedAt: '2019-02-11T13:38:14.449Z',
b64c950a
C
664 account: {
665 name: 'root',
7243f84d 666 host: 'localhost:' + servers[2].port
b64c950a 667 },
b1f5b93e
C
668 isLocal,
669 duration: 5,
47564bbe 670 commentsEnabled: true,
7f2cfe3a 671 downloadEnabled: true,
b1f5b93e
C
672 tags: [ 'tag_up_1', 'tag_up_2' ],
673 privacy: VideoPrivacy.PUBLIC,
674 channel: {
f6eebcb3
C
675 displayName: 'Main root channel',
676 name: 'root_channel',
b1f5b93e
C
677 description: '',
678 isLocal
679 },
680 fixture: 'video_short3.webm',
681 files: [
682 {
683 resolution: 720,
684 size: 292677
685 }
ac81d1a0
C
686 ],
687 thumbnailfile: 'thumbnail',
688 previewfile: 'preview'
b1f5b93e 689 }
d23dd9fb 690 await completeVideoCheck(server, videoUpdated, checkAttributes)
0e1dc3e7
C
691 }
692 })
693
5cf027bd 694 it('Should only update thumbnail and update updatedAt attribute', async function () {
b18a501a 695 this.timeout(30000)
5cf027bd
C
696
697 const attributes = {
698 thumbnailfile: 'thumbnail.jpg'
699 }
700
701 updatedAtMin = new Date()
702 await servers[2].videos.update({ id: toRemove[0].id, attributes })
703
704 await waitJobs(servers)
705
706 for (const server of servers) {
707 const { data } = await server.videos.list()
708
709 const videoUpdated = data.find(video => video.name === 'my super video updated')
710 expect(new Date(videoUpdated.updatedAt)).to.be.greaterThan(updatedAtMin)
711 }
712 })
713
83903cb6
C
714 it('Should remove the videos 3 and 3-2 by asking server 3 and correctly delete files', async function () {
715 this.timeout(30000)
0e1dc3e7 716
83903cb6
C
717 for (const id of [ toRemove[0].id, toRemove[1].id ]) {
718 await saveVideoInServers(servers, id)
0e1dc3e7 719
83903cb6 720 await servers[2].videos.remove({ id })
0e1dc3e7 721
83903cb6
C
722 await waitJobs(servers)
723
724 for (const server of servers) {
725 await checkVideoFilesWereRemoved({ server, video: server.store.videoDetails })
726 }
f05a1c30
C
727 }
728 })
729
9a27cdc2 730 it('Should have videos 1 and 3 on each server', async function () {
0e1dc3e7 731 for (const server of servers) {
89d241a7 732 const { data } = await server.videos.list()
d23dd9fb
C
733
734 expect(data).to.be.an('array')
735 expect(data.length).to.equal(2)
736 expect(data[0].name).not.to.equal(data[1].name)
737 expect(data[0].name).not.to.equal(toRemove[0].name)
738 expect(data[1].name).not.to.equal(toRemove[0].name)
739 expect(data[0].name).not.to.equal(toRemove[1].name)
740 expect(data[1].name).not.to.equal(toRemove[1].name)
741
742 videoUUID = data.find(video => video.name === 'my super name for server 1').uuid
0e1dc3e7
C
743 }
744 })
745
9a27cdc2 746 it('Should get the same video by UUID on each server', async function () {
0e1dc3e7
C
747 let baseVideo = null
748 for (const server of servers) {
89d241a7 749 const video = await server.videos.get({ id: videoUUID })
0e1dc3e7
C
750
751 if (baseVideo === null) {
752 baseVideo = video
35a097b8 753 continue
0e1dc3e7
C
754 }
755
756 expect(baseVideo.name).to.equal(video.name)
757 expect(baseVideo.uuid).to.equal(video.uuid)
5d00a3d7
C
758 expect(baseVideo.category.id).to.equal(video.category.id)
759 expect(baseVideo.language.id).to.equal(video.language.id)
760 expect(baseVideo.licence.id).to.equal(video.licence.id)
0e1dc3e7 761 expect(baseVideo.nsfw).to.equal(video.nsfw)
b64c950a
C
762 expect(baseVideo.account.name).to.equal(video.account.name)
763 expect(baseVideo.account.displayName).to.equal(video.account.displayName)
764 expect(baseVideo.account.url).to.equal(video.account.url)
765 expect(baseVideo.account.host).to.equal(video.account.host)
0e1dc3e7
C
766 expect(baseVideo.tags).to.deep.equal(video.tags)
767 }
768 })
769
9a27cdc2 770 it('Should get the preview from each server', async function () {
0e1dc3e7 771 for (const server of servers) {
89d241a7 772 const video = await server.videos.get({ id: videoUUID })
0e1dc3e7 773
7b0956ec 774 await testImage(server.url, 'video_short1-preview.webm', video.previewPath)
0e1dc3e7
C
775 }
776 })
777 })
778
d50acfab 779 describe('Should comment these videos', function () {
73c08093
C
780 let childOfFirstChild: VideoCommentThreadTree
781
d50acfab
C
782 it('Should add comment (threads and replies)', async function () {
783 this.timeout(25000)
784
785 {
786 const text = 'my super first comment'
89d241a7 787 await servers[0].comments.createThread({ videoId: videoUUID, text })
d50acfab
C
788 }
789
790 {
791 const text = 'my super second comment'
89d241a7 792 await servers[2].comments.createThread({ videoId: videoUUID, text })
d50acfab
C
793 }
794
3cd0734f 795 await waitJobs(servers)
d50acfab
C
796
797 {
89d241a7 798 const threadId = await servers[1].comments.findCommentId({ videoId: videoUUID, text: 'my super first comment' })
d50acfab
C
799
800 const text = 'my super answer to thread 1'
89d241a7 801 await servers[1].comments.addReply({ videoId: videoUUID, toCommentId: threadId, text })
d50acfab
C
802 }
803
3cd0734f 804 await waitJobs(servers)
d50acfab
C
805
806 {
89d241a7 807 const threadId = await servers[2].comments.findCommentId({ videoId: videoUUID, text: 'my super first comment' })
d50acfab 808
89d241a7 809 const body = await servers[2].comments.getThread({ videoId: videoUUID, threadId })
12edc149 810 const childCommentId = body.children[0].comment.id
d50acfab
C
811
812 const text3 = 'my second answer to thread 1'
89d241a7 813 await servers[2].comments.addReply({ videoId: videoUUID, toCommentId: threadId, text: text3 })
d50acfab
C
814
815 const text2 = 'my super answer to answer of thread 1'
89d241a7 816 await servers[2].comments.addReply({ videoId: videoUUID, toCommentId: childCommentId, text: text2 })
d50acfab
C
817 }
818
3cd0734f 819 await waitJobs(servers)
d50acfab
C
820 })
821
822 it('Should have these threads', async function () {
823 for (const server of servers) {
89d241a7 824 const body = await server.comments.listThreads({ videoId: videoUUID })
d50acfab 825
12edc149
C
826 expect(body.total).to.equal(2)
827 expect(body.data).to.be.an('array')
828 expect(body.data).to.have.lengthOf(2)
d50acfab
C
829
830 {
12edc149 831 const comment = body.data.find(c => c.text === 'my super first comment')
d50acfab
C
832 expect(comment).to.not.be.undefined
833 expect(comment.inReplyToCommentId).to.be.null
834 expect(comment.account.name).to.equal('root')
7243f84d 835 expect(comment.account.host).to.equal('localhost:' + servers[0].port)
d50acfab
C
836 expect(comment.totalReplies).to.equal(3)
837 expect(dateIsValid(comment.createdAt as string)).to.be.true
838 expect(dateIsValid(comment.updatedAt as string)).to.be.true
839 }
840
841 {
12edc149 842 const comment = body.data.find(c => c.text === 'my super second comment')
d50acfab
C
843 expect(comment).to.not.be.undefined
844 expect(comment.inReplyToCommentId).to.be.null
845 expect(comment.account.name).to.equal('root')
7243f84d 846 expect(comment.account.host).to.equal('localhost:' + servers[2].port)
d50acfab
C
847 expect(comment.totalReplies).to.equal(0)
848 expect(dateIsValid(comment.createdAt as string)).to.be.true
849 expect(dateIsValid(comment.updatedAt as string)).to.be.true
850 }
851 }
852 })
853
854 it('Should have these comments', async function () {
855 for (const server of servers) {
89d241a7 856 const body = await server.comments.listThreads({ videoId: videoUUID })
12edc149 857 const threadId = body.data.find(c => c.text === 'my super first comment').id
d50acfab 858
89d241a7 859 const tree = await server.comments.getThread({ videoId: videoUUID, threadId })
d50acfab 860
d50acfab
C
861 expect(tree.comment.text).equal('my super first comment')
862 expect(tree.comment.account.name).equal('root')
7243f84d 863 expect(tree.comment.account.host).equal('localhost:' + servers[0].port)
d50acfab
C
864 expect(tree.children).to.have.lengthOf(2)
865
866 const firstChild = tree.children[0]
867 expect(firstChild.comment.text).to.equal('my super answer to thread 1')
868 expect(firstChild.comment.account.name).equal('root')
7243f84d 869 expect(firstChild.comment.account.host).equal('localhost:' + servers[1].port)
d50acfab
C
870 expect(firstChild.children).to.have.lengthOf(1)
871
73c08093 872 childOfFirstChild = firstChild.children[0]
d50acfab
C
873 expect(childOfFirstChild.comment.text).to.equal('my super answer to answer of thread 1')
874 expect(childOfFirstChild.comment.account.name).equal('root')
7243f84d 875 expect(childOfFirstChild.comment.account.host).equal('localhost:' + servers[2].port)
d50acfab
C
876 expect(childOfFirstChild.children).to.have.lengthOf(0)
877
878 const secondChild = tree.children[1]
879 expect(secondChild.comment.text).to.equal('my second answer to thread 1')
880 expect(secondChild.comment.account.name).equal('root')
7243f84d 881 expect(secondChild.comment.account.host).equal('localhost:' + servers[2].port)
d50acfab
C
882 expect(secondChild.children).to.have.lengthOf(0)
883 }
884 })
47564bbe 885
73c08093 886 it('Should delete a reply', async function () {
b18a501a 887 this.timeout(30000)
73c08093 888
89d241a7 889 await servers[2].comments.delete({ videoId: videoUUID, commentId: childOfFirstChild.comment.id })
73c08093 890
3cd0734f 891 await waitJobs(servers)
73c08093
C
892 })
893
69222afa 894 it('Should have this comment marked as deleted', async function () {
73c08093 895 for (const server of servers) {
89d241a7 896 const { data } = await server.comments.listThreads({ videoId: videoUUID })
12edc149 897 const threadId = data.find(c => c.text === 'my super first comment').id
73c08093 898
89d241a7 899 const tree = await server.comments.getThread({ videoId: videoUUID, threadId })
73c08093
C
900 expect(tree.comment.text).equal('my super first comment')
901
902 const firstChild = tree.children[0]
903 expect(firstChild.comment.text).to.equal('my super answer to thread 1')
69222afa
JM
904 expect(firstChild.children).to.have.lengthOf(1)
905
906 const deletedComment = firstChild.children[0].comment
907 expect(deletedComment.isDeleted).to.be.true
908 expect(deletedComment.deletedAt).to.not.be.null
909 expect(deletedComment.account).to.be.null
910 expect(deletedComment.text).to.equal('')
73c08093
C
911
912 const secondChild = tree.children[1]
913 expect(secondChild.comment.text).to.equal('my second answer to thread 1')
914 }
915 })
916
4cb6d457 917 it('Should delete the thread comments', async function () {
b18a501a 918 this.timeout(30000)
4cb6d457 919
89d241a7 920 const { data } = await servers[0].comments.listThreads({ videoId: videoUUID })
12edc149 921 const commentId = data.find(c => c.text === 'my super first comment').id
89d241a7 922 await servers[0].comments.delete({ videoId: videoUUID, commentId })
4cb6d457 923
3cd0734f 924 await waitJobs(servers)
4cb6d457
C
925 })
926
69222afa 927 it('Should have the threads marked as deleted on other servers too', async function () {
4cb6d457 928 for (const server of servers) {
89d241a7 929 const body = await server.comments.listThreads({ videoId: videoUUID })
4cb6d457 930
12edc149
C
931 expect(body.total).to.equal(2)
932 expect(body.data).to.be.an('array')
933 expect(body.data).to.have.lengthOf(2)
4cb6d457
C
934
935 {
12edc149 936 const comment = body.data[0]
4cb6d457
C
937 expect(comment).to.not.be.undefined
938 expect(comment.inReplyToCommentId).to.be.null
939 expect(comment.account.name).to.equal('root')
7243f84d 940 expect(comment.account.host).to.equal('localhost:' + servers[2].port)
4cb6d457
C
941 expect(comment.totalReplies).to.equal(0)
942 expect(dateIsValid(comment.createdAt as string)).to.be.true
943 expect(dateIsValid(comment.updatedAt as string)).to.be.true
944 }
69222afa
JM
945
946 {
12edc149 947 const deletedComment = body.data[1]
69222afa
JM
948 expect(deletedComment).to.not.be.undefined
949 expect(deletedComment.isDeleted).to.be.true
950 expect(deletedComment.deletedAt).to.not.be.null
951 expect(deletedComment.text).to.equal('')
952 expect(deletedComment.inReplyToCommentId).to.be.null
953 expect(deletedComment.account).to.be.null
99cb53fd 954 expect(deletedComment.totalReplies).to.equal(2)
69222afa
JM
955 expect(dateIsValid(deletedComment.createdAt as string)).to.be.true
956 expect(dateIsValid(deletedComment.updatedAt as string)).to.be.true
957 expect(dateIsValid(deletedComment.deletedAt as string)).to.be.true
958 }
4cb6d457
C
959 }
960 })
961
511765c9 962 it('Should delete a remote thread by the origin server', async function () {
b5206dfc
JM
963 this.timeout(5000)
964
89d241a7 965 const { data } = await servers[0].comments.listThreads({ videoId: videoUUID })
12edc149 966 const commentId = data.find(c => c.text === 'my super second comment').id
89d241a7 967 await servers[0].comments.delete({ videoId: videoUUID, commentId })
511765c9
C
968
969 await waitJobs(servers)
970 })
971
69222afa 972 it('Should have the threads marked as deleted on other servers too', async function () {
511765c9 973 for (const server of servers) {
89d241a7 974 const body = await server.comments.listThreads({ videoId: videoUUID })
511765c9 975
12edc149
C
976 expect(body.total).to.equal(2)
977 expect(body.data).to.have.lengthOf(2)
69222afa
JM
978
979 {
12edc149 980 const comment = body.data[0]
69222afa
JM
981 expect(comment.text).to.equal('')
982 expect(comment.isDeleted).to.be.true
983 expect(comment.createdAt).to.not.be.null
984 expect(comment.deletedAt).to.not.be.null
985 expect(comment.account).to.be.null
986 expect(comment.totalReplies).to.equal(0)
987 }
988
989 {
12edc149 990 const comment = body.data[1]
69222afa
JM
991 expect(comment.text).to.equal('')
992 expect(comment.isDeleted).to.be.true
993 expect(comment.createdAt).to.not.be.null
994 expect(comment.deletedAt).to.not.be.null
995 expect(comment.account).to.be.null
99cb53fd 996 expect(comment.totalReplies).to.equal(2)
69222afa 997 }
511765c9
C
998 }
999 })
1000
53a94c7c 1001 it('Should disable comments and download', async function () {
47564bbe
C
1002 this.timeout(20000)
1003
1004 const attributes = {
53a94c7c
C
1005 commentsEnabled: false,
1006 downloadEnabled: false
47564bbe
C
1007 }
1008
89d241a7 1009 await servers[0].videos.update({ id: videoUUID, attributes })
47564bbe 1010
3cd0734f 1011 await waitJobs(servers)
47564bbe
C
1012
1013 for (const server of servers) {
89d241a7 1014 const video = await server.videos.get({ id: videoUUID })
d23dd9fb
C
1015 expect(video.commentsEnabled).to.be.false
1016 expect(video.downloadEnabled).to.be.false
47564bbe
C
1017
1018 const text = 'my super forbidden comment'
89d241a7 1019 await server.comments.createThread({ videoId: videoUUID, text, expectedStatus: HttpStatusCode.CONFLICT_409 })
47564bbe
C
1020 }
1021 })
d50acfab
C
1022 })
1023
f595d394
C
1024 describe('With minimum parameters', function () {
1025 it('Should upload and propagate the video', async function () {
2186386c 1026 this.timeout(60000)
f595d394
C
1027
1028 const path = '/api/v1/videos/upload'
1029
1030 const req = request(servers[1].url)
1031 .post(path)
1032 .set('Accept', 'application/json')
1033 .set('Authorization', 'Bearer ' + servers[1].accessToken)
1034 .field('name', 'minimum parameters')
1035 .field('privacy', '1')
f595d394
C
1036 .field('channelId', '1')
1037
3d470a53 1038 await req.attach('videofile', buildAbsoluteFixturePath('video_short.webm'))
f2eb23cd 1039 .expect(HttpStatusCode.OK_200)
f595d394 1040
3cd0734f 1041 await waitJobs(servers)
f595d394
C
1042
1043 for (const server of servers) {
89d241a7 1044 const { data } = await server.videos.list()
d23dd9fb 1045 const video = data.find(v => v.name === 'minimum parameters')
f595d394 1046
7243f84d 1047 const isLocal = server.url === 'http://localhost:' + servers[1].port
b1f5b93e
C
1048 const checkAttributes = {
1049 name: 'minimum parameters',
1050 category: null,
1051 licence: null,
1052 language: null,
1053 nsfw: false,
1054 description: null,
2422c46b 1055 support: null,
b64c950a
C
1056 account: {
1057 name: 'root',
7243f84d 1058 host: 'localhost:' + servers[1].port
b64c950a 1059 },
b1f5b93e
C
1060 isLocal,
1061 duration: 5,
210709a9 1062 commentsEnabled: true,
7519127b 1063 downloadEnabled: true,
a1587156 1064 tags: [],
b1f5b93e
C
1065 privacy: VideoPrivacy.PUBLIC,
1066 channel: {
f6eebcb3
C
1067 displayName: 'Main root channel',
1068 name: 'root_channel',
b1f5b93e
C
1069 description: '',
1070 isLocal
1071 },
1072 fixture: 'video_short.webm',
1073 files: [
1074 {
1075 resolution: 720,
d78b51aa 1076 size: 61000
b1f5b93e
C
1077 },
1078 {
1079 resolution: 480,
d78b51aa 1080 size: 40000
b1f5b93e
C
1081 },
1082 {
1083 resolution: 360,
d78b51aa 1084 size: 32000
b1f5b93e
C
1085 },
1086 {
1087 resolution: 240,
7519c4a2 1088 size: 23000
b1f5b93e
C
1089 }
1090 ]
1091 }
d23dd9fb 1092 await completeVideoCheck(server, video, checkAttributes)
f595d394
C
1093 }
1094 })
1095 })
1096
89231874
C
1097 describe('TMP directory', function () {
1098 it('Should have an empty tmp directory', async function () {
1099 for (const server of servers) {
1100 await checkTmpIsEmpty(server)
1101 }
1102 })
1103 })
1104
7c3b7976
C
1105 after(async function () {
1106 await cleanupTests(servers)
0e1dc3e7
C
1107 })
1108})