aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/tests/shared/streaming-playlists.ts
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2023-04-21 15:00:01 +0200
committerChocobozzz <chocobozzz@cpy.re>2023-05-09 08:57:34 +0200
commitd102de1b38f2877463529c3b27bd35ffef4fd8bf (patch)
tree31fa0bdf26ad7a2ee46d600d804a6f03260266c8 /server/tests/shared/streaming-playlists.ts
parent2fe978744e5b74eb824e4d79c1bb9b840169f125 (diff)
downloadPeerTube-d102de1b38f2877463529c3b27bd35ffef4fd8bf.tar.gz
PeerTube-d102de1b38f2877463529c3b27bd35ffef4fd8bf.tar.zst
PeerTube-d102de1b38f2877463529c3b27bd35ffef4fd8bf.zip
Add runner server tests
Diffstat (limited to 'server/tests/shared/streaming-playlists.ts')
-rw-r--r--server/tests/shared/streaming-playlists.ts134
1 files changed, 91 insertions, 43 deletions
diff --git a/server/tests/shared/streaming-playlists.ts b/server/tests/shared/streaming-playlists.ts
index 1c38cb512..acfb2b408 100644
--- a/server/tests/shared/streaming-playlists.ts
+++ b/server/tests/shared/streaming-playlists.ts
@@ -4,10 +4,11 @@ import { expect } from 'chai'
4import { basename, dirname, join } from 'path' 4import { basename, dirname, join } from 'path'
5import { removeFragmentedMP4Ext, uuidRegex } from '@shared/core-utils' 5import { removeFragmentedMP4Ext, uuidRegex } from '@shared/core-utils'
6import { sha256 } from '@shared/extra-utils' 6import { sha256 } from '@shared/extra-utils'
7import { HttpStatusCode, VideoStreamingPlaylist, VideoStreamingPlaylistType } from '@shared/models' 7import { HttpStatusCode, VideoPrivacy, VideoResolution, VideoStreamingPlaylist, VideoStreamingPlaylistType } from '@shared/models'
8import { makeRawRequest, PeerTubeServer, webtorrentAdd } from '@shared/server-commands' 8import { makeRawRequest, PeerTubeServer } from '@shared/server-commands'
9import { expectStartWith } from './checks' 9import { expectStartWith } from './checks'
10import { hlsInfohashExist } from './tracker' 10import { hlsInfohashExist } from './tracker'
11import { checkWebTorrentWorks } from './webtorrent'
11 12
12async function checkSegmentHash (options: { 13async function checkSegmentHash (options: {
13 server: PeerTubeServer 14 server: PeerTubeServer
@@ -15,14 +16,15 @@ async function checkSegmentHash (options: {
15 baseUrlSegment: string 16 baseUrlSegment: string
16 resolution: number 17 resolution: number
17 hlsPlaylist: VideoStreamingPlaylist 18 hlsPlaylist: VideoStreamingPlaylist
19 token?: string
18}) { 20}) {
19 const { server, baseUrlPlaylist, baseUrlSegment, resolution, hlsPlaylist } = options 21 const { server, baseUrlPlaylist, baseUrlSegment, resolution, hlsPlaylist, token } = options
20 const command = server.streamingPlaylists 22 const command = server.streamingPlaylists
21 23
22 const file = hlsPlaylist.files.find(f => f.resolution.id === resolution) 24 const file = hlsPlaylist.files.find(f => f.resolution.id === resolution)
23 const videoName = basename(file.fileUrl) 25 const videoName = basename(file.fileUrl)
24 26
25 const playlist = await command.get({ url: `${baseUrlPlaylist}/${removeFragmentedMP4Ext(videoName)}.m3u8` }) 27 const playlist = await command.get({ url: `${baseUrlPlaylist}/${removeFragmentedMP4Ext(videoName)}.m3u8`, token })
26 28
27 const matches = /#EXT-X-BYTERANGE:(\d+)@(\d+)/.exec(playlist) 29 const matches = /#EXT-X-BYTERANGE:(\d+)@(\d+)/.exec(playlist)
28 30
@@ -33,11 +35,12 @@ async function checkSegmentHash (options: {
33 const segmentBody = await command.getFragmentedSegment({ 35 const segmentBody = await command.getFragmentedSegment({
34 url: `${baseUrlSegment}/${videoName}`, 36 url: `${baseUrlSegment}/${videoName}`,
35 expectedStatus: HttpStatusCode.PARTIAL_CONTENT_206, 37 expectedStatus: HttpStatusCode.PARTIAL_CONTENT_206,
36 range: `bytes=${range}` 38 range: `bytes=${range}`,
39 token
37 }) 40 })
38 41
39 const shaBody = await command.getSegmentSha256({ url: hlsPlaylist.segmentsSha256Url }) 42 const shaBody = await command.getSegmentSha256({ url: hlsPlaylist.segmentsSha256Url, token })
40 expect(sha256(segmentBody)).to.equal(shaBody[videoName][range]) 43 expect(sha256(segmentBody)).to.equal(shaBody[videoName][range], `Invalid sha256 result for ${videoName} range ${range}`)
41} 44}
42 45
43// --------------------------------------------------------------------------- 46// ---------------------------------------------------------------------------
@@ -64,19 +67,24 @@ async function checkResolutionsInMasterPlaylist (options: {
64 server: PeerTubeServer 67 server: PeerTubeServer
65 playlistUrl: string 68 playlistUrl: string
66 resolutions: number[] 69 resolutions: number[]
70 token?: string
67 transcoded?: boolean // default true 71 transcoded?: boolean // default true
68 withRetry?: boolean // default false 72 withRetry?: boolean // default false
69}) { 73}) {
70 const { server, playlistUrl, resolutions, withRetry = false, transcoded = true } = options 74 const { server, playlistUrl, resolutions, token, withRetry = false, transcoded = true } = options
71 75
72 const masterPlaylist = await server.streamingPlaylists.get({ url: playlistUrl, withRetry }) 76 const masterPlaylist = await server.streamingPlaylists.get({ url: playlistUrl, token, withRetry })
73 77
74 for (const resolution of resolutions) { 78 for (const resolution of resolutions) {
75 const reg = transcoded 79 const base = '#EXT-X-STREAM-INF:BANDWIDTH=\\d+,RESOLUTION=\\d+x' + resolution
76 ? new RegExp('#EXT-X-STREAM-INF:BANDWIDTH=\\d+,RESOLUTION=\\d+x' + resolution + ',(FRAME-RATE=\\d+,)?CODECS="avc1.64001f,mp4a.40.2"') 80
77 : new RegExp('#EXT-X-STREAM-INF:BANDWIDTH=\\d+,RESOLUTION=\\d+x' + resolution + '') 81 if (resolution === VideoResolution.H_NOVIDEO) {
78 82 expect(masterPlaylist).to.match(new RegExp(`${base},CODECS="mp4a.40.2"`))
79 expect(masterPlaylist).to.match(reg) 83 } else if (transcoded) {
84 expect(masterPlaylist).to.match(new RegExp(`${base},(FRAME-RATE=\\d+,)?CODECS="avc1.64001f,mp4a.40.2"`))
85 } else {
86 expect(masterPlaylist).to.match(new RegExp(`${base}`))
87 }
80 } 88 }
81 89
82 const playlistsLength = masterPlaylist.split('\n').filter(line => line.startsWith('#EXT-X-STREAM-INF:BANDWIDTH=')) 90 const playlistsLength = masterPlaylist.split('\n').filter(line => line.startsWith('#EXT-X-STREAM-INF:BANDWIDTH='))
@@ -89,14 +97,23 @@ async function completeCheckHlsPlaylist (options: {
89 hlsOnly: boolean 97 hlsOnly: boolean
90 98
91 resolutions?: number[] 99 resolutions?: number[]
92 objectStorageBaseUrl: string 100 objectStorageBaseUrl?: string
93}) { 101}) {
94 const { videoUUID, hlsOnly, objectStorageBaseUrl } = options 102 const { videoUUID, hlsOnly, objectStorageBaseUrl } = options
95 103
96 const resolutions = options.resolutions ?? [ 240, 360, 480, 720 ] 104 const resolutions = options.resolutions ?? [ 240, 360, 480, 720 ]
97 105
98 for (const server of options.servers) { 106 for (const server of options.servers) {
99 const videoDetails = await server.videos.get({ id: videoUUID }) 107 const videoDetails = await server.videos.getWithToken({ id: videoUUID })
108 const requiresAuth = videoDetails.privacy.id === VideoPrivacy.PRIVATE || videoDetails.privacy.id === VideoPrivacy.INTERNAL
109
110 const privatePath = requiresAuth
111 ? 'private/'
112 : ''
113 const token = requiresAuth
114 ? server.accessToken
115 : undefined
116
100 const baseUrl = `http://${videoDetails.account.host}` 117 const baseUrl = `http://${videoDetails.account.host}`
101 118
102 expect(videoDetails.streamingPlaylists).to.have.lengthOf(1) 119 expect(videoDetails.streamingPlaylists).to.have.lengthOf(1)
@@ -115,35 +132,55 @@ async function completeCheckHlsPlaylist (options: {
115 const file = hlsFiles.find(f => f.resolution.id === resolution) 132 const file = hlsFiles.find(f => f.resolution.id === resolution)
116 expect(file).to.not.be.undefined 133 expect(file).to.not.be.undefined
117 134
118 expect(file.magnetUri).to.have.lengthOf.above(2) 135 if (file.resolution.id === VideoResolution.H_NOVIDEO) {
119 expect(file.torrentUrl).to.match( 136 expect(file.resolution.label).to.equal('Audio')
120 new RegExp(`${server.url}/lazy-static/torrents/${uuidRegex}-${file.resolution.id}-hls.torrent`)
121 )
122
123 if (objectStorageBaseUrl) {
124 expectStartWith(file.fileUrl, objectStorageBaseUrl)
125 } else { 137 } else {
126 expect(file.fileUrl).to.match( 138 expect(file.resolution.label).to.equal(resolution + 'p')
127 new RegExp(`${baseUrl}/static/streaming-playlists/hls/${videoDetails.uuid}/${uuidRegex}-${file.resolution.id}-fragmented.mp4`)
128 )
129 } 139 }
130 140
131 expect(file.resolution.label).to.equal(resolution + 'p') 141 expect(file.magnetUri).to.have.lengthOf.above(2)
132 142 await checkWebTorrentWorks(file.magnetUri)
133 await makeRawRequest({ url: file.torrentUrl, expectedStatus: HttpStatusCode.OK_200 }) 143
134 await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) 144 {
145 const nameReg = `${uuidRegex}-${file.resolution.id}`
146
147 expect(file.torrentUrl).to.match(new RegExp(`${server.url}/lazy-static/torrents/${nameReg}-hls.torrent`))
148
149 if (objectStorageBaseUrl && requiresAuth) {
150 // eslint-disable-next-line max-len
151 expect(file.fileUrl).to.match(new RegExp(`${server.url}/object-storage-proxy/streaming-playlists/hls/${privatePath}${videoDetails.uuid}/${nameReg}-fragmented.mp4`))
152 } else if (objectStorageBaseUrl) {
153 expectStartWith(file.fileUrl, objectStorageBaseUrl)
154 } else {
155 expect(file.fileUrl).to.match(
156 new RegExp(`${baseUrl}/static/streaming-playlists/hls/${privatePath}${videoDetails.uuid}/${nameReg}-fragmented.mp4`)
157 )
158 }
159 }
135 160
136 const torrent = await webtorrentAdd(file.magnetUri, true) 161 {
137 expect(torrent.files).to.be.an('array') 162 await Promise.all([
138 expect(torrent.files.length).to.equal(1) 163 makeRawRequest({ url: file.torrentUrl, token, expectedStatus: HttpStatusCode.OK_200 }),
139 expect(torrent.files[0].path).to.exist.and.to.not.equal('') 164 makeRawRequest({ url: file.torrentDownloadUrl, token, expectedStatus: HttpStatusCode.OK_200 }),
165 makeRawRequest({ url: file.metadataUrl, token, expectedStatus: HttpStatusCode.OK_200 }),
166 makeRawRequest({ url: file.fileUrl, token, expectedStatus: HttpStatusCode.OK_200 }),
167
168 makeRawRequest({
169 url: file.fileDownloadUrl,
170 token,
171 expectedStatus: objectStorageBaseUrl
172 ? HttpStatusCode.FOUND_302
173 : HttpStatusCode.OK_200
174 })
175 ])
176 }
140 } 177 }
141 178
142 // Check master playlist 179 // Check master playlist
143 { 180 {
144 await checkResolutionsInMasterPlaylist({ server, playlistUrl: hlsPlaylist.playlistUrl, resolutions }) 181 await checkResolutionsInMasterPlaylist({ server, token, playlistUrl: hlsPlaylist.playlistUrl, resolutions })
145 182
146 const masterPlaylist = await server.streamingPlaylists.get({ url: hlsPlaylist.playlistUrl }) 183 const masterPlaylist = await server.streamingPlaylists.get({ url: hlsPlaylist.playlistUrl, token })
147 184
148 let i = 0 185 let i = 0
149 for (const resolution of resolutions) { 186 for (const resolution of resolutions) {
@@ -163,11 +200,16 @@ async function completeCheckHlsPlaylist (options: {
163 const file = hlsFiles.find(f => f.resolution.id === resolution) 200 const file = hlsFiles.find(f => f.resolution.id === resolution)
164 const playlistName = removeFragmentedMP4Ext(basename(file.fileUrl)) + '.m3u8' 201 const playlistName = removeFragmentedMP4Ext(basename(file.fileUrl)) + '.m3u8'
165 202
166 const url = objectStorageBaseUrl 203 let url: string
167 ? `${objectStorageBaseUrl}hls/${videoUUID}/${playlistName}` 204 if (objectStorageBaseUrl && requiresAuth) {
168 : `${baseUrl}/static/streaming-playlists/hls/${videoUUID}/${playlistName}` 205 url = `${baseUrl}/object-storage-proxy/streaming-playlists/hls/${privatePath}${videoUUID}/${playlistName}`
206 } else if (objectStorageBaseUrl) {
207 url = `${objectStorageBaseUrl}hls/${videoUUID}/${playlistName}`
208 } else {
209 url = `${baseUrl}/static/streaming-playlists/hls/${privatePath}${videoUUID}/${playlistName}`
210 }
169 211
170 const subPlaylist = await server.streamingPlaylists.get({ url }) 212 const subPlaylist = await server.streamingPlaylists.get({ url, token })
171 213
172 expect(subPlaylist).to.match(new RegExp(`${uuidRegex}-${resolution}-fragmented.mp4`)) 214 expect(subPlaylist).to.match(new RegExp(`${uuidRegex}-${resolution}-fragmented.mp4`))
173 expect(subPlaylist).to.contain(basename(file.fileUrl)) 215 expect(subPlaylist).to.contain(basename(file.fileUrl))
@@ -175,13 +217,19 @@ async function completeCheckHlsPlaylist (options: {
175 } 217 }
176 218
177 { 219 {
178 const baseUrlAndPath = objectStorageBaseUrl 220 let baseUrlAndPath: string
179 ? objectStorageBaseUrl + 'hls/' + videoUUID 221 if (objectStorageBaseUrl && requiresAuth) {
180 : baseUrl + '/static/streaming-playlists/hls/' + videoUUID 222 baseUrlAndPath = `${baseUrl}/object-storage-proxy/streaming-playlists/hls/${privatePath}${videoUUID}`
223 } else if (objectStorageBaseUrl) {
224 baseUrlAndPath = `${objectStorageBaseUrl}hls/${videoUUID}`
225 } else {
226 baseUrlAndPath = `${baseUrl}/static/streaming-playlists/hls/${privatePath}${videoUUID}`
227 }
181 228
182 for (const resolution of resolutions) { 229 for (const resolution of resolutions) {
183 await checkSegmentHash({ 230 await checkSegmentHash({
184 server, 231 server,
232 token,
185 baseUrlPlaylist: baseUrlAndPath, 233 baseUrlPlaylist: baseUrlAndPath,
186 baseUrlSegment: baseUrlAndPath, 234 baseUrlSegment: baseUrlAndPath,
187 resolution, 235 resolution,