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