]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/tests/shared/live.ts
f165832fe7c29fb6a219cce1ec882712a5c572ab
[github/Chocobozzz/PeerTube.git] / server / tests / shared / live.ts
1 /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3 import { expect } from 'chai'
4 import { pathExists, readdir } from 'fs-extra'
5 import { join } from 'path'
6 import { wait } from '@shared/core-utils'
7 import { LiveVideo, VideoStreamingPlaylistType } from '@shared/models'
8 import { ObjectStorageCommand, PeerTubeServer } from '@shared/server-commands'
9 import { checkLiveSegmentHash, checkResolutionsInMasterPlaylist } from './streaming-playlists'
10
11 async function checkLiveCleanup (server: PeerTubeServer, videoUUID: string, savedResolutions: number[] = []) {
12 const basePath = server.servers.buildDirectory('streaming-playlists')
13 const hlsPath = join(basePath, 'hls', videoUUID)
14
15 if (savedResolutions.length === 0) {
16 return checkUnsavedLiveCleanup(server, videoUUID, hlsPath)
17 }
18
19 return checkSavedLiveCleanup(hlsPath, savedResolutions)
20 }
21
22 // ---------------------------------------------------------------------------
23
24 async function testVideoResolutions (options: {
25 originServer: PeerTubeServer
26 servers: PeerTubeServer[]
27 liveVideoId: string
28 resolutions: number[]
29 transcoded: boolean
30 objectStorage: boolean
31 }) {
32 const { originServer, servers, liveVideoId, resolutions, transcoded, objectStorage } = options
33
34 for (const server of servers) {
35 const { data } = await server.videos.list()
36 expect(data.find(v => v.uuid === liveVideoId)).to.exist
37
38 const video = await server.videos.get({ id: liveVideoId })
39 expect(video.streamingPlaylists).to.have.lengthOf(1)
40
41 const hlsPlaylist = video.streamingPlaylists.find(s => s.type === VideoStreamingPlaylistType.HLS)
42 expect(hlsPlaylist).to.exist
43 expect(hlsPlaylist.files).to.have.lengthOf(0) // Only fragmented mp4 files are displayed
44
45 await checkResolutionsInMasterPlaylist({ server, playlistUrl: hlsPlaylist.playlistUrl, resolutions, transcoded })
46
47 if (objectStorage) {
48 expect(hlsPlaylist.playlistUrl).to.contain(ObjectStorageCommand.getPlaylistBaseUrl())
49 }
50
51 for (let i = 0; i < resolutions.length; i++) {
52 const segmentNum = 3
53 const segmentName = `${i}-00000${segmentNum}.ts`
54 await originServer.live.waitUntilSegmentGeneration({ videoUUID: video.uuid, playlistNumber: i, segment: segmentNum })
55
56 const baseUrl = objectStorage
57 ? ObjectStorageCommand.getPlaylistBaseUrl() + 'hls'
58 : originServer.url + '/static/streaming-playlists/hls'
59
60 if (objectStorage) {
61 await originServer.live.waitUntilSegmentUpload({ playlistNumber: i, segment: segmentNum })
62 await wait(1000)
63
64 expect(hlsPlaylist.segmentsSha256Url).to.contain(ObjectStorageCommand.getPlaylistBaseUrl())
65 }
66
67 const subPlaylist = await originServer.streamingPlaylists.get({
68 url: `${baseUrl}/${video.uuid}/${i}.m3u8`,
69 withRetry: objectStorage // With object storage, the request may fail because of inconsistent data in S3
70 })
71
72 expect(subPlaylist).to.contain(segmentName)
73
74 await checkLiveSegmentHash({
75 server,
76 baseUrlSegment: baseUrl,
77 videoUUID: video.uuid,
78 segmentName,
79 hlsPlaylist
80 })
81 }
82 }
83 }
84
85 // ---------------------------------------------------------------------------
86
87 export {
88 checkLiveCleanup,
89 testVideoResolutions
90 }
91
92 // ---------------------------------------------------------------------------
93
94 async function checkSavedLiveCleanup (hlsPath: string, savedResolutions: number[] = []) {
95 const files = await readdir(hlsPath)
96
97 // fragmented file and playlist per resolution + master playlist + segments sha256 json file
98 expect(files).to.have.lengthOf(savedResolutions.length * 2 + 2)
99
100 for (const resolution of savedResolutions) {
101 const fragmentedFile = files.find(f => f.endsWith(`-${resolution}-fragmented.mp4`))
102 expect(fragmentedFile).to.exist
103
104 const playlistFile = files.find(f => f.endsWith(`${resolution}.m3u8`))
105 expect(playlistFile).to.exist
106 }
107
108 const masterPlaylistFile = files.find(f => f.endsWith('-master.m3u8'))
109 expect(masterPlaylistFile).to.exist
110
111 const shaFile = files.find(f => f.endsWith('-segments-sha256.json'))
112 expect(shaFile).to.exist
113 }
114
115 async function checkUnsavedLiveCleanup (server: PeerTubeServer, videoUUID: string, hlsPath: string) {
116 let live: LiveVideo
117
118 try {
119 live = await server.live.get({ videoId: videoUUID })
120 } catch {}
121
122 if (live?.permanentLive) {
123 expect(await pathExists(hlsPath)).to.be.true
124
125 const hlsFiles = await readdir(hlsPath)
126 expect(hlsFiles).to.have.lengthOf(1) // Only replays directory
127
128 const replayDir = join(hlsPath, 'replay')
129 expect(await pathExists(replayDir)).to.be.true
130
131 const replayFiles = await readdir(join(hlsPath, 'replay'))
132 expect(replayFiles).to.have.lengthOf(0)
133
134 return
135 }
136
137 expect(await pathExists(hlsPath)).to.be.false
138 }