Files
OSGAccountServer/src/test/kotlin/com/osglab/account/config/SmokeDeploymentTest.kt
T
Rocky 10ba4f0a0c
CI / verify (push) Has been cancelled
CI / publish (push) Has been cancelled
Fix production migration privilege compatibility
Rescope OOBE claims with permitted ALTER operations and make deployment smoke validation require every migration through V28.
2026-08-22 16:44:24 +08:00

96 lines
4.5 KiB
Kotlin

package com.osglab.account.config
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.collections.shouldContainExactly
import io.kotest.matchers.shouldBe
import io.kotest.matchers.string.shouldContain
import io.kotest.matchers.string.shouldNotContain
import java.nio.file.Files
import java.nio.file.Path
class SmokeDeploymentTest : FunSpec({
val root = Path.of(System.getProperty("user.dir"))
test("smoke Compose builds locally and publishes only loopback ports") {
val compose = root.read("compose.smoke.yaml")
compose shouldContain "image: mysql:8.4"
compose shouldContain "build:"
compose shouldContain "dockerfile: Dockerfile"
compose shouldContain "127.0.0.1:\${SMOKE_APP_PORT"
compose shouldContain "internal: true"
compose shouldContain "network_mode: none"
compose shouldContain "read_only: true"
compose shouldContain "no-new-privileges:true"
compose shouldNotContain "SMOKE_MYSQL_PORT"
compose shouldNotContain "0.0.0.0:"
compose shouldNotContain "ghcr.io/"
}
test("smoke runner isolates secrets providers and cleanup") {
val runner = root.read("deploy/smoke-local.sh")
runner shouldContain "set -euo pipefail"
runner shouldContain "mktemp -d"
runner shouldContain "trap cleanup EXIT INT TERM"
runner shouldContain "down --volumes --remove-orphans --rmi local"
runner shouldContain "APPLE_JWKS_URL=http://127.0.0.1:9/"
runner shouldContain "VOLCENGINE_ASR_ENDPOINT=ws://127.0.0.1:9/"
runner shouldContain "DEEPSEEK_ENDPOINT=http://127.0.0.1:9/"
runner shouldContain "Flyway history was not exactly successful V1-V28"
runner shouldContain "default referral rewards were not 1000 credits for both accounts"
runner shouldContain "active smaller credit rates did not match the V10 contract"
runner shouldContain "first ledger page omitted nextCursor"
runner shouldContain "DELETE FROM admin_sessions WHERE expires_at < UTC_TIMESTAMP()"
runner shouldContain "UPDATE storekit_credit_purchases SET credits_granted = credits_granted"
runner shouldContain "DELETE FROM storekit_credit_purchases WHERE 1 = 0"
runner shouldNotContain "appleid.apple.com"
runner shouldNotContain "api.deepseek.com"
runner shouldNotContain "openspeech.bytedance.com"
}
test("runtime grants cover every migrated table without mutable history privileges") {
val grants = root.read("deploy/smoke/runtime-grants.sql")
val migrationTables = Files.list(root.resolve("src/main/resources/db/migration")).use { paths ->
paths.filter { MIGRATION_FILE.matches(it.fileName.toString()) }
.flatMap { migration ->
CREATE_TABLE.findAll(Files.readString(migration))
.map { it.groupValues[1] }
.toList()
.stream()
}
.toList()
}
.toSet()
val grantedTables = GRANTED_TABLE.findAll(grants)
.map { it.groupValues[1] }
.toSet()
grantedTables.sorted() shouldContainExactly migrationTables.sorted()
grants shouldContain "GRANT INSERT, UPDATE, DELETE ON osg_account_smoke.admin_sessions"
grants shouldContain
"GRANT INSERT, UPDATE, DELETE ON osg_account_smoke.gateway_complimentary_requests"
grants shouldNotContain "UPDATE ON osg_account_smoke.credit_ledger"
grants shouldNotContain "DELETE ON osg_account_smoke.credit_ledger"
grants shouldNotContain "UPDATE ON osg_account_smoke.admin_audit_log"
grants shouldNotContain "DELETE ON osg_account_smoke.admin_audit_log"
grants shouldNotContain "UPDATE ON osg_account_smoke.admin_credit_grants"
grants shouldNotContain "DELETE ON osg_account_smoke.admin_credit_grants"
}
test("fixture forces the ledger cursor boundary") {
val fixture = root.read("deploy/smoke/fixture.sql")
fixture shouldContain "WHERE value < 101"
fixture shouldContain "INSERT INTO credit_ledger"
fixture shouldNotContain "osg_account"
}
})
private fun Path.read(relativePath: String): String =
Files.readString(resolve(relativePath))
private val CREATE_TABLE = Regex("""CREATE TABLE\s+([a-z0-9_]+)""", RegexOption.IGNORE_CASE)
private val GRANTED_TABLE = Regex("""ON osg_account_smoke\.([a-z0-9_]+)""")
private val MIGRATION_FILE = Regex("""V\d+__.+\.sql""")