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