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