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