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