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