CodeUseTelemetrySidecarStoreSmokeTest.kt
src/jvmMain/kotlin/afield/examples/CodeUseTelemetrySidecarStoreSmokeTest.kt · 171 lines
package afield.examples
import afield.app.diagnostics.CodeUseSemanticAnalyzeResult
import afield.app.diagnostics.CodeUseSemanticUseRow
import afield.app.diagnostics.CodeUseTelemetryService
import com.sun.net.httpserver.HttpExchange
import com.sun.net.httpserver.HttpServer
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import java.net.InetSocketAddress
import java.nio.charset.StandardCharsets
import java.nio.file.Files
import java.sql.DriverManager
import java.util.concurrent.atomic.AtomicInteger
object CodeUseTelemetrySidecarStoreSmokeTest
FIELD_TEST id: examples.code-use.telemetry-sidecar-store runner: jvm-main entrypoint: afield.examples.CodeUseTelemetrySidecarStoreSmokeTest tags: [smoke, code-use, telemetry, sidecar, sqlite] timeoutSec: 20 expect: exitCode: 0 stdoutContains: - "CodeUseTelemetrySidecarStoreSmokeTest ok"
object CodeUseTelemetrySidecarStoreSmokeTest {
private val json = Json { encodeDefaults = true }
fun main(args: Array<String>)
body — 140 lines, from line 31
@JvmStatic
fun main(args: Array<String>) {
val tempDir = Files.createTempDirectory("afield-code-use-sidecar-store")
val database = tempDir.resolve("field-code-use.sqlite")
val analyzeCalls = AtomicInteger(0)
val server = HttpServer.create(InetSocketAddress("127.0.0.1", 0), 0)
server.createContext("/health") { exchange ->
exchange.respondJson("""{"ok":true,"backend":"k2-standalone","workspaceRoot":"${System.getProperty("user.dir")}"}""")
}
server.createContext("/analyze") { exchange ->
analyzeCalls.incrementAndGet()
exchange.requestBody.use { it.readBytes() }
exchange.respondJson(
json.encodeToString(
CodeUseSemanticAnalyzeResult(
success = true,
backend = "k2-standalone",
message = "fake sidecar resolved one use",
sourceName = "SidecarStoreSmoke.kts",
resolvedUses = listOf(
CodeUseSemanticUseRow(
symbolName = "afield.FakeK2.hot",
callableId = "afield.FakeK2.hot",
kind = "fun",
packageName = "afield",
sourceFile = "src/jvmMain/kotlin/afield/FakeK2.kt",
line = 12,
useKind = "call",
snippetLine = 1,
snippetColumn = 1,
confidence = "k2-resolved",
evidence = "FakeK2.hot()"
)
)
)
)
)
}
server.start()
try {
System.setProperty("afield.codeUse.path", database.toString())
System.setProperty("afield.codeUse.semanticSidecar.url", "http://127.0.0.1:${server.address.port}")
val context = CodeUseTelemetryService.CodeUseContext(
document = "code-use-sidecar-smoke",
documentPath = tempDir.resolve("code-use-sidecar-smoke").toString(),
boxUid = "box-code-use-sidecar-smoke",
boxName = "Code Use Sidecar Smoke",
property = "code",
mode = "compile:user-code",
strand = "__main__"
)
val snippetId = CodeUseTelemetryService.newSnippetKey()
CodeUseTelemetryService.recordCompileResult(
snippetId = snippetId,
source = "FakeK2.hot()",
sourceName = "SidecarStoreSmoke.kts",
context = context,
success = true,
diagnostics = emptyList(),
elapsedMs = 0.1,
classpathHash = "sidecar-smoke"
)
val summary = waitForSummary {
it.enabled && it.compileEvents >= 1 && it.analyzerBackend == "k2-sidecar"
}
require(summary.analyzerBackend == "k2-sidecar") { "Store analyzer did not report sidecar backend: $summary" }
waitForK2Rows(database.toString(), snippetId)
val early = CodeUseTelemetryService.earlyDocumentSymbols("code-use-sidecar-smoke", earlyWindowMs = 60_000, limit = 10)
require(
early.any {
it.symbolName == "afield.FakeK2.hot" &&
it.confidence == "k2-resolved" &&
it.earlyUseCount == 1L
}
) {
"Early-document symbols should use persisted k2-resolved edges: $early"
}
require(analyzeCalls.get() >= 1) { "Fake sidecar was not called" }
println("CodeUseTelemetrySidecarStoreSmokeTest ok")
} finally {
server.stop(0)
}
}
private fun waitForSummary(predicate: (afield.app.diagnostics.CodeUseSummary) -> Boolean): afield.app.diagnostics.CodeUseSummary {
val deadline = System.currentTimeMillis() + 5_000
var latest = CodeUseTelemetryService.summary()
while (System.currentTimeMillis() < deadline) {
latest = CodeUseTelemetryService.summary()
if (predicate(latest)) return latest
Thread.sleep(50)
}
error("Timed out waiting for code-use telemetry summary: $latest")
}
private fun waitForK2Rows(databasePath: String, snippetId: String) {
val deadline = System.currentTimeMillis() + 5_000
while (System.currentTimeMillis() < deadline) {
val rows = DriverManager.getConnection("jdbc:sqlite:$databasePath").use { conn ->
conn.prepareStatement(
"""
SELECT sy.fq_name, sy.callable_id, su.confidence
FROM symbol_uses su
JOIN symbols sy ON sy.id = su.symbol_id
WHERE su.snippet_id = ?
""".trimIndent()
).use { ps ->
ps.setString(1, snippetId)
ps.executeQuery().use { rs ->
buildList {
while (rs.next()) {
add(
Triple(
rs.getString("fq_name").orEmpty(),
rs.getString("callable_id").orEmpty(),
rs.getString("confidence").orEmpty()
)
)
}
}
}
}
}
if (rows.any { it.first == "afield.FakeK2.hot" && it.second == "afield.FakeK2.hot" && it.third == "k2-resolved" }) {
return
}
Thread.sleep(50)
}
error("Timed out waiting for k2-resolved symbol_use rows")
}
private fun HttpExchange.respondJson(body: String) {
val bytes = body.toByteArray(StandardCharsets.UTF_8)
responseHeaders.add("Content-Type", "application/json")
sendResponseHeaders(200, bytes.size.toLong())
responseBody.use { it.write(bytes) }
}
}