]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/tests/api/videos/multiple-servers.ts
Fix getting avatars in videos list
[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
d50acfab 3import 'mocha'
2b02c520 4import * as chai from 'chai'
242f5225 5import { and } from 'sequelize/dist'
41fb13c3 6import request from 'supertest'
0e1dc3e7 7import {
89231874 8 checkTmpIsEmpty,
7243f84d 9 checkVideoFilesWereRemoved,
c55e3d72
C
10 completeVideoCheck,
11 dateIsValid,
12 saveVideoInServers,
13 testImage
14} from '@server/tests/shared'
15import { buildAbsoluteFixturePath, wait } from '@shared/core-utils'
16import { HttpStatusCode, VideoCommentThreadTree, VideoPrivacy } from '@shared/models'
17import {
7243f84d 18 cleanupTests,
4c7e60bc 19 createMultipleServers,
b64c950a 20 doubleFollow,
242f5225 21 makeGetRequest,
254d3579 22 PeerTubeServer,
b64c950a 23 setAccessTokensToServers,
d0800f76 24 setDefaultAccountAvatar,
25 setDefaultChannelAvatar,
12edc149 26 waitJobs,
b64c950a 27 webtorrentAdd
bf54587a 28} from '@shared/server-commands'
0e1dc3e7
C
29
30const expect = chai.expect
31
9a27cdc2 32describe('Test multiple servers', function () {
254d3579 33 let servers: PeerTubeServer[] = []
0e1dc3e7
C
34 const toRemove = []
35 let videoUUID = ''
5f04dd2f 36 let videoChannelId: number
0e1dc3e7
C
37
38 before(async function () {
39 this.timeout(120000)
40
254d3579 41 servers = await createMultipleServers(3)
0e1dc3e7
C
42
43 // Get the access tokens
44 await setAccessTokensToServers(servers)
45
48dce1c9
C
46 {
47 const videoChannel = {
8a19bee1 48 name: 'super_channel_name',
08c1efbe 49 displayName: 'my channel',
48dce1c9
C
50 description: 'super channel'
51 }
89d241a7 52 await servers[0].channels.create({ attributes: videoChannel })
d0800f76 53 await setDefaultChannelAvatar(servers[0], videoChannel.name)
54 await setDefaultAccountAvatar(servers)
55
89d241a7 56 const { data } = await servers[0].channels.list({ start: 0, count: 1 })
a5461888 57 videoChannelId = data[0].id
5f04dd2f 58 }
5f04dd2f 59
9a27cdc2
C
60 // Server 1 and server 2 follow each other
61 await doubleFollow(servers[0], servers[1])
62 // Server 1 and server 3 follow each other
63 await doubleFollow(servers[0], servers[2])
64 // Server 2 and server 3 follow each other
65 await doubleFollow(servers[1], servers[2])
0e1dc3e7
C
66 })
67
9a27cdc2 68 it('Should not have videos for all servers', async function () {
0e1dc3e7 69 for (const server of servers) {
89d241a7 70 const { data } = await server.videos.list()
d23dd9fb
C
71 expect(data).to.be.an('array')
72 expect(data.length).to.equal(0)
0e1dc3e7
C
73 }
74 })
75
9a27cdc2
C
76 describe('Should upload the video and propagate on each server', function () {
77 it('Should upload the video on server 1 and propagate on each server', async function () {
652b3056 78 this.timeout(25000)
0e1dc3e7 79
d23dd9fb 80 const attributes = {
9a27cdc2 81 name: 'my super name for server 1',
0e1dc3e7
C
82 category: 5,
83 licence: 4,
9d3ef9fe 84 language: 'ja',
0e1dc3e7 85 nsfw: true,
9a27cdc2 86 description: 'my super description for server 1',
2422c46b 87 support: 'my super support text for server 1',
7519127b 88 originallyPublishedAt: '2019-02-10T13:38:14.449Z',
0e1dc3e7 89 tags: [ 'tag1p1', 'tag2p1' ],
5f04dd2f 90 channelId: videoChannelId,
0e1dc3e7
C
91 fixture: 'video_short1.webm'
92 }
89d241a7 93 await servers[0].videos.upload({ attributes })
0e1dc3e7 94
3cd0734f 95 await waitJobs(servers)
0e1dc3e7 96
9a27cdc2 97 // All servers should have this video
53a61317 98 let publishedAt: string = null
0e1dc3e7 99 for (const server of servers) {
48f07b4a 100 const isLocal = server.port === servers[0].port
b1f5b93e
C
101 const checkAttributes = {
102 name: 'my super name for server 1',
103 category: 5,
104 licence: 4,
9d3ef9fe 105 language: 'ja',
b1f5b93e
C
106 nsfw: true,
107 description: 'my super description for server 1',
2422c46b 108 support: 'my super support text for server 1',
7519127b 109 originallyPublishedAt: '2019-02-10T13:38:14.449Z',
b64c950a
C
110 account: {
111 name: 'root',
7243f84d 112 host: 'localhost:' + servers[0].port
b64c950a 113 },
b1f5b93e 114 isLocal,
53a61317 115 publishedAt,
b1f5b93e
C
116 duration: 10,
117 tags: [ 'tag1p1', 'tag2p1' ],
118 privacy: VideoPrivacy.PUBLIC,
47564bbe 119 commentsEnabled: true,
7f2cfe3a 120 downloadEnabled: true,
b1f5b93e 121 channel: {
f6eebcb3
C
122 displayName: 'my channel',
123 name: 'super_channel_name',
b1f5b93e
C
124 description: 'super channel',
125 isLocal
126 },
8b0d42ee 127 fixture: 'video_short1.webm',
b1f5b93e
C
128 files: [
129 {
130 resolution: 720,
131 size: 572456
132 }
133 ]
134 }
0e1dc3e7 135
89d241a7 136 const { data } = await server.videos.list()
d23dd9fb
C
137 expect(data).to.be.an('array')
138 expect(data.length).to.equal(1)
139 const video = data[0]
0e1dc3e7 140
d23dd9fb
C
141 await completeVideoCheck(server, video, checkAttributes)
142 publishedAt = video.publishedAt as string
242f5225
C
143
144 expect(video.channel.avatars).to.have.lengthOf(2)
145 expect(video.account.avatars).to.have.lengthOf(2)
146
147 for (const image of [ ...video.channel.avatars, ...video.account.avatars ]) {
148 expect(image.createdAt).to.exist
149 expect(image.updatedAt).to.exist
150 expect(image.width).to.be.above(20).and.below(1000)
151 expect(image.path).to.exist
152
153 await makeGetRequest({
154 url: server.url,
155 path: image.path,
156 expectedStatus: HttpStatusCode.OK_200
157 })
158 }
0e1dc3e7
C
159 }
160 })
161
9a27cdc2 162 it('Should upload the video on server 2 and propagate on each server', async function () {
f1273314 163 this.timeout(100000)
0e1dc3e7 164
5f04dd2f
C
165 const user = {
166 username: 'user1',
167 password: 'super_password'
168 }
89d241a7
C
169 await servers[1].users.create({ username: user.username, password: user.password })
170 const userAccessToken = await servers[1].login.getAccessToken(user)
5f04dd2f 171
d23dd9fb 172 const attributes = {
9a27cdc2 173 name: 'my super name for server 2',
0e1dc3e7
C
174 category: 4,
175 licence: 3,
9d3ef9fe 176 language: 'de',
0e1dc3e7 177 nsfw: true,
9a27cdc2 178 description: 'my super description for server 2',
2422c46b 179 support: 'my super support text for server 2',
0e1dc3e7 180 tags: [ 'tag1p2', 'tag2p2', 'tag3p2' ],
ac81d1a0
C
181 fixture: 'video_short2.webm',
182 thumbnailfile: 'thumbnail.jpg',
183 previewfile: 'preview.jpg'
0e1dc3e7 184 }
89d241a7 185 await servers[1].videos.upload({ token: userAccessToken, attributes, mode: 'resumable' })
0e1dc3e7 186
572f8d3d 187 // Transcoding
3cd0734f 188 await waitJobs(servers)
0e1dc3e7 189
9a27cdc2 190 // All servers should have this video
0e1dc3e7 191 for (const server of servers) {
7243f84d 192 const isLocal = server.url === 'http://localhost:' + servers[1].port
b1f5b93e
C
193 const checkAttributes = {
194 name: 'my super name for server 2',
195 category: 4,
196 licence: 3,
9d3ef9fe 197 language: 'de',
b1f5b93e
C
198 nsfw: true,
199 description: 'my super description for server 2',
2422c46b 200 support: 'my super support text for server 2',
b64c950a
C
201 account: {
202 name: 'user1',
7243f84d 203 host: 'localhost:' + servers[1].port
b64c950a 204 },
b1f5b93e 205 isLocal,
47564bbe 206 commentsEnabled: true,
7f2cfe3a 207 downloadEnabled: true,
b1f5b93e
C
208 duration: 5,
209 tags: [ 'tag1p2', 'tag2p2', 'tag3p2' ],
210 privacy: VideoPrivacy.PUBLIC,
211 channel: {
f6eebcb3
C
212 displayName: 'Main user1 channel',
213 name: 'user1_channel',
b1f5b93e
C
214 description: 'super channel',
215 isLocal
216 },
217 fixture: 'video_short2.webm',
218 files: [
219 {
220 resolution: 240,
33ff70ba 221 size: 270000
b1f5b93e
C
222 },
223 {
224 resolution: 360,
33ff70ba 225 size: 359000
b1f5b93e
C
226 },
227 {
228 resolution: 480,
33ff70ba 229 size: 465000
b1f5b93e
C
230 },
231 {
232 resolution: 720,
d0800f76 233 size: 750000
b1f5b93e 234 }
ac81d1a0
C
235 ],
236 thumbnailfile: 'thumbnail',
237 previewfile: 'preview'
b1f5b93e 238 }
0e1dc3e7 239
89d241a7 240 const { data } = await server.videos.list()
d23dd9fb
C
241 expect(data).to.be.an('array')
242 expect(data.length).to.equal(2)
243 const video = data[1]
0e1dc3e7 244
d23dd9fb 245 await completeVideoCheck(server, video, checkAttributes)
0e1dc3e7
C
246 }
247 })
248
9a27cdc2 249 it('Should upload two videos on server 3 and propagate on each server', async function () {
0e1dc3e7
C
250 this.timeout(45000)
251
d23dd9fb
C
252 {
253 const attributes = {
254 name: 'my super name for server 3',
255 category: 6,
256 licence: 5,
257 language: 'de',
258 nsfw: true,
259 description: 'my super description for server 3',
260 support: 'my super support text for server 3',
261 tags: [ 'tag1p3' ],
262 fixture: 'video_short3.webm'
263 }
89d241a7 264 await servers[2].videos.upload({ attributes })
0e1dc3e7 265 }
d23dd9fb
C
266
267 {
268 const attributes = {
269 name: 'my super name for server 3-2',
270 category: 7,
271 licence: 6,
272 language: 'ko',
273 nsfw: false,
274 description: 'my super description for server 3-2',
275 support: 'my super support text for server 3-2',
276 tags: [ 'tag2p3', 'tag3p3', 'tag4p3' ],
277 fixture: 'video_short.webm'
278 }
89d241a7 279 await servers[2].videos.upload({ attributes })
0e1dc3e7 280 }
0e1dc3e7 281
3cd0734f 282 await waitJobs(servers)
0e1dc3e7 283
9a27cdc2 284 // All servers should have this video
0e1dc3e7 285 for (const server of servers) {
7243f84d 286 const isLocal = server.url === 'http://localhost:' + servers[2].port
89d241a7 287 const { data } = await server.videos.list()
0e1dc3e7 288
d23dd9fb
C
289 expect(data).to.be.an('array')
290 expect(data.length).to.equal(4)
0e1dc3e7
C
291
292 // We not sure about the order of the two last uploads
293 let video1 = null
294 let video2 = null
d23dd9fb
C
295 if (data[2].name === 'my super name for server 3') {
296 video1 = data[2]
297 video2 = data[3]
0e1dc3e7 298 } else {
d23dd9fb
C
299 video1 = data[3]
300 video2 = data[2]
0e1dc3e7
C
301 }
302
b1f5b93e
C
303 const checkAttributesVideo1 = {
304 name: 'my super name for server 3',
305 category: 6,
306 licence: 5,
9d3ef9fe 307 language: 'de',
b1f5b93e
C
308 nsfw: true,
309 description: 'my super description for server 3',
2422c46b 310 support: 'my super support text for server 3',
b64c950a
C
311 account: {
312 name: 'root',
7243f84d 313 host: 'localhost:' + servers[2].port
b64c950a 314 },
b1f5b93e
C
315 isLocal,
316 duration: 5,
47564bbe 317 commentsEnabled: true,
7f2cfe3a 318 downloadEnabled: true,
b1f5b93e
C
319 tags: [ 'tag1p3' ],
320 privacy: VideoPrivacy.PUBLIC,
321 channel: {
f6eebcb3
C
322 displayName: 'Main root channel',
323 name: 'root_channel',
b1f5b93e
C
324 description: '',
325 isLocal
326 },
327 fixture: 'video_short3.webm',
328 files: [
329 {
330 resolution: 720,
331 size: 292677
332 }
333 ]
0e1dc3e7 334 }
d23dd9fb 335 await completeVideoCheck(server, video1, checkAttributesVideo1)
b1f5b93e
C
336
337 const checkAttributesVideo2 = {
338 name: 'my super name for server 3-2',
339 category: 7,
340 licence: 6,
9d3ef9fe 341 language: 'ko',
b1f5b93e
C
342 nsfw: false,
343 description: 'my super description for server 3-2',
2422c46b 344 support: 'my super support text for server 3-2',
b64c950a
C
345 account: {
346 name: 'root',
7243f84d 347 host: 'localhost:' + servers[2].port
b64c950a 348 },
47564bbe 349 commentsEnabled: true,
7f2cfe3a 350 downloadEnabled: true,
b1f5b93e
C
351 isLocal,
352 duration: 5,
353 tags: [ 'tag2p3', 'tag3p3', 'tag4p3' ],
354 privacy: VideoPrivacy.PUBLIC,
355 channel: {
f6eebcb3
C
356 displayName: 'Main root channel',
357 name: 'root_channel',
b1f5b93e
C
358 description: '',
359 isLocal
360 },
8b0d42ee 361 fixture: 'video_short.webm',
b1f5b93e
C
362 files: [
363 {
364 resolution: 720,
365 size: 218910
366 }
367 ]
0e1dc3e7 368 }
d23dd9fb 369 await completeVideoCheck(server, video2, checkAttributesVideo2)
0e1dc3e7
C
370 }
371 })
372 })
373
066e94c5
C
374 describe('It should list local videos', function () {
375 it('Should list only local videos on server 1', async function () {
2760b454 376 const { data, total } = await servers[0].videos.list({ isLocal: true })
066e94c5 377
d23dd9fb
C
378 expect(total).to.equal(1)
379 expect(data).to.be.an('array')
380 expect(data.length).to.equal(1)
381 expect(data[0].name).to.equal('my super name for server 1')
066e94c5
C
382 })
383
384 it('Should list only local videos on server 2', async function () {
2760b454 385 const { data, total } = await servers[1].videos.list({ isLocal: true })
066e94c5 386
d23dd9fb
C
387 expect(total).to.equal(1)
388 expect(data).to.be.an('array')
389 expect(data.length).to.equal(1)
390 expect(data[0].name).to.equal('my super name for server 2')
066e94c5
C
391 })
392
393 it('Should list only local videos on server 3', async function () {
2760b454 394 const { data, total } = await servers[2].videos.list({ isLocal: true })
066e94c5 395
d23dd9fb
C
396 expect(total).to.equal(2)
397 expect(data).to.be.an('array')
398 expect(data.length).to.equal(2)
399 expect(data[0].name).to.equal('my super name for server 3')
400 expect(data[1].name).to.equal('my super name for server 3-2')
066e94c5
C
401 })
402 })
403
0e1dc3e7 404 describe('Should seed the uploaded video', function () {
9a27cdc2 405 it('Should add the file 1 by asking server 3', async function () {
b18a501a 406 this.timeout(30000)
0e1dc3e7 407
89d241a7 408 const { data } = await servers[2].videos.list()
0e1dc3e7 409
d23dd9fb
C
410 const video = data[0]
411 toRemove.push(data[2])
412 toRemove.push(data[3])
5f04dd2f 413
89d241a7 414 const videoDetails = await servers[2].videos.get({ id: video.id })
b1f5b93e 415 const torrent = await webtorrentAdd(videoDetails.files[0].magnetUri, true)
0e1dc3e7
C
416 expect(torrent.files).to.be.an('array')
417 expect(torrent.files.length).to.equal(1)
418 expect(torrent.files[0].path).to.exist.and.to.not.equal('')
419 })
420
9a27cdc2 421 it('Should add the file 2 by asking server 1', async function () {
b18a501a 422 this.timeout(30000)
0e1dc3e7 423
89d241a7 424 const { data } = await servers[0].videos.list()
0e1dc3e7 425
d23dd9fb 426 const video = data[1]
89d241a7 427 const videoDetails = await servers[0].videos.get({ id: video.id })
0e1dc3e7 428
b1f5b93e 429 const torrent = await webtorrentAdd(videoDetails.files[0].magnetUri, true)
0e1dc3e7
C
430 expect(torrent.files).to.be.an('array')
431 expect(torrent.files.length).to.equal(1)
432 expect(torrent.files[0].path).to.exist.and.to.not.equal('')
433 })
434
9a27cdc2 435 it('Should add the file 3 by asking server 2', async function () {
b18a501a 436 this.timeout(30000)
0e1dc3e7 437
89d241a7 438 const { data } = await servers[1].videos.list()
0e1dc3e7 439
d23dd9fb 440 const video = data[2]
89d241a7 441 const videoDetails = await servers[1].videos.get({ id: video.id })
0e1dc3e7 442
b1f5b93e 443 const torrent = await webtorrentAdd(videoDetails.files[0].magnetUri, true)
0e1dc3e7
C
444 expect(torrent.files).to.be.an('array')
445 expect(torrent.files.length).to.equal(1)
446 expect(torrent.files[0].path).to.exist.and.to.not.equal('')
447 })
448
9a27cdc2 449 it('Should add the file 3-2 by asking server 1', async function () {
b18a501a 450 this.timeout(30000)
0e1dc3e7 451
89d241a7 452 const { data } = await servers[0].videos.list()
0e1dc3e7 453
d23dd9fb 454 const video = data[3]
89d241a7 455 const videoDetails = await servers[0].videos.get({ id: video.id })
0e1dc3e7 456
5f04dd2f 457 const torrent = await webtorrentAdd(videoDetails.files[0].magnetUri)
0e1dc3e7
C
458 expect(torrent.files).to.be.an('array')
459 expect(torrent.files.length).to.equal(1)
460 expect(torrent.files[0].path).to.exist.and.to.not.equal('')
461 })
14d3270f 462
9a27cdc2 463 it('Should add the file 2 in 360p by asking server 1', async function () {
b18a501a 464 this.timeout(30000)
14d3270f 465
89d241a7 466 const { data } = await servers[0].videos.list()
14d3270f 467
d23dd9fb 468 const video = data.find(v => v.name === 'my super name for server 2')
89d241a7 469 const videoDetails = await servers[0].videos.get({ id: video.id })
5f04dd2f 470
5d00a3d7 471 const file = videoDetails.files.find(f => f.resolution.id === 360)
14d3270f
C
472 expect(file).not.to.be.undefined
473
474 const torrent = await webtorrentAdd(file.magnetUri)
475 expect(torrent.files).to.be.an('array')
476 expect(torrent.files.length).to.equal(1)
477 expect(torrent.files[0].path).to.exist.and.to.not.equal('')
478 })
0e1dc3e7
C
479 })
480
481 describe('Should update video views, likes and dislikes', function () {
9a27cdc2
C
482 let localVideosServer3 = []
483 let remoteVideosServer1 = []
484 let remoteVideosServer2 = []
485 let remoteVideosServer3 = []
0e1dc3e7
C
486
487 before(async function () {
d23dd9fb 488 {
89d241a7 489 const { data } = await servers[0].videos.list()
d23dd9fb
C
490 remoteVideosServer1 = data.filter(video => video.isLocal === false).map(video => video.uuid)
491 }
0e1dc3e7 492
d23dd9fb 493 {
89d241a7 494 const { data } = await servers[1].videos.list()
d23dd9fb
C
495 remoteVideosServer2 = data.filter(video => video.isLocal === false).map(video => video.uuid)
496 }
0e1dc3e7 497
d23dd9fb 498 {
89d241a7 499 const { data } = await servers[2].videos.list()
d23dd9fb
C
500 localVideosServer3 = data.filter(video => video.isLocal === true).map(video => video.uuid)
501 remoteVideosServer3 = data.filter(video => video.isLocal === false).map(video => video.uuid)
502 }
0e1dc3e7
C
503 })
504
505 it('Should view multiple videos on owned servers', async function () {
6b616860 506 this.timeout(30000)
0e1dc3e7 507
89d241a7 508 await servers[2].videos.view({ id: localVideosServer3[0] })
511765c9 509 await wait(1000)
b5c0e955 510
89d241a7
C
511 await servers[2].videos.view({ id: localVideosServer3[0] })
512 await servers[2].videos.view({ id: localVideosServer3[1] })
b5c0e955 513
511765c9 514 await wait(1000)
b5c0e955 515
89d241a7
C
516 await servers[2].videos.view({ id: localVideosServer3[0] })
517 await servers[2].videos.view({ id: localVideosServer3[0] })
0e1dc3e7 518
3cd0734f 519 await waitJobs(servers)
0e1dc3e7 520
6b616860
C
521 // Wait the repeatable job
522 await wait(6000)
523
c883db6d
C
524 await waitJobs(servers)
525
0e1dc3e7 526 for (const server of servers) {
89d241a7 527 const { data } = await server.videos.list()
0e1dc3e7 528
d23dd9fb
C
529 const video0 = data.find(v => v.uuid === localVideosServer3[0])
530 const video1 = data.find(v => v.uuid === localVideosServer3[1])
5f04dd2f 531
1f3e9fec
C
532 expect(video0.views).to.equal(3)
533 expect(video1.views).to.equal(1)
0e1dc3e7
C
534 }
535 })
536
537 it('Should view multiple videos on each servers', async function () {
24163420 538 this.timeout(45000)
0e1dc3e7
C
539
540 const tasks: Promise<any>[] = []
89d241a7
C
541 tasks.push(servers[0].videos.view({ id: remoteVideosServer1[0] }))
542 tasks.push(servers[1].videos.view({ id: remoteVideosServer2[0] }))
543 tasks.push(servers[1].videos.view({ id: remoteVideosServer2[0] }))
544 tasks.push(servers[2].videos.view({ id: remoteVideosServer3[0] }))
545 tasks.push(servers[2].videos.view({ id: remoteVideosServer3[1] }))
546 tasks.push(servers[2].videos.view({ id: remoteVideosServer3[1] }))
547 tasks.push(servers[2].videos.view({ id: remoteVideosServer3[1] }))
548 tasks.push(servers[2].videos.view({ id: localVideosServer3[1] }))
549 tasks.push(servers[2].videos.view({ id: localVideosServer3[1] }))
550 tasks.push(servers[2].videos.view({ id: localVideosServer3[1] }))
0e1dc3e7
C
551
552 await Promise.all(tasks)
553
3cd0734f 554 await waitJobs(servers)
0e1dc3e7 555
6b616860 556 // Wait the repeatable job
24163420 557 await wait(16000)
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)
0e1dc3e7
C
610 expect(baseVideo.likes).to.equal(sameVideo.likes)
611 expect(baseVideo.dislikes).to.equal(sameVideo.dislikes)
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})