]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/tests/api/redundancy/redundancy.ts
Merge branch 'release/3.3.0' into develop
[github/Chocobozzz/PeerTube.git] / server / tests / api / redundancy / redundancy.ts
CommitLineData
a1587156 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
26370ce4 2
26370ce4 3import 'mocha'
6949a1a1
C
4import * as chai from 'chai'
5import { readdir } from 'fs-extra'
6import * as magnetUtil from 'magnet-uri'
83903cb6 7import { basename, join } from 'path'
26370ce4 8import {
07b1a18a 9 checkSegmentHash,
b764380a
C
10 checkVideoFilesWereRemoved,
11 cleanupTests,
254d3579 12 createMultipleServers,
4c7e60bc 13 doubleFollow,
07b1a18a 14 killallServers,
83903cb6 15 makeRawRequest,
254d3579 16 PeerTubeServer,
4c7e60bc 17 root,
83903cb6 18 saveVideoInServers,
07b1a18a 19 setAccessTokensToServers,
26370ce4 20 wait,
6c5065a0 21 waitJobs
dab04709 22} from '@shared/extra-utils'
83903cb6
C
23import {
24 HttpStatusCode,
25 VideoDetails,
26 VideoFile,
27 VideoPrivacy,
28 VideoRedundancyStrategy,
29 VideoRedundancyStrategyWithManual
30} from '@shared/models'
26370ce4
C
31
32const expect = chai.expect
33
254d3579 34let servers: PeerTubeServer[] = []
83903cb6 35let video1Server2: VideoDetails
26370ce4 36
83903cb6 37async function checkMagnetWebseeds (file: VideoFile, baseWebseeds: string[], server: PeerTubeServer) {
26370ce4
C
38 const parsed = magnetUtil.decode(file.magnetUri)
39
40 for (const ws of baseWebseeds) {
83903cb6 41 const found = parsed.urlList.find(url => url === `${ws}${basename(file.fileUrl)}`)
26370ce4
C
42 expect(found, `Webseed ${ws} not found in ${file.magnetUri} on server ${server.url}`).to.not.be.undefined
43 }
44
45 expect(parsed.urlList).to.have.lengthOf(baseWebseeds.length)
83903cb6
C
46
47 for (const url of parsed.urlList) {
48 await makeRawRequest(url, HttpStatusCode.OK_200)
49 }
26370ce4
C
50}
51
254d3579 52async function createSingleServers (strategy: VideoRedundancyStrategy | null, additionalParams: any = {}, withWebtorrent = true) {
b764380a
C
53 const strategies: any[] = []
54
55 if (strategy !== null) {
56 strategies.push(
6c5065a0 57 {
b764380a
C
58 min_lifetime: '1 hour',
59 strategy: strategy,
6c5065a0
C
60 size: '400KB',
61
62 ...additionalParams
63 }
b764380a
C
64 )
65 }
66
26370ce4 67 const config = {
09209296 68 transcoding: {
7448551f
C
69 webtorrent: {
70 enabled: withWebtorrent
71 },
09209296
C
72 hls: {
73 enabled: true
74 }
75 },
26370ce4
C
76 redundancy: {
77 videos: {
78 check_interval: '5 seconds',
b764380a 79 strategies
26370ce4
C
80 }
81 }
82 }
b764380a 83
254d3579 84 servers = await createMultipleServers(3, config)
26370ce4
C
85
86 // Get the access tokens
87 await setAccessTokensToServers(servers)
88
89 {
83903cb6
C
90 const { id } = await servers[1].videos.upload({ attributes: { name: 'video 1 server 2' } })
91 video1Server2 = await servers[1].videos.get({ id })
26370ce4 92
83903cb6 93 await servers[1].videos.view({ id })
26370ce4
C
94 }
95
96 await waitJobs(servers)
97
98 // Server 1 and server 2 follow each other
a1587156 99 await doubleFollow(servers[0], servers[1])
26370ce4 100 // Server 1 and server 3 follow each other
a1587156 101 await doubleFollow(servers[0], servers[2])
26370ce4 102 // Server 2 and server 3 follow each other
a1587156 103 await doubleFollow(servers[1], servers[2])
26370ce4
C
104
105 await waitJobs(servers)
106}
107
83903cb6
C
108async function ensureSameFilenames (videoUUID: string) {
109 let webtorrentFilenames: string[]
110 let hlsFilenames: string[]
111
112 for (const server of servers) {
113 const video = await server.videos.getWithToken({ id: videoUUID })
114
115 // Ensure we use the same filenames that the origin
116
117 const localWebtorrentFilenames = video.files.map(f => basename(f.fileUrl)).sort()
118 const localHLSFilenames = video.streamingPlaylists[0].files.map(f => basename(f.fileUrl)).sort()
119
120 if (webtorrentFilenames) expect(webtorrentFilenames).to.deep.equal(localWebtorrentFilenames)
121 else webtorrentFilenames = localWebtorrentFilenames
122
123 if (hlsFilenames) expect(hlsFilenames).to.deep.equal(localHLSFilenames)
124 else hlsFilenames = localHLSFilenames
125 }
126
127 return { webtorrentFilenames, hlsFilenames }
128}
129
09209296 130async function check1WebSeed (videoUUID?: string) {
83903cb6 131 if (!videoUUID) videoUUID = video1Server2.uuid
26370ce4
C
132
133 const webseeds = [
83903cb6 134 `http://localhost:${servers[1].port}/static/webseed/`
26370ce4
C
135 ]
136
137 for (const server of servers) {
09209296 138 // With token to avoid issues with video follow constraints
89d241a7 139 const video = await server.videos.getWithToken({ id: videoUUID })
26370ce4 140
09209296 141 for (const f of video.files) {
83903cb6 142 await checkMagnetWebseeds(f, webseeds, server)
26370ce4
C
143 }
144 }
83903cb6
C
145
146 await ensureSameFilenames(videoUUID)
26370ce4
C
147}
148
09209296 149async function check2Webseeds (videoUUID?: string) {
83903cb6 150 if (!videoUUID) videoUUID = video1Server2.uuid
26370ce4
C
151
152 const webseeds = [
83903cb6
C
153 `http://localhost:${servers[0].port}/static/redundancy/`,
154 `http://localhost:${servers[1].port}/static/webseed/`
26370ce4
C
155 ]
156
157 for (const server of servers) {
89d241a7 158 const video = await server.videos.get({ id: videoUUID })
26370ce4
C
159
160 for (const file of video.files) {
83903cb6 161 await checkMagnetWebseeds(file, webseeds, server)
26370ce4
C
162 }
163 }
164
83903cb6
C
165 const { webtorrentFilenames } = await ensureSameFilenames(videoUUID)
166
7243f84d
C
167 const directories = [
168 'test' + servers[0].internalServerNumber + '/redundancy',
169 'test' + servers[1].internalServerNumber + '/videos'
170 ]
171
172 for (const directory of directories) {
b9fffa29 173 const files = await readdir(join(root(), directory))
26370ce4
C
174 expect(files).to.have.length.at.least(4)
175
83903cb6
C
176 // Ensure we files exist on disk
177 expect(files.find(f => webtorrentFilenames.includes(f))).to.exist
26370ce4
C
178 }
179}
180
09209296 181async function check0PlaylistRedundancies (videoUUID?: string) {
83903cb6 182 if (!videoUUID) videoUUID = video1Server2.uuid
09209296
C
183
184 for (const server of servers) {
185 // With token to avoid issues with video follow constraints
89d241a7 186 const video = await server.videos.getWithToken({ id: videoUUID })
09209296
C
187
188 expect(video.streamingPlaylists).to.be.an('array')
189 expect(video.streamingPlaylists).to.have.lengthOf(1)
190 expect(video.streamingPlaylists[0].redundancies).to.have.lengthOf(0)
191 }
83903cb6
C
192
193 await ensureSameFilenames(videoUUID)
09209296
C
194}
195
196async function check1PlaylistRedundancies (videoUUID?: string) {
83903cb6 197 if (!videoUUID) videoUUID = video1Server2.uuid
09209296
C
198
199 for (const server of servers) {
89d241a7 200 const video = await server.videos.get({ id: videoUUID })
09209296
C
201
202 expect(video.streamingPlaylists).to.have.lengthOf(1)
203 expect(video.streamingPlaylists[0].redundancies).to.have.lengthOf(1)
204
205 const redundancy = video.streamingPlaylists[0].redundancies[0]
206
207 expect(redundancy.baseUrl).to.equal(servers[0].url + '/static/redundancy/hls/' + videoUUID)
208 }
209
0b16f5f2 210 const baseUrlPlaylist = servers[1].url + '/static/streaming-playlists/hls'
4c280004
C
211 const baseUrlSegment = servers[0].url + '/static/redundancy/hls'
212
89d241a7 213 const video = await servers[0].videos.get({ id: videoUUID })
d23dd9fb 214 const hlsPlaylist = video.streamingPlaylists[0]
4c280004
C
215
216 for (const resolution of [ 240, 360, 480, 720 ]) {
57f879a5 217 await checkSegmentHash({ server: servers[1], baseUrlPlaylist, baseUrlSegment, videoUUID, resolution, hlsPlaylist })
4c280004 218 }
09209296 219
83903cb6
C
220 const { hlsFilenames } = await ensureSameFilenames(videoUUID)
221
7243f84d
C
222 const directories = [
223 'test' + servers[0].internalServerNumber + '/redundancy/hls',
224 'test' + servers[1].internalServerNumber + '/streaming-playlists/hls'
225 ]
226
227 for (const directory of directories) {
09209296
C
228 const files = await readdir(join(root(), directory, videoUUID))
229 expect(files).to.have.length.at.least(4)
230
83903cb6
C
231 // Ensure we files exist on disk
232 expect(files.find(f => hlsFilenames.includes(f))).to.exist
09209296
C
233 }
234}
235
b764380a
C
236async function checkStatsGlobal (strategy: VideoRedundancyStrategyWithManual) {
237 let totalSize: number = null
238 let statsLength = 1
239
240 if (strategy !== 'manual') {
241 totalSize = 409600
242 statsLength = 2
243 }
244
89d241a7 245 const data = await servers[0].stats.get()
b764380a 246 expect(data.videosRedundancy).to.have.lengthOf(statsLength)
09209296 247
b764380a 248 const stat = data.videosRedundancy[0]
09209296 249 expect(stat.strategy).to.equal(strategy)
b764380a
C
250 expect(stat.totalSize).to.equal(totalSize)
251
252 return stat
253}
254
6949a1a1 255async function checkStatsWith1Redundancy (strategy: VideoRedundancyStrategyWithManual, onlyHls = false) {
b764380a
C
256 const stat = await checkStatsGlobal(strategy)
257
9e3e3617 258 expect(stat.totalUsed).to.be.at.least(1).and.below(409601)
6949a1a1 259 expect(stat.totalVideoFiles).to.equal(onlyHls ? 4 : 8)
09209296
C
260 expect(stat.totalVideos).to.equal(1)
261}
262
7448551f 263async function checkStatsWithoutRedundancy (strategy: VideoRedundancyStrategyWithManual) {
b764380a 264 const stat = await checkStatsGlobal(strategy)
09209296 265
09209296
C
266 expect(stat.totalUsed).to.equal(0)
267 expect(stat.totalVideoFiles).to.equal(0)
268 expect(stat.totalVideos).to.equal(0)
269}
270
c3d29f69 271async function findServerFollows () {
89d241a7 272 const body = await servers[0].follows.getFollowings({ start: 0, count: 5, sort: '-createdAt' })
c3d29f69
C
273 const follows = body.data
274 const server2 = follows.find(f => f.following.host === `localhost:${servers[1].port}`)
275 const server3 = follows.find(f => f.following.host === `localhost:${servers[2].port}`)
276
277 return { server2, server3 }
278}
279
26370ce4 280async function enableRedundancyOnServer1 () {
89d241a7 281 await servers[0].redundancy.updateRedundancy({ host: servers[1].host, redundancyAllowed: true })
26370ce4 282
c3d29f69 283 const { server2, server3 } = await findServerFollows()
26370ce4
C
284
285 expect(server3).to.not.be.undefined
286 expect(server3.following.hostRedundancyAllowed).to.be.false
287
288 expect(server2).to.not.be.undefined
289 expect(server2.following.hostRedundancyAllowed).to.be.true
290}
291
292async function disableRedundancyOnServer1 () {
89d241a7 293 await servers[0].redundancy.updateRedundancy({ host: servers[1].host, redundancyAllowed: false })
26370ce4 294
c3d29f69 295 const { server2, server3 } = await findServerFollows()
26370ce4
C
296
297 expect(server3).to.not.be.undefined
298 expect(server3.following.hostRedundancyAllowed).to.be.false
299
300 expect(server2).to.not.be.undefined
301 expect(server2.following.hostRedundancyAllowed).to.be.false
302}
303
26370ce4
C
304describe('Test videos redundancy', function () {
305
306 describe('With most-views strategy', function () {
307 const strategy = 'most-views'
308
309 before(function () {
310 this.timeout(120000)
311
254d3579 312 return createSingleServers(strategy)
26370ce4
C
313 })
314
315 it('Should have 1 webseed on the first video', async function () {
09209296
C
316 await check1WebSeed()
317 await check0PlaylistRedundancies()
7448551f 318 await checkStatsWithoutRedundancy(strategy)
26370ce4
C
319 })
320
321 it('Should enable redundancy on server 1', function () {
322 return enableRedundancyOnServer1()
323 })
324
6cb3482c 325 it('Should have 2 webseeds on the first video', async function () {
09209296 326 this.timeout(80000)
26370ce4
C
327
328 await waitJobs(servers)
89d241a7 329 await servers[0].servers.waitUntilLog('Duplicated ', 5)
26370ce4
C
330 await waitJobs(servers)
331
09209296
C
332 await check2Webseeds()
333 await check1PlaylistRedundancies()
7448551f 334 await checkStatsWith1Redundancy(strategy)
26370ce4
C
335 })
336
337 it('Should undo redundancy on server 1 and remove duplicated videos', async function () {
09209296 338 this.timeout(80000)
26370ce4
C
339
340 await disableRedundancyOnServer1()
341
342 await waitJobs(servers)
343 await wait(5000)
344
09209296
C
345 await check1WebSeed()
346 await check0PlaylistRedundancies()
26370ce4 347
83903cb6 348 await checkVideoFilesWereRemoved({ server: servers[0], video: video1Server2, onlyVideoFiles: true })
26370ce4
C
349 })
350
7c3b7976
C
351 after(async function () {
352 return cleanupTests(servers)
26370ce4
C
353 })
354 })
355
356 describe('With trending strategy', function () {
357 const strategy = 'trending'
358
359 before(function () {
360 this.timeout(120000)
361
254d3579 362 return createSingleServers(strategy)
26370ce4
C
363 })
364
365 it('Should have 1 webseed on the first video', async function () {
09209296
C
366 await check1WebSeed()
367 await check0PlaylistRedundancies()
7448551f 368 await checkStatsWithoutRedundancy(strategy)
26370ce4
C
369 })
370
371 it('Should enable redundancy on server 1', function () {
372 return enableRedundancyOnServer1()
373 })
374
6cb3482c 375 it('Should have 2 webseeds on the first video', async function () {
09209296 376 this.timeout(80000)
26370ce4
C
377
378 await waitJobs(servers)
89d241a7 379 await servers[0].servers.waitUntilLog('Duplicated ', 5)
26370ce4
C
380 await waitJobs(servers)
381
09209296
C
382 await check2Webseeds()
383 await check1PlaylistRedundancies()
7448551f 384 await checkStatsWith1Redundancy(strategy)
26370ce4
C
385 })
386
387 it('Should unfollow on server 1 and remove duplicated videos', async function () {
09209296 388 this.timeout(80000)
26370ce4 389
89d241a7 390 await servers[0].follows.unfollow({ target: servers[1] })
26370ce4
C
391
392 await waitJobs(servers)
393 await wait(5000)
394
09209296
C
395 await check1WebSeed()
396 await check0PlaylistRedundancies()
26370ce4 397
83903cb6 398 await checkVideoFilesWereRemoved({ server: servers[0], video: video1Server2, onlyVideoFiles: true })
26370ce4
C
399 })
400
7c3b7976
C
401 after(async function () {
402 await cleanupTests(servers)
26370ce4
C
403 })
404 })
405
406 describe('With recently added strategy', function () {
407 const strategy = 'recently-added'
408
409 before(function () {
410 this.timeout(120000)
411
254d3579 412 return createSingleServers(strategy, { min_views: 3 })
26370ce4
C
413 })
414
415 it('Should have 1 webseed on the first video', async function () {
09209296
C
416 await check1WebSeed()
417 await check0PlaylistRedundancies()
7448551f 418 await checkStatsWithoutRedundancy(strategy)
26370ce4
C
419 })
420
421 it('Should enable redundancy on server 1', function () {
422 return enableRedundancyOnServer1()
423 })
424
425 it('Should still have 1 webseed on the first video', async function () {
09209296 426 this.timeout(80000)
26370ce4
C
427
428 await waitJobs(servers)
429 await wait(15000)
430 await waitJobs(servers)
431
09209296
C
432 await check1WebSeed()
433 await check0PlaylistRedundancies()
7448551f 434 await checkStatsWithoutRedundancy(strategy)
26370ce4
C
435 })
436
437 it('Should view 2 times the first video to have > min_views config', async function () {
09209296 438 this.timeout(80000)
26370ce4 439
83903cb6
C
440 await servers[0].videos.view({ id: video1Server2.uuid })
441 await servers[2].videos.view({ id: video1Server2.uuid })
26370ce4
C
442
443 await wait(10000)
444 await waitJobs(servers)
445 })
446
6cb3482c 447 it('Should have 2 webseeds on the first video', async function () {
09209296 448 this.timeout(80000)
26370ce4
C
449
450 await waitJobs(servers)
89d241a7 451 await servers[0].servers.waitUntilLog('Duplicated ', 5)
26370ce4
C
452 await waitJobs(servers)
453
09209296
C
454 await check2Webseeds()
455 await check1PlaylistRedundancies()
7448551f 456 await checkStatsWith1Redundancy(strategy)
26370ce4
C
457 })
458
459 it('Should remove the video and the redundancy files', async function () {
460 this.timeout(20000)
461
83903cb6
C
462 await saveVideoInServers(servers, video1Server2.uuid)
463 await servers[1].videos.remove({ id: video1Server2.uuid })
26370ce4
C
464
465 await waitJobs(servers)
466
467 for (const server of servers) {
83903cb6 468 await checkVideoFilesWereRemoved({ server, video: server.store.videoDetails })
26370ce4
C
469 }
470 })
471
7c3b7976
C
472 after(async function () {
473 await cleanupTests(servers)
26370ce4
C
474 })
475 })
476
7448551f
C
477 describe('With only HLS files', function () {
478 const strategy = 'recently-added'
479
480 before(async function () {
481 this.timeout(120000)
482
254d3579 483 await createSingleServers(strategy, { min_views: 3 }, false)
7448551f
C
484 })
485
486 it('Should have 0 playlist redundancy on the first video', async function () {
487 await check1WebSeed()
488 await check0PlaylistRedundancies()
489 })
490
491 it('Should enable redundancy on server 1', function () {
492 return enableRedundancyOnServer1()
493 })
494
495 it('Should still have 0 redundancy on the first video', async function () {
496 this.timeout(80000)
497
498 await waitJobs(servers)
499 await wait(15000)
500 await waitJobs(servers)
501
502 await check0PlaylistRedundancies()
503 await checkStatsWithoutRedundancy(strategy)
504 })
505
506 it('Should have 1 redundancy on the first video', async function () {
507 this.timeout(160000)
508
83903cb6
C
509 await servers[0].videos.view({ id: video1Server2.uuid })
510 await servers[2].videos.view({ id: video1Server2.uuid })
7448551f
C
511
512 await wait(10000)
513 await waitJobs(servers)
514
515 await waitJobs(servers)
89d241a7 516 await servers[0].servers.waitUntilLog('Duplicated ', 1)
7448551f
C
517 await waitJobs(servers)
518
519 await check1PlaylistRedundancies()
6949a1a1 520 await checkStatsWith1Redundancy(strategy, true)
7448551f
C
521 })
522
523 it('Should remove the video and the redundancy files', async function () {
524 this.timeout(20000)
525
83903cb6
C
526 await saveVideoInServers(servers, video1Server2.uuid)
527 await servers[1].videos.remove({ id: video1Server2.uuid })
7448551f
C
528
529 await waitJobs(servers)
530
531 for (const server of servers) {
83903cb6 532 await checkVideoFilesWereRemoved({ server, video: server.store.videoDetails })
7448551f
C
533 }
534 })
6949a1a1
C
535
536 after(async function () {
537 await cleanupTests(servers)
538 })
7448551f
C
539 })
540
b764380a
C
541 describe('With manual strategy', function () {
542 before(function () {
543 this.timeout(120000)
544
254d3579 545 return createSingleServers(null)
b764380a
C
546 })
547
548 it('Should have 1 webseed on the first video', async function () {
549 await check1WebSeed()
550 await check0PlaylistRedundancies()
7448551f 551 await checkStatsWithoutRedundancy('manual')
b764380a
C
552 })
553
554 it('Should create a redundancy on first video', async function () {
83903cb6 555 await servers[0].redundancy.addVideo({ videoId: video1Server2.id })
b764380a
C
556 })
557
558 it('Should have 2 webseeds on the first video', async function () {
559 this.timeout(80000)
560
561 await waitJobs(servers)
89d241a7 562 await servers[0].servers.waitUntilLog('Duplicated ', 5)
b764380a
C
563 await waitJobs(servers)
564
565 await check2Webseeds()
566 await check1PlaylistRedundancies()
7448551f 567 await checkStatsWith1Redundancy('manual')
b764380a
C
568 })
569
570 it('Should manually remove redundancies on server 1 and remove duplicated videos', async function () {
571 this.timeout(80000)
572
89d241a7 573 const body = await servers[0].redundancy.listVideos({ target: 'remote-videos' })
b764380a 574
dab04709 575 const videos = body.data
b764380a
C
576 expect(videos).to.have.lengthOf(1)
577
578 const video = videos[0]
dab04709 579
b764380a 580 for (const r of video.redundancies.files.concat(video.redundancies.streamingPlaylists)) {
89d241a7 581 await servers[0].redundancy.removeVideo({ redundancyId: r.id })
b764380a
C
582 }
583
584 await waitJobs(servers)
585 await wait(5000)
586
587 await check1WebSeed()
588 await check0PlaylistRedundancies()
589
83903cb6 590 await checkVideoFilesWereRemoved({ server: servers[0], video: video1Server2, onlyVideoFiles: true })
b764380a
C
591 })
592
593 after(async function () {
594 await cleanupTests(servers)
595 })
596 })
597
26370ce4
C
598 describe('Test expiration', function () {
599 const strategy = 'recently-added'
600
254d3579 601 async function checkContains (servers: PeerTubeServer[], str: string) {
26370ce4 602 for (const server of servers) {
83903cb6 603 const video = await server.videos.get({ id: video1Server2.uuid })
26370ce4
C
604
605 for (const f of video.files) {
606 expect(f.magnetUri).to.contain(str)
607 }
608 }
609 }
610
254d3579 611 async function checkNotContains (servers: PeerTubeServer[], str: string) {
26370ce4 612 for (const server of servers) {
83903cb6 613 const video = await server.videos.get({ id: video1Server2.uuid })
26370ce4
C
614
615 for (const f of video.files) {
616 expect(f.magnetUri).to.not.contain(str)
617 }
618 }
619 }
620
621 before(async function () {
622 this.timeout(120000)
623
254d3579 624 await createSingleServers(strategy, { min_lifetime: '7 seconds', min_views: 0 })
26370ce4
C
625
626 await enableRedundancyOnServer1()
627 })
628
629 it('Should still have 2 webseeds after 10 seconds', async function () {
09209296 630 this.timeout(80000)
26370ce4
C
631
632 await wait(10000)
633
634 try {
7243f84d 635 await checkContains(servers, 'http%3A%2F%2Flocalhost%3A' + servers[0].port)
26370ce4
C
636 } catch {
637 // Maybe a server deleted a redundancy in the scheduler
638 await wait(2000)
639
7243f84d 640 await checkContains(servers, 'http%3A%2F%2Flocalhost%3A' + servers[0].port)
26370ce4
C
641 }
642 })
643
644 it('Should stop server 1 and expire video redundancy', async function () {
09209296 645 this.timeout(80000)
26370ce4 646
9293139f 647 await killallServers([ servers[0] ])
26370ce4 648
6cb3482c 649 await wait(15000)
26370ce4 650
7243f84d 651 await checkNotContains([ servers[1], servers[2] ], 'http%3A%2F%2Flocalhost%3A' + servers[0].port)
26370ce4
C
652 })
653
7c3b7976
C
654 after(async function () {
655 await cleanupTests(servers)
26370ce4
C
656 })
657 })
658
659 describe('Test file replacement', function () {
660 let video2Server2UUID: string
661 const strategy = 'recently-added'
662
663 before(async function () {
664 this.timeout(120000)
665
254d3579 666 await createSingleServers(strategy, { min_lifetime: '7 seconds', min_views: 0 })
26370ce4
C
667
668 await enableRedundancyOnServer1()
669
670 await waitJobs(servers)
89d241a7 671 await servers[0].servers.waitUntilLog('Duplicated ', 5)
26370ce4
C
672 await waitJobs(servers)
673
83903cb6
C
674 await check2Webseeds()
675 await check1PlaylistRedundancies()
7448551f 676 await checkStatsWith1Redundancy(strategy)
26370ce4 677
89d241a7 678 const { uuid } = await servers[1].videos.upload({ attributes: { name: 'video 2 server 2', privacy: VideoPrivacy.PRIVATE } })
d23dd9fb 679 video2Server2UUID = uuid
5e8dd6e0
C
680
681 // Wait transcoding before federation
682 await waitJobs(servers)
683
89d241a7 684 await servers[1].videos.update({ id: video2Server2UUID, attributes: { privacy: VideoPrivacy.PUBLIC } })
26370ce4
C
685 })
686
6cb3482c
C
687 it('Should cache video 2 webseeds on the first video', async function () {
688 this.timeout(120000)
26370ce4
C
689
690 await waitJobs(servers)
691
6cb3482c 692 let checked = false
26370ce4 693
6cb3482c
C
694 while (checked === false) {
695 await wait(1000)
26370ce4
C
696
697 try {
83903cb6
C
698 await check1WebSeed()
699 await check0PlaylistRedundancies()
5e8dd6e0 700
09209296
C
701 await check2Webseeds(video2Server2UUID)
702 await check1PlaylistRedundancies(video2Server2UUID)
26370ce4 703
6cb3482c
C
704 checked = true
705 } catch {
706 checked = false
26370ce4
C
707 }
708 }
709 })
710
09209296
C
711 it('Should disable strategy and remove redundancies', async function () {
712 this.timeout(80000)
713
714 await waitJobs(servers)
715
9293139f 716 await killallServers([ servers[0] ])
254d3579 717 await servers[0].run({
09209296
C
718 redundancy: {
719 videos: {
720 check_interval: '1 second',
721 strategies: []
722 }
723 }
724 })
725
726 await waitJobs(servers)
727
83903cb6 728 await checkVideoFilesWereRemoved({ server: servers[0], video: video1Server2, onlyVideoFiles: true })
09209296
C
729 })
730
7c3b7976
C
731 after(async function () {
732 await cleanupTests(servers)
26370ce4
C
733 })
734 })
735})