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