ci / go (push) Waiting to run
ci / go-db (agent) (push) Waiting to run
ci / go-db (config) (push) Waiting to run
ci / go-db (db) (push) Waiting to run
ci / go-db (evidence) (push) Waiting to run
ci / go-db (llmrec) (push) Waiting to run
ci / go-db (server) (push) Waiting to run
web / web (push) Waiting to run
docs / links (push) Canceled after 0s
detections / detections (push) Canceled after 0s
63 lines
2.0 KiB
Go
63 lines
2.0 KiB
Go
package db
|
|
|
|
import (
|
|
"testing"
|
|
)
|
|
|
|
// The raw-body columns were added after release, so existing installs only get
|
|
// them through llmRecordsMigrate. This runs the real migration against the dev
|
|
// PG on a table stripped back to its pre-upgrade shape, inside a transaction
|
|
// that is always rolled back — PG does transactional DDL, so nothing persists.
|
|
func TestLLMRecordsMigrateAddsRawColumnsToOldTable(t *testing.T) {
|
|
d, err := Open(testDSN(t))
|
|
if err != nil {
|
|
t.Skipf("postgres unavailable (%v) — skipping", err)
|
|
}
|
|
defer d.Close()
|
|
if err := d.EnsureLLMRecordsTable(); err != nil {
|
|
t.Fatalf("ensure: %v", err)
|
|
}
|
|
|
|
tx, err := d.Begin()
|
|
if err != nil {
|
|
t.Fatalf("begin: %v", err)
|
|
}
|
|
defer tx.Rollback() //nolint:errcheck // the test never commits
|
|
|
|
// Roll the table back to how a pre-upgrade install looks.
|
|
if _, err := tx.Exec(`ALTER TABLE llm_records DROP COLUMN IF EXISTS raw_request, DROP COLUMN IF EXISTS raw_response`); err != nil {
|
|
t.Fatalf("simulate old table: %v", err)
|
|
}
|
|
if _, err := tx.Exec(llmRecordsMigrate); err != nil {
|
|
t.Fatalf("migrate: %v", err)
|
|
}
|
|
|
|
for _, col := range []string{"raw_request", "raw_response"} {
|
|
var n int
|
|
if err := tx.QueryRow(
|
|
`SELECT count(*) FROM information_schema.columns
|
|
WHERE table_name='llm_records' AND column_name=$1`, col).Scan(&n); err != nil {
|
|
t.Fatalf("inspect %s: %v", col, err)
|
|
}
|
|
if n != 1 {
|
|
t.Errorf("column %s missing after migrate", col)
|
|
}
|
|
}
|
|
|
|
// Re-running must stay a no-op (the migration runs on every startup).
|
|
if _, err := tx.Exec(llmRecordsMigrate); err != nil {
|
|
t.Fatalf("migrate is not idempotent: %v", err)
|
|
}
|
|
|
|
// An insert carrying raw bodies must round-trip through the migrated table.
|
|
var got string
|
|
if err := tx.QueryRow(
|
|
`INSERT INTO llm_records(model, raw_request, raw_response) VALUES ('m','{"a":1}','data: x')
|
|
RETURNING raw_response`).Scan(&got); err != nil {
|
|
t.Fatalf("insert into migrated table: %v", err)
|
|
}
|
|
if got != "data: x" {
|
|
t.Errorf("raw_response=%q want %q", got, "data: x")
|
|
}
|
|
}
|