package audit import ( "log/slog" "path/filepath" "testing" "time" ) func TestSQLiteRoundTrip(t *testing.T) { path := filepath.Join(t.TempDir(), "audit.db") rec, err := NewSQLite(path, slog.Default()) if err != nil { t.Fatal("NewSQLite:", err) } defer rec.Close() base := time.Now() rec.Record(Event{Time: base, Actor: "alice", ActorType: ActorUser, Action: "signal.write", DS: "epics", Signal: "PV:A", Value: "1.5"}) rec.Record(Event{Time: base.Add(time.Second), Actor: "flow1", ActorType: ActorSystem, Action: "signal.write", DS: "epics", Signal: "PV:B", Value: "0"}) rec.Record(Event{Time: base.Add(2 * time.Second), Actor: "bob", ActorType: ActorUser, Action: "interface.update", Detail: "panel-1", Outcome: OutcomeError, Error: "denied"}) // Flush the async writer. if err := rec.Close(); err != nil { t.Fatal("Close:", err) } rec, err = NewSQLite(path, slog.Default()) if err != nil { t.Fatal("reopen:", err) } defer rec.Close() all, err := rec.Query(Filter{}) if err != nil { t.Fatal("Query:", err) } if len(all) != 3 { t.Fatalf("got %d events, want 3", len(all)) } // Newest first. if all[0].Actor != "bob" { t.Errorf("first actor = %q, want bob", all[0].Actor) } byActor, err := rec.Query(Filter{Actor: "alice"}) if err != nil { t.Fatal("Query actor:", err) } if len(byActor) != 1 || byActor[0].Signal != "PV:A" { t.Errorf("actor filter = %+v, want one PV:A event", byActor) } byAction, err := rec.Query(Filter{Action: "signal.write"}) if err != nil { t.Fatal("Query action:", err) } if len(byAction) != 2 { t.Errorf("action filter returned %d, want 2", len(byAction)) } since, err := rec.Query(Filter{Start: base.Add(1500 * time.Millisecond)}) if err != nil { t.Fatal("Query start:", err) } if len(since) != 1 || since[0].Actor != "bob" { t.Errorf("time filter = %+v, want one bob event", since) } }