Skip to content

Commit 2f5f5f0

Browse files
committed
test: cover audio-only hls rejection
1 parent 7901f19 commit 2f5f5f0

1 file changed

Lines changed: 84 additions & 0 deletions

File tree

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package dev.typetype.server
2+
3+
import dev.typetype.server.models.ExtractionResult
4+
import dev.typetype.server.models.ProxyResponse
5+
import dev.typetype.server.routes.audioOnlyContractRoutes
6+
import dev.typetype.server.routes.audioOnlySourceRoutes
7+
import dev.typetype.server.services.AudioOnlyMediaTokenService
8+
import dev.typetype.server.services.ProxyService
9+
import dev.typetype.server.services.StreamService
10+
import io.ktor.client.request.get
11+
import io.ktor.client.request.header
12+
import io.ktor.client.statement.bodyAsText
13+
import io.ktor.http.HttpHeaders
14+
import io.ktor.http.HttpStatusCode
15+
import io.ktor.serialization.kotlinx.json.json
16+
import io.ktor.server.application.install
17+
import io.ktor.server.plugins.contentnegotiation.ContentNegotiation
18+
import io.ktor.server.routing.routing
19+
import io.ktor.server.testing.testApplication
20+
import io.mockk.coEvery
21+
import io.mockk.mockk
22+
import org.junit.jupiter.api.Assertions.assertEquals
23+
import org.junit.jupiter.api.Assertions.assertTrue
24+
import org.junit.jupiter.api.Test
25+
import java.io.ByteArrayInputStream
26+
27+
class AudioOnlyProgressiveContractRoutesTest {
28+
private val streamService: StreamService = mockk()
29+
private val proxyService: ProxyService = mockk()
30+
private val tokenService = AudioOnlyMediaTokenService("test-secret")
31+
32+
@Test
33+
fun `GET audio-only rejects HLS manifest audio streams`() = testApplication {
34+
val hlsAudio = testAudioStream(url = HLS_URL, audioLocale = "en")
35+
coEvery { streamService.getStreamInfo(any()) } returns ExtractionResult.Success(
36+
testStreamResponse(audioStreams = listOf(hlsAudio))
37+
)
38+
installContractApp()
39+
40+
val response = client.get("/streams/audio-only?url=https://youtube.com/watch?v=test")
41+
42+
assertEquals(HttpStatusCode.UnprocessableEntity, response.status)
43+
assertTrue(response.bodyAsText().contains("No audio-only stream is available"))
44+
}
45+
46+
@Test
47+
fun `GET audio-only source rejects HLS upstream response`() = testApplication {
48+
coEvery { streamService.getStreamInfo(any()) } returns ExtractionResult.Success(testStreamResponse())
49+
coEvery { proxyService.pipe(any(), any(), any()) } returns ExtractionResult.Success(
50+
ProxyResponse(
51+
status = 206,
52+
contentType = "application/vnd.apple.mpegurl",
53+
contentLength = null,
54+
contentRange = null,
55+
acceptRanges = null,
56+
stream = ByteArrayInputStream("#EXTM3U".toByteArray()),
57+
close = {},
58+
)
59+
)
60+
installSourceApp()
61+
val token = tokenService.createToken(null, "https://youtube.com/watch?v=test", false, "en")
62+
63+
val response = client.get("/streams/audio-only/source?token=$token") {
64+
header(HttpHeaders.Range, "bytes=0-1023")
65+
}
66+
67+
assertEquals(HttpStatusCode.UnprocessableEntity, response.status)
68+
assertTrue(response.bodyAsText().contains("Audio-only source did not return progressive audio"))
69+
}
70+
71+
private fun io.ktor.server.testing.ApplicationTestBuilder.installContractApp(): Unit = application {
72+
install(ContentNegotiation) { json() }
73+
routing { audioOnlyContractRoutes(streamService, tokenService) }
74+
}
75+
76+
private fun io.ktor.server.testing.ApplicationTestBuilder.installSourceApp(): Unit = application {
77+
install(ContentNegotiation) { json() }
78+
routing { audioOnlySourceRoutes(streamService, proxyService, tokenService) }
79+
}
80+
81+
private companion object {
82+
const val HLS_URL = "https://manifest.googlevideo.com/api/manifest/hls/test"
83+
}
84+
}

0 commit comments

Comments
 (0)