Files
felhom.eu/hub/internal/store/r1346_speed_test.go
T

124 lines
5.1 KiB
Go

package store
import (
"bytes"
"log"
"strings"
"testing"
"time"
)
// R-1346 (2026-10-30): the statements the measurement named read whole tables on the hub's network disk — in the pod,
// with 256 MiB for a 570 MB database, nearly every page is a disk read. Each is pinned to the plan that reads only what
// it needs. A plan is the mechanism; the consequence was measured on a copy of the live database (pages read, before
// → after): the vouch's fleet check 35 623 → 90, the OS alarm's agent versions 38 570 → 118, the night prune 30 097 →
// 1 013 (read INSIDE its write lock), the apps page 15 404 → 1 437. RED-PROOF: each seen failing before its index /
// hint existed.
func planOf(t *testing.T, s *Store, query string, args ...any) string {
t.Helper()
rows, err := s.db.Query("EXPLAIN QUERY PLAN "+query, args...)
if err != nil {
t.Fatalf("explain %q: %v", query, err)
}
defer rows.Close()
var out []string
for rows.Next() {
var id, parent, notused int
var detail string
if err := rows.Scan(&id, &parent, &notused, &detail); err != nil {
t.Fatal(err)
}
out = append(out, detail)
}
return strings.Join(out, " | ")
}
func TestR1346_HeavyStatementsUseTheirIndex(t *testing.T) {
s := newTestStore(t)
cutoff := "2026-08-01 00:00:00"
for _, tc := range []struct {
name, query, want string
args []any
}{
{"the vouch's fleet check (NewestReportedControllerVersion)", queryNewestControllerVersion, "COVERING INDEX idx_reports_controller_version", nil},
{"the OS alarm's agent versions (HostAgentVersionsSeen)", queryHostAgentVersionsSeen, "COVERING INDEX idx_host_reports_agent_version", []any{"h1"}},
{"the prune of reports", queryPruneReports, "INDEX idx_reports_received", []any{cutoff}},
{"the prune of host reports", queryPruneHostReports, "INDEX idx_host_reports_received", []any{cutoff}},
{"the apps page (GetFleetAppSummary)", queryFleetAppSummary, "INDEX idx_app_telemetry_prune", []any{time.Now()}},
} {
plan := planOf(t, s, tc.query, tc.args...)
if !strings.Contains(plan, tc.want) {
t.Errorf("%s: plan %q — want %q (a whole-table read on the network disk)", tc.name, plan, tc.want)
}
}
}
// The behaviour around the plans is unchanged: the newest valid version wins (an rc never does), the prune still
// removes exactly the old rows, the manifest still round-trips.
func TestR1346_BehaviourUnchanged(t *testing.T) {
s := newTestStore(t)
for _, v := range []string{"0.340.0", "0.349.0", "0.350.0-rc.1", "", "0.348.2"} {
if _, err := s.db.Exec(`INSERT INTO reports (customer_id, report_json, controller_version) VALUES ('c1', '{}', ?)`, v); err != nil {
t.Fatal(err)
}
}
if got := s.NewestReportedControllerVersion(); got != "v0.349.0" && got != "0.349.0" {
t.Fatalf("newest = %q, want 0.349.0", got)
}
if _, err := s.db.Exec(`INSERT INTO reports (customer_id, report_json, received_at) VALUES ('c1', '{}', '2020-01-01 00:00:00')`); err != nil {
t.Fatal(err)
}
if _, err := s.db.Exec(`INSERT INTO host_reports (host_id, customer_id, report_json, received_at, agent_version) VALUES ('h1', 'c1', '{}', '2020-01-01 00:00:00', '0.100.0'), ('h1', 'c1', '{}', datetime('now'), '0.170.0')`); err != nil {
t.Fatal(err)
}
seen, err := s.HostAgentVersionsSeen("h1")
if err != nil || len(seen) != 2 {
t.Fatalf("agent versions seen = %v, %v", seen, err)
}
n, err := s.Prune(90)
if err != nil || n != 2 {
t.Fatalf("prune removed %d (%v), want the 2 old rows", n, err)
}
m := ArtifactManifest{AgentVersion: "0.171.0", AgentSHA256: "aa", GoldenVersion: "0.349.0", GoldenSHA256: "bb", MinAgent: "0.158.1", WrapperSHA256: "cc", BundleSHA256: "dd"}
if err := s.SetArtifactManifest(m); err != nil {
t.Fatal(err)
}
if got := s.GetArtifactManifest(); got != m {
t.Fatalf("manifest round trip: %+v, want %+v", got, m)
}
}
// The slow-statement line names the statement — and never the values bound to it (they can be customer data).
func TestTimedDriver_ASlowStatementIsNamedNeverItsValues(t *testing.T) {
s := newTestStore(t)
var buf bytes.Buffer
old := statementLogger.Load()
statementLogger.Store(log.New(&buf, "", 0))
SetSlowStatementThreshold(0)
defer func() { statementLogger.Store(old); SetSlowStatementThreshold(time.Second) }()
if _, err := s.db.Exec(`INSERT INTO hub_settings (key, value, updated_at) VALUES (?, ?, datetime('now'))`, "r1346-key", "SECRET-VALUE-42"); err != nil {
t.Fatal(err)
}
var v string
if err := s.db.QueryRow(`SELECT value FROM hub_settings WHERE key = ?`, "r1346-key").Scan(&v); err != nil || v != "SECRET-VALUE-42" {
t.Fatalf("read back %q, %v", v, err)
}
out := buf.String()
if !strings.Contains(out, "slow statement:") || !strings.Contains(out, "INSERT INTO hub_settings") ||
!strings.Contains(out, "SELECT value FROM hub_settings WHERE key = ?") {
t.Fatalf("the statements are not named:\n%s", out)
}
if strings.Contains(out, "SECRET-VALUE-42") || strings.Contains(out, "r1346-key") {
t.Fatalf("a bound VALUE reached the log:\n%s", out)
}
// Under the threshold: silent.
buf.Reset()
SetSlowStatementThreshold(time.Hour)
_ = s.db.QueryRow(`SELECT 1`).Scan(&v)
if buf.Len() != 0 {
t.Fatalf("a fast statement was logged: %s", buf.String())
}
}