108 lines
3.9 KiB
Go
108 lines
3.9 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
"log/slog"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// newTestBot builds a Bot with just the fields the telemetry path needs — no network,
|
|
// so it sidesteps NewBot's identity check.
|
|
func newTestBot(st *Store, cfg *Config) *Bot {
|
|
return &Bot{cfg: cfg, st: st, log: slog.New(slog.NewTextHandler(io.Discard, nil)), promptVersion: "testv"}
|
|
}
|
|
|
|
func requestLogCount(t *testing.T, st *Store) int {
|
|
t.Helper()
|
|
ctx, cancel := opContext()
|
|
defer cancel()
|
|
var n int
|
|
if err := st.pool.QueryRow(ctx, `SELECT count(*) FROM request_log`).Scan(&n); err != nil {
|
|
t.Fatalf("count: %v", err)
|
|
}
|
|
return n
|
|
}
|
|
|
|
// TestRecordSkipWritesRow proves the early-return telemetry path actually records a
|
|
// row (route=none + the skip reason) when TELEMETRY_ENABLED is on. The write is async,
|
|
// so poll briefly.
|
|
func TestRecordSkipWritesRow(t *testing.T) {
|
|
st := openTestStore(t)
|
|
defer st.Close()
|
|
b := newTestBot(st, &Config{TelemetryEnabled: true})
|
|
|
|
ev := &Event{EventID: "$skip-1", RoomID: "!r:vojo.chat", Sender: "@u:vojo.chat"}
|
|
b.recordSkip(context.Background(), ev, degradeMedia)
|
|
|
|
deadline := time.Now().Add(2 * time.Second)
|
|
for requestLogCount(t, st) == 0 && time.Now().Before(deadline) {
|
|
time.Sleep(20 * time.Millisecond)
|
|
}
|
|
if n := requestLogCount(t, st); n != 1 {
|
|
t.Fatalf("telemetry rows = %d, want 1", n)
|
|
}
|
|
ctx, cancel := opContext()
|
|
defer cancel()
|
|
var route, degraded string
|
|
if err := st.pool.QueryRow(ctx,
|
|
`SELECT route, degraded FROM request_log WHERE id = $1`, ev.EventID).Scan(&route, °raded); err != nil {
|
|
t.Fatalf("read: %v", err)
|
|
}
|
|
if route != routeNone || degraded != degradeMedia {
|
|
t.Fatalf("row = (%q,%q), want (none, media)", route, degraded)
|
|
}
|
|
}
|
|
|
|
// TestTelemetryStripsTextWhenStoreTextOff proves the content gate: with TELEMETRY_ENABLED
|
|
// on but TELEMETRY_STORE_TEXT off, the user query, the model-authored search query, and the
|
|
// answer are all NULL — only metadata signals land. The boolean signals are still recorded.
|
|
func TestTelemetryStripsTextWhenStoreTextOff(t *testing.T) {
|
|
st := openTestStore(t)
|
|
defer st.Close()
|
|
b := newTestBot(st, &Config{TelemetryEnabled: true, TelemetryStoreText: false})
|
|
|
|
b.recordTelemetry(context.Background(), RequestLog{
|
|
ID: "$strip-1", Route: routeWebThenGrok, RouterSource: "classifier",
|
|
QueryText: "secret query", SearchQuery: "secret search", AnswerText: "secret answer",
|
|
NeedsWeb: true, WebDecidedBy: "classifier_needs_web", OK: true,
|
|
})
|
|
|
|
deadline := time.Now().Add(2 * time.Second)
|
|
for requestLogCount(t, st) == 0 && time.Now().Before(deadline) {
|
|
time.Sleep(20 * time.Millisecond)
|
|
}
|
|
ctx, cancel := opContext()
|
|
defer cancel()
|
|
var qt, sq, ans, decidedBy *string
|
|
var needsWeb bool
|
|
if err := st.pool.QueryRow(ctx,
|
|
`SELECT query_text, search_query, answer_text, web_decided_by, needs_web FROM request_log WHERE id=$1`,
|
|
"$strip-1").Scan(&qt, &sq, &ans, &decidedBy, &needsWeb); err != nil {
|
|
t.Fatalf("read: %v", err)
|
|
}
|
|
if qt != nil || sq != nil || ans != nil {
|
|
t.Fatalf("text columns must be NULL when store-text off: qt=%v sq=%v ans=%v", qt, sq, ans)
|
|
}
|
|
// Metadata is still recorded (it is not content).
|
|
if !needsWeb || decidedBy == nil || *decidedBy != "classifier_needs_web" {
|
|
t.Fatalf("metadata signals must survive: needsWeb=%v decidedBy=%v", needsWeb, decidedBy)
|
|
}
|
|
}
|
|
|
|
// TestTelemetryDisabledWritesNothing proves the default (TELEMETRY_ENABLED off) adds
|
|
// no write path — strict "cascade-off == today".
|
|
func TestTelemetryDisabledWritesNothing(t *testing.T) {
|
|
st := openTestStore(t)
|
|
defer st.Close()
|
|
b := newTestBot(st, &Config{TelemetryEnabled: false})
|
|
|
|
b.recordSkip(context.Background(), &Event{EventID: "$skip-2", RoomID: "!r:vojo.chat", Sender: "@u:vojo.chat"}, degradeMedia)
|
|
|
|
// Give any (incorrect) async write time to land, then assert nothing was written.
|
|
time.Sleep(200 * time.Millisecond)
|
|
if n := requestLogCount(t, st); n != 0 {
|
|
t.Fatalf("telemetry rows = %d, want 0 (TELEMETRY_ENABLED off)", n)
|
|
}
|
|
}
|