From 0845a529bcdb7a068b9d35e995013dca8b5e1d6d Mon Sep 17 00:00:00 2001 From: Marco Vermeulen Date: Thu, 16 Jan 2025 21:37:32 +0000 Subject: [PATCH] Allow GET by candidate and platform --- src/main/kotlin/io/sdkman/plugins/Routing.kt | 14 +- .../io/sdkman/repos/VersionsRepository.kt | 20 ++- src/test/kotlin/io/sdkman/ApiSpec.kt | 133 ++++++++++++++++-- 3 files changed, 154 insertions(+), 13 deletions(-) diff --git a/src/main/kotlin/io/sdkman/plugins/Routing.kt b/src/main/kotlin/io/sdkman/plugins/Routing.kt index 1d555b7..847910b 100644 --- a/src/main/kotlin/io/sdkman/plugins/Routing.kt +++ b/src/main/kotlin/io/sdkman/plugins/Routing.kt @@ -1,6 +1,7 @@ package io.sdkman.plugins import arrow.core.getOrElse +import arrow.core.raise.option import arrow.core.toOption import io.ktor.http.* import io.ktor.server.application.* @@ -8,8 +9,9 @@ import io.ktor.server.auth.* import io.ktor.server.request.* import io.ktor.server.response.* import io.ktor.server.routing.* -import io.sdkman.domain.Version +import io.sdkman.domain.Platform import io.sdkman.domain.UniqueVersion +import io.sdkman.domain.Version import io.sdkman.repos.VersionsRepository fun Application.configureRouting(repo: VersionsRepository) { @@ -22,6 +24,16 @@ fun Application.configureRouting(repo: VersionsRepository) { throw IllegalArgumentException("Candidate not found") } } + get("/versions/{candidate}/{platform}") { + option { + val candidate = call.parameters["candidate"].toOption().bind() + val platform = call.parameters["platform"].toOption().bind() + val versions = repo.read(candidate, Platform.entries.first { it.slug == platform }.name) + call.respond(HttpStatusCode.OK, versions) + }.getOrElse { + throw IllegalArgumentException("Candidate or platform not found") + } + } authenticate("auth-basic") { post("/versions") { call.receive() diff --git a/src/main/kotlin/io/sdkman/repos/VersionsRepository.kt b/src/main/kotlin/io/sdkman/repos/VersionsRepository.kt index 32fb7a6..c8efce9 100644 --- a/src/main/kotlin/io/sdkman/repos/VersionsRepository.kt +++ b/src/main/kotlin/io/sdkman/repos/VersionsRepository.kt @@ -1,8 +1,8 @@ package io.sdkman.repos import arrow.core.toOption -import io.sdkman.domain.Version import io.sdkman.domain.UniqueVersion +import io.sdkman.domain.Version import kotlinx.coroutines.Dispatchers import org.jetbrains.exposed.dao.id.IntIdTable import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq @@ -49,6 +49,24 @@ class VersionsRepository { .sortedWith(compareBy({ it.candidate }, { it.version }, { it.vendor }, { it.platform })) } + suspend fun read(candidate: String, platform: String): List = dbQuery { + Versions.select { (Versions.candidate eq candidate) and (Versions.platform eq platform) } + .map { + Version( + candidate = it[Versions.candidate], + version = it[Versions.version], + vendor = it[Versions.vendor], + platform = it[Versions.platform], + url = it[Versions.url], + visible = it[Versions.visible], + md5sum = it[Versions.md5sum].toOption(), + sha256sum = it[Versions.sha256sum].toOption(), + sha512sum = it[Versions.sha512sum].toOption(), + ) + } + .sortedWith(compareBy({ it.candidate }, { it.version }, { it.vendor }, { it.platform })) + } + fun create(cv: Version): InsertStatement = transaction { Versions.insert { it[candidate] = cv.candidate diff --git a/src/test/kotlin/io/sdkman/ApiSpec.kt b/src/test/kotlin/io/sdkman/ApiSpec.kt index a4844da..b4b15be 100644 --- a/src/test/kotlin/io/sdkman/ApiSpec.kt +++ b/src/test/kotlin/io/sdkman/ApiSpec.kt @@ -8,8 +8,8 @@ import io.ktor.client.request.* import io.ktor.client.statement.* import io.ktor.http.* import io.ktor.http.HttpHeaders.Authorization -import io.sdkman.domain.Version import io.sdkman.domain.UniqueVersion +import io.sdkman.domain.Version import io.sdkman.support.* import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonArray @@ -28,24 +28,135 @@ class ApiSpec : ShouldSpec({ url = "https://java-17.0.1-tem", visible = true ) + val java21linuxArm64 = Version( + candidate = "java", + version = "21.0.1", + vendor = "tem", + platform = "LINUX_ARM64", + url = "https://java-21.0.1-tem", + visible = true + ) val java17linuxX64 = Version( candidate = "java", version = "17.0.1", vendor = "tem", - platform = "LINUX_X64", - url = "https://java-17.0.1-tem-", + platform = "LINUX_64", + url = "https://java-17.0.1-tem", + visible = true + ) + val java21linuxX64 = Version( + candidate = "java", + version = "21.0.1", + vendor = "tem", + platform = "LINUX_64", + url = "https://java-21.0.1-tem", visible = true ) withCleanDatabase { - insertVersions(java17linuxArm64, java17linuxX64) + insertVersions(java17linuxArm64, java21linuxArm64, java17linuxX64, java21linuxX64) withTestApplication { client.get("/versions/java").apply { + status shouldBe HttpStatusCode.OK + Json.decodeFromString(bodyAsText()) shouldBe JsonArray( + listOf( + java17linuxX64.toJson(), + java17linuxArm64.toJson(), + java21linuxX64.toJson(), + java21linuxArm64.toJson(), + ) + ) + } + } + } + } + + should("GET all versions for a universal candidate") { + val java17universal = Version( + candidate = "java", + version = "17.0.1", + vendor = "tem", + platform = "UNIVERSAL", + url = "https://java-17.0.1-tem", + visible = true + ) + val java21universal = Version( + candidate = "java", + version = "21.0.1", + vendor = "tem", + platform = "UNIVERSAL", + url = "https://java-21.0.1-tem", + visible = true + ) + + withCleanDatabase { + insertVersions(java17universal, java21universal) + withTestApplication { + client.get("/versions/java/universal").apply { + status shouldBe HttpStatusCode.OK + Json.decodeFromString(bodyAsText()) shouldBe JsonArray( + listOf( + java17universal.toJson(), + java21universal.toJson(), + ) + ) + } + } + } + } + + should("GET all versions for a multi-platform candidate") { + val java17linuxArm64 = Version( + candidate = "java", + version = "17.0.1", + vendor = "tem", + platform = "LINUX_ARM64", + url = "https://java-17.0.1-tem", + visible = true + ) + val java21linuxArm64 = Version( + candidate = "java", + version = "21.0.1", + vendor = "tem", + platform = "LINUX_ARM64", + url = "https://java-21.0.1-tem", + visible = true + ) + val java17linuxX64 = Version( + candidate = "java", + version = "17.0.1", + vendor = "tem", + platform = "LINUX_64", + url = "https://java-17.0.1-tem", + visible = true + ) + val java21linuxX64 = Version( + candidate = "java", + version = "21.0.1", + vendor = "tem", + platform = "LINUX_64", + url = "https://java-21.0.1-tem", + visible = true + ) + + withCleanDatabase { + insertVersions(java17linuxArm64, java21linuxArm64, java17linuxX64, java21linuxX64) + withTestApplication { + client.get("/versions/java/linuxarm64").apply { status shouldBe HttpStatusCode.OK Json.decodeFromString(bodyAsText()) shouldBe JsonArray( listOf( java17linuxArm64.toJson(), + java21linuxArm64.toJson(), + ) + ) + } + client.get("/versions/java/linuxx64").apply { + status shouldBe HttpStatusCode.OK + Json.decodeFromString(bodyAsText()) shouldBe JsonArray( + listOf( java17linuxX64.toJson(), + java21linuxX64.toJson(), ) ) } @@ -54,7 +165,7 @@ class ApiSpec : ShouldSpec({ } should("POST a new version for a candidate, platform and vendor") { - val expected = Version( + val version = Version( candidate = "java", version = "17.0.1", vendor = "tem", @@ -63,7 +174,7 @@ class ApiSpec : ShouldSpec({ visible = true, md5sum = "3bc0c1d7b4805831680ee5a8690ebb6e".some() ) - val requestBody = expected.toJsonString() + val requestBody = version.toJsonString() withCleanDatabase { withTestApplication { @@ -75,11 +186,11 @@ class ApiSpec : ShouldSpec({ response.status shouldBe HttpStatusCode.NoContent } selectVersion( - candidate = expected.candidate, - version = expected.version, - vendor = expected.vendor, - platform = expected.platform - ) shouldBe expected.some() + candidate = version.candidate, + version = version.version, + vendor = version.vendor, + platform = version.platform + ) shouldBe version.some() } }