]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/tests/api/videos/multiple-servers.ts
Support live session in server
[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
b2111066 507 await servers[2].views.simulateView({ id: localVideosServer3[0] })
511765c9 508 await wait(1000)
b5c0e955 509
b2111066
C
510 await servers[2].views.simulateView({ id: localVideosServer3[0] })
511 await servers[2].views.simulateView({ id: localVideosServer3[1] })
b5c0e955 512
511765c9 513 await wait(1000)
b5c0e955 514
b2111066
C
515 await servers[2].views.simulateView({ id: localVideosServer3[0] })
516 await servers[2].views.simulateView({ id: localVideosServer3[0] })
0e1dc3e7 517
3cd0734f 518 await waitJobs(servers)
0e1dc3e7 519
b2111066
C
520 for (const server of servers) {
521 await server.debug.sendCommand({ body: { command: 'process-video-views-buffer' } })
522 }
6b616860 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>[] = []
b2111066
C
541 tasks.push(servers[0].views.simulateView({ id: remoteVideosServer1[0] }))
542 tasks.push(servers[1].views.simulateView({ id: remoteVideosServer2[0] }))
543 tasks.push(servers[1].views.simulateView({ id: remoteVideosServer2[0] }))
544 tasks.push(servers[2].views.simulateView({ id: remoteVideosServer3[0] }))
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: remoteVideosServer3[1] }))
548 tasks.push(servers[2].views.simulateView({ id: localVideosServer3[1] }))
549 tasks.push(servers[2].views.simulateView({ id: localVideosServer3[1] }))
550 tasks.push(servers[2].views.simulateView({ id: localVideosServer3[1] }))
0e1dc3e7
C
551
552 await Promise.all(tasks)
553
3cd0734f 554 await waitJobs(servers)
0e1dc3e7 555
b2111066
C
556 for (const server of servers) {
557 await server.debug.sendCommand({ body: { command: 'process-video-views-buffer' } })
558 }
6b616860 559
c883db6d
C
560 await waitJobs(servers)
561
0e1dc3e7
C
562 let baseVideos = null
563
564 for (const server of servers) {
89d241a7 565 const { data } = await server.videos.list()
0e1dc3e7
C
566
567 // Initialize base videos for future comparisons
568 if (baseVideos === null) {
d23dd9fb 569 baseVideos = data
35a097b8 570 continue
0e1dc3e7
C
571 }
572
573 for (const baseVideo of baseVideos) {
d23dd9fb 574 const sameVideo = data.find(video => video.name === baseVideo.name)
0e1dc3e7
C
575 expect(baseVideo.views).to.equal(sameVideo.views)
576 }
577 }
578 })
579
580 it('Should like and dislikes videos on different services', async function () {
185eabe1 581 this.timeout(50000)
0e1dc3e7 582
89d241a7 583 await servers[0].videos.rate({ id: remoteVideosServer1[0], rating: 'like' })
2ba92871 584 await wait(500)
89d241a7 585 await servers[0].videos.rate({ id: remoteVideosServer1[0], rating: 'dislike' })
2ba92871 586 await wait(500)
89d241a7
C
587 await servers[0].videos.rate({ id: remoteVideosServer1[0], rating: 'like' })
588 await servers[2].videos.rate({ id: localVideosServer3[1], rating: 'like' })
2ba92871 589 await wait(500)
89d241a7
C
590 await servers[2].videos.rate({ id: localVideosServer3[1], rating: 'dislike' })
591 await servers[2].videos.rate({ id: remoteVideosServer3[1], rating: 'dislike' })
2ba92871 592 await wait(500)
89d241a7 593 await servers[2].videos.rate({ id: remoteVideosServer3[0], rating: 'like' })
0e1dc3e7 594
3cd0734f 595 await waitJobs(servers)
021c4265 596 await wait(5000)
0d8ecb75 597 await waitJobs(servers)
0e1dc3e7
C
598
599 let baseVideos = null
600 for (const server of servers) {
89d241a7 601 const { data } = await server.videos.list()
0e1dc3e7
C
602
603 // Initialize base videos for future comparisons
604 if (baseVideos === null) {
d23dd9fb 605 baseVideos = data
35a097b8 606 continue
0e1dc3e7
C
607 }
608
35a097b8 609 for (const baseVideo of baseVideos) {
d23dd9fb 610 const sameVideo = data.find(video => video.name === baseVideo.name)
57e4e1c1
C
611 expect(baseVideo.likes).to.equal(sameVideo.likes, `Likes of ${sameVideo.uuid} do not correspond`)
612 expect(baseVideo.dislikes).to.equal(sameVideo.dislikes, `Dislikes of ${sameVideo.uuid} do not correspond`)
35a097b8 613 }
0e1dc3e7
C
614 }
615 })
616 })
617
618 describe('Should manipulate these videos', function () {
d78b51aa
C
619 let updatedAtMin: Date
620
621 it('Should update video 3', async function () {
b18a501a 622 this.timeout(30000)
0e1dc3e7
C
623
624 const attributes = {
625 name: 'my super video updated',
626 category: 10,
627 licence: 7,
9d3ef9fe 628 language: 'fr',
0e1dc3e7
C
629 nsfw: true,
630 description: 'my super description updated',
2422c46b 631 support: 'my super support text updated',
ac81d1a0
C
632 tags: [ 'tag_up_1', 'tag_up_2' ],
633 thumbnailfile: 'thumbnail.jpg',
7519127b 634 originallyPublishedAt: '2019-02-11T13:38:14.449Z',
ac81d1a0 635 previewfile: 'preview.jpg'
0e1dc3e7
C
636 }
637
d78b51aa 638 updatedAtMin = new Date()
89d241a7 639 await servers[2].videos.update({ id: toRemove[0].id, attributes })
0e1dc3e7 640
3cd0734f 641 await waitJobs(servers)
0e1dc3e7
C
642 })
643
9a27cdc2 644 it('Should have the video 3 updated on each server', async function () {
b18a501a 645 this.timeout(30000)
0e1dc3e7
C
646
647 for (const server of servers) {
89d241a7 648 const { data } = await server.videos.list()
0e1dc3e7 649
d23dd9fb 650 const videoUpdated = data.find(video => video.name === 'my super video updated')
0e1dc3e7 651 expect(!!videoUpdated).to.be.true
0e1dc3e7 652
d78b51aa
C
653 expect(new Date(videoUpdated.updatedAt)).to.be.greaterThan(updatedAtMin)
654
7243f84d 655 const isLocal = server.url === 'http://localhost:' + servers[2].port
b1f5b93e
C
656 const checkAttributes = {
657 name: 'my super video updated',
658 category: 10,
659 licence: 7,
9d3ef9fe 660 language: 'fr',
b1f5b93e
C
661 nsfw: true,
662 description: 'my super description updated',
2422c46b 663 support: 'my super support text updated',
7519127b 664 originallyPublishedAt: '2019-02-11T13:38:14.449Z',
b64c950a
C
665 account: {
666 name: 'root',
7243f84d 667 host: 'localhost:' + servers[2].port
b64c950a 668 },
b1f5b93e
C
669 isLocal,
670 duration: 5,
47564bbe 671 commentsEnabled: true,
7f2cfe3a 672 downloadEnabled: true,
b1f5b93e
C
673 tags: [ 'tag_up_1', 'tag_up_2' ],
674 privacy: VideoPrivacy.PUBLIC,
675 channel: {
f6eebcb3
C
676 displayName: 'Main root channel',
677 name: 'root_channel',
b1f5b93e
C
678 description: '',
679 isLocal
680 },
681 fixture: 'video_short3.webm',
682 files: [
683 {
684 resolution: 720,
685 size: 292677
686 }
ac81d1a0
C
687 ],
688 thumbnailfile: 'thumbnail',
689 previewfile: 'preview'
b1f5b93e 690 }
d23dd9fb 691 await completeVideoCheck(server, videoUpdated, checkAttributes)
0e1dc3e7
C
692 }
693 })
694
5cf027bd 695 it('Should only update thumbnail and update updatedAt attribute', async function () {
b18a501a 696 this.timeout(30000)
5cf027bd
C
697
698 const attributes = {
699 thumbnailfile: 'thumbnail.jpg'
700 }
701
702 updatedAtMin = new Date()
703 await servers[2].videos.update({ id: toRemove[0].id, attributes })
704
705 await waitJobs(servers)
706
707 for (const server of servers) {
708 const { data } = await server.videos.list()
709
710 const videoUpdated = data.find(video => video.name === 'my super video updated')
711 expect(new Date(videoUpdated.updatedAt)).to.be.greaterThan(updatedAtMin)
712 }
713 })
714
83903cb6
C
715 it('Should remove the videos 3 and 3-2 by asking server 3 and correctly delete files', async function () {
716 this.timeout(30000)
0e1dc3e7 717
83903cb6
C
718 for (const id of [ toRemove[0].id, toRemove[1].id ]) {
719 await saveVideoInServers(servers, id)
0e1dc3e7 720
83903cb6 721 await servers[2].videos.remove({ id })
0e1dc3e7 722
83903cb6
C
723 await waitJobs(servers)
724
725 for (const server of servers) {
726 await checkVideoFilesWereRemoved({ server, video: server.store.videoDetails })
727 }
f05a1c30
C
728 }
729 })
730
9a27cdc2 731 it('Should have videos 1 and 3 on each server', async function () {
0e1dc3e7 732 for (const server of servers) {
89d241a7 733 const { data } = await server.videos.list()
d23dd9fb
C
734
735 expect(data).to.be.an('array')
736 expect(data.length).to.equal(2)
737 expect(data[0].name).not.to.equal(data[1].name)
738 expect(data[0].name).not.to.equal(toRemove[0].name)
739 expect(data[1].name).not.to.equal(toRemove[0].name)
740 expect(data[0].name).not.to.equal(toRemove[1].name)
741 expect(data[1].name).not.to.equal(toRemove[1].name)
742
743 videoUUID = data.find(video => video.name === 'my super name for server 1').uuid
0e1dc3e7
C
744 }
745 })
746
9a27cdc2 747 it('Should get the same video by UUID on each server', async function () {
0e1dc3e7
C
748 let baseVideo = null
749 for (const server of servers) {
89d241a7 750 const video = await server.videos.get({ id: videoUUID })
0e1dc3e7
C
751
752 if (baseVideo === null) {
753 baseVideo = video
35a097b8 754 continue
0e1dc3e7
C
755 }
756
757 expect(baseVideo.name).to.equal(video.name)
758 expect(baseVideo.uuid).to.equal(video.uuid)
5d00a3d7
C
759 expect(baseVideo.category.id).to.equal(video.category.id)
760 expect(baseVideo.language.id).to.equal(video.language.id)
761 expect(baseVideo.licence.id).to.equal(video.licence.id)
0e1dc3e7 762 expect(baseVideo.nsfw).to.equal(video.nsfw)
b64c950a
C
763 expect(baseVideo.account.name).to.equal(video.account.name)
764 expect(baseVideo.account.displayName).to.equal(video.account.displayName)
765 expect(baseVideo.account.url).to.equal(video.account.url)
766 expect(baseVideo.account.host).to.equal(video.account.host)
0e1dc3e7
C
767 expect(baseVideo.tags).to.deep.equal(video.tags)
768 }
769 })
770
9a27cdc2 771 it('Should get the preview from each server', async function () {
0e1dc3e7 772 for (const server of servers) {
89d241a7 773 const video = await server.videos.get({ id: videoUUID })
0e1dc3e7 774
7b0956ec 775 await testImage(server.url, 'video_short1-preview.webm', video.previewPath)
0e1dc3e7
C
776 }
777 })
778 })
779
d50acfab 780 describe('Should comment these videos', function () {
73c08093
C
781 let childOfFirstChild: VideoCommentThreadTree
782
d50acfab
C
783 it('Should add comment (threads and replies)', async function () {
784 this.timeout(25000)
785
786 {
787 const text = 'my super first comment'
89d241a7 788 await servers[0].comments.createThread({ videoId: videoUUID, text })
d50acfab
C
789 }
790
791 {
792 const text = 'my super second comment'
89d241a7 793 await servers[2].comments.createThread({ videoId: videoUUID, text })
d50acfab
C
794 }
795
3cd0734f 796 await waitJobs(servers)
d50acfab
C
797
798 {
89d241a7 799 const threadId = await servers[1].comments.findCommentId({ videoId: videoUUID, text: 'my super first comment' })
d50acfab
C
800
801 const text = 'my super answer to thread 1'
89d241a7 802 await servers[1].comments.addReply({ videoId: videoUUID, toCommentId: threadId, text })
d50acfab
C
803 }
804
3cd0734f 805 await waitJobs(servers)
d50acfab
C
806
807 {
89d241a7 808 const threadId = await servers[2].comments.findCommentId({ videoId: videoUUID, text: 'my super first comment' })
d50acfab 809
89d241a7 810 const body = await servers[2].comments.getThread({ videoId: videoUUID, threadId })
12edc149 811 const childCommentId = body.children[0].comment.id
d50acfab
C
812
813 const text3 = 'my second answer to thread 1'
89d241a7 814 await servers[2].comments.addReply({ videoId: videoUUID, toCommentId: threadId, text: text3 })
d50acfab
C
815
816 const text2 = 'my super answer to answer of thread 1'
89d241a7 817 await servers[2].comments.addReply({ videoId: videoUUID, toCommentId: childCommentId, text: text2 })
d50acfab
C
818 }
819
3cd0734f 820 await waitJobs(servers)
d50acfab
C
821 })
822
823 it('Should have these threads', async function () {
824 for (const server of servers) {
89d241a7 825 const body = await server.comments.listThreads({ videoId: videoUUID })
d50acfab 826
12edc149
C
827 expect(body.total).to.equal(2)
828 expect(body.data).to.be.an('array')
829 expect(body.data).to.have.lengthOf(2)
d50acfab
C
830
831 {
12edc149 832 const comment = body.data.find(c => c.text === 'my super first comment')
d50acfab
C
833 expect(comment).to.not.be.undefined
834 expect(comment.inReplyToCommentId).to.be.null
835 expect(comment.account.name).to.equal('root')
7243f84d 836 expect(comment.account.host).to.equal('localhost:' + servers[0].port)
d50acfab
C
837 expect(comment.totalReplies).to.equal(3)
838 expect(dateIsValid(comment.createdAt as string)).to.be.true
839 expect(dateIsValid(comment.updatedAt as string)).to.be.true
840 }
841
842 {
12edc149 843 const comment = body.data.find(c => c.text === 'my super second comment')
d50acfab
C
844 expect(comment).to.not.be.undefined
845 expect(comment.inReplyToCommentId).to.be.null
846 expect(comment.account.name).to.equal('root')
7243f84d 847 expect(comment.account.host).to.equal('localhost:' + servers[2].port)
d50acfab
C
848 expect(comment.totalReplies).to.equal(0)
849 expect(dateIsValid(comment.createdAt as string)).to.be.true
850 expect(dateIsValid(comment.updatedAt as string)).to.be.true
851 }
852 }
853 })
854
855 it('Should have these comments', async function () {
856 for (const server of servers) {
89d241a7 857 const body = await server.comments.listThreads({ videoId: videoUUID })
12edc149 858 const threadId = body.data.find(c => c.text === 'my super first comment').id
d50acfab 859
89d241a7 860 const tree = await server.comments.getThread({ videoId: videoUUID, threadId })
d50acfab 861
d50acfab
C
862 expect(tree.comment.text).equal('my super first comment')
863 expect(tree.comment.account.name).equal('root')
7243f84d 864 expect(tree.comment.account.host).equal('localhost:' + servers[0].port)
d50acfab
C
865 expect(tree.children).to.have.lengthOf(2)
866
867 const firstChild = tree.children[0]
868 expect(firstChild.comment.text).to.equal('my super answer to thread 1')
869 expect(firstChild.comment.account.name).equal('root')
7243f84d 870 expect(firstChild.comment.account.host).equal('localhost:' + servers[1].port)
d50acfab
C
871 expect(firstChild.children).to.have.lengthOf(1)
872
73c08093 873 childOfFirstChild = firstChild.children[0]
d50acfab
C
874 expect(childOfFirstChild.comment.text).to.equal('my super answer to answer of thread 1')
875 expect(childOfFirstChild.comment.account.name).equal('root')
7243f84d 876 expect(childOfFirstChild.comment.account.host).equal('localhost:' + servers[2].port)
d50acfab
C
877 expect(childOfFirstChild.children).to.have.lengthOf(0)
878
879 const secondChild = tree.children[1]
880 expect(secondChild.comment.text).to.equal('my second answer to thread 1')
881 expect(secondChild.comment.account.name).equal('root')
7243f84d 882 expect(secondChild.comment.account.host).equal('localhost:' + servers[2].port)
d50acfab
C
883 expect(secondChild.children).to.have.lengthOf(0)
884 }
885 })
47564bbe 886
73c08093 887 it('Should delete a reply', async function () {
b18a501a 888 this.timeout(30000)
73c08093 889
89d241a7 890 await servers[2].comments.delete({ videoId: videoUUID, commentId: childOfFirstChild.comment.id })
73c08093 891
3cd0734f 892 await waitJobs(servers)
73c08093
C
893 })
894
69222afa 895 it('Should have this comment marked as deleted', async function () {
73c08093 896 for (const server of servers) {
89d241a7 897 const { data } = await server.comments.listThreads({ videoId: videoUUID })
12edc149 898 const threadId = data.find(c => c.text === 'my super first comment').id
73c08093 899
89d241a7 900 const tree = await server.comments.getThread({ videoId: videoUUID, threadId })
73c08093
C
901 expect(tree.comment.text).equal('my super first comment')
902
903 const firstChild = tree.children[0]
904 expect(firstChild.comment.text).to.equal('my super answer to thread 1')
69222afa
JM
905 expect(firstChild.children).to.have.lengthOf(1)
906
907 const deletedComment = firstChild.children[0].comment
908 expect(deletedComment.isDeleted).to.be.true
909 expect(deletedComment.deletedAt).to.not.be.null
910 expect(deletedComment.account).to.be.null
911 expect(deletedComment.text).to.equal('')
73c08093
C
912
913 const secondChild = tree.children[1]
914 expect(secondChild.comment.text).to.equal('my second answer to thread 1')
915 }
916 })
917
4cb6d457 918 it('Should delete the thread comments', async function () {
b18a501a 919 this.timeout(30000)
4cb6d457 920
89d241a7 921 const { data } = await servers[0].comments.listThreads({ videoId: videoUUID })
12edc149 922 const commentId = data.find(c => c.text === 'my super first comment').id
89d241a7 923 await servers[0].comments.delete({ videoId: videoUUID, commentId })
4cb6d457 924
3cd0734f 925 await waitJobs(servers)
4cb6d457
C
926 })
927
69222afa 928 it('Should have the threads marked as deleted on other servers too', async function () {
4cb6d457 929 for (const server of servers) {
89d241a7 930 const body = await server.comments.listThreads({ videoId: videoUUID })
4cb6d457 931
12edc149
C
932 expect(body.total).to.equal(2)
933 expect(body.data).to.be.an('array')
934 expect(body.data).to.have.lengthOf(2)
4cb6d457
C
935
936 {
12edc149 937 const comment = body.data[0]
4cb6d457
C
938 expect(comment).to.not.be.undefined
939 expect(comment.inReplyToCommentId).to.be.null
940 expect(comment.account.name).to.equal('root')
7243f84d 941 expect(comment.account.host).to.equal('localhost:' + servers[2].port)
4cb6d457
C
942 expect(comment.totalReplies).to.equal(0)
943 expect(dateIsValid(comment.createdAt as string)).to.be.true
944 expect(dateIsValid(comment.updatedAt as string)).to.be.true
945 }
69222afa
JM
946
947 {
12edc149 948 const deletedComment = body.data[1]
69222afa
JM
949 expect(deletedComment).to.not.be.undefined
950 expect(deletedComment.isDeleted).to.be.true
951 expect(deletedComment.deletedAt).to.not.be.null
952 expect(deletedComment.text).to.equal('')
953 expect(deletedComment.inReplyToCommentId).to.be.null
954 expect(deletedComment.account).to.be.null
99cb53fd 955 expect(deletedComment.totalReplies).to.equal(2)
69222afa
JM
956 expect(dateIsValid(deletedComment.createdAt as string)).to.be.true
957 expect(dateIsValid(deletedComment.updatedAt as string)).to.be.true
958 expect(dateIsValid(deletedComment.deletedAt as string)).to.be.true
959 }
4cb6d457
C
960 }
961 })
962
511765c9 963 it('Should delete a remote thread by the origin server', async function () {
b5206dfc
JM
964 this.timeout(5000)
965
89d241a7 966 const { data } = await servers[0].comments.listThreads({ videoId: videoUUID })
12edc149 967 const commentId = data.find(c => c.text === 'my super second comment').id
89d241a7 968 await servers[0].comments.delete({ videoId: videoUUID, commentId })
511765c9
C
969
970 await waitJobs(servers)
971 })
972
69222afa 973 it('Should have the threads marked as deleted on other servers too', async function () {
511765c9 974 for (const server of servers) {
89d241a7 975 const body = await server.comments.listThreads({ videoId: videoUUID })
511765c9 976
12edc149
C
977 expect(body.total).to.equal(2)
978 expect(body.data).to.have.lengthOf(2)
69222afa
JM
979
980 {
12edc149 981 const comment = body.data[0]
69222afa
JM
982 expect(comment.text).to.equal('')
983 expect(comment.isDeleted).to.be.true
984 expect(comment.createdAt).to.not.be.null
985 expect(comment.deletedAt).to.not.be.null
986 expect(comment.account).to.be.null
987 expect(comment.totalReplies).to.equal(0)
988 }
989
990 {
12edc149 991 const comment = body.data[1]
69222afa
JM
992 expect(comment.text).to.equal('')
993 expect(comment.isDeleted).to.be.true
994 expect(comment.createdAt).to.not.be.null
995 expect(comment.deletedAt).to.not.be.null
996 expect(comment.account).to.be.null
99cb53fd 997 expect(comment.totalReplies).to.equal(2)
69222afa 998 }
511765c9
C
999 }
1000 })
1001
53a94c7c 1002 it('Should disable comments and download', async function () {
47564bbe
C
1003 this.timeout(20000)
1004
1005 const attributes = {
53a94c7c
C
1006 commentsEnabled: false,
1007 downloadEnabled: false
47564bbe
C
1008 }
1009
89d241a7 1010 await servers[0].videos.update({ id: videoUUID, attributes })
47564bbe 1011
3cd0734f 1012 await waitJobs(servers)
47564bbe
C
1013
1014 for (const server of servers) {
89d241a7 1015 const video = await server.videos.get({ id: videoUUID })
d23dd9fb
C
1016 expect(video.commentsEnabled).to.be.false
1017 expect(video.downloadEnabled).to.be.false
47564bbe
C
1018
1019 const text = 'my super forbidden comment'
89d241a7 1020 await server.comments.createThread({ videoId: videoUUID, text, expectedStatus: HttpStatusCode.CONFLICT_409 })
47564bbe
C
1021 }
1022 })
d50acfab
C
1023 })
1024
f595d394
C
1025 describe('With minimum parameters', function () {
1026 it('Should upload and propagate the video', async function () {
2186386c 1027 this.timeout(60000)
f595d394
C
1028
1029 const path = '/api/v1/videos/upload'
1030
1031 const req = request(servers[1].url)
1032 .post(path)
1033 .set('Accept', 'application/json')
1034 .set('Authorization', 'Bearer ' + servers[1].accessToken)
1035 .field('name', 'minimum parameters')
1036 .field('privacy', '1')
f595d394
C
1037 .field('channelId', '1')
1038
3d470a53 1039 await req.attach('videofile', buildAbsoluteFixturePath('video_short.webm'))
f2eb23cd 1040 .expect(HttpStatusCode.OK_200)
f595d394 1041
3cd0734f 1042 await waitJobs(servers)
f595d394
C
1043
1044 for (const server of servers) {
89d241a7 1045 const { data } = await server.videos.list()
d23dd9fb 1046 const video = data.find(v => v.name === 'minimum parameters')
f595d394 1047
7243f84d 1048 const isLocal = server.url === 'http://localhost:' + servers[1].port
b1f5b93e
C
1049 const checkAttributes = {
1050 name: 'minimum parameters',
1051 category: null,
1052 licence: null,
1053 language: null,
1054 nsfw: false,
1055 description: null,
2422c46b 1056 support: null,
b64c950a
C
1057 account: {
1058 name: 'root',
7243f84d 1059 host: 'localhost:' + servers[1].port
b64c950a 1060 },
b1f5b93e
C
1061 isLocal,
1062 duration: 5,
210709a9 1063 commentsEnabled: true,
7519127b 1064 downloadEnabled: true,
a1587156 1065 tags: [],
b1f5b93e
C
1066 privacy: VideoPrivacy.PUBLIC,
1067 channel: {
f6eebcb3
C
1068 displayName: 'Main root channel',
1069 name: 'root_channel',
b1f5b93e
C
1070 description: '',
1071 isLocal
1072 },
1073 fixture: 'video_short.webm',
1074 files: [
1075 {
1076 resolution: 720,
d78b51aa 1077 size: 61000
b1f5b93e
C
1078 },
1079 {
1080 resolution: 480,
d78b51aa 1081 size: 40000
b1f5b93e
C
1082 },
1083 {
1084 resolution: 360,
d78b51aa 1085 size: 32000
b1f5b93e
C
1086 },
1087 {
1088 resolution: 240,
7519c4a2 1089 size: 23000
b1f5b93e
C
1090 }
1091 ]
1092 }
d23dd9fb 1093 await completeVideoCheck(server, video, checkAttributes)
f595d394
C
1094 }
1095 })
1096 })
1097
89231874
C
1098 describe('TMP directory', function () {
1099 it('Should have an empty tmp directory', async function () {
1100 for (const server of servers) {
1101 await checkTmpIsEmpty(server)
1102 }
1103 })
1104 })
1105
7c3b7976
C
1106 after(async function () {
1107 await cleanupTests(servers)
0e1dc3e7
C
1108 })
1109})