This commit is contained in:
Martino Ferrari
2026-06-24 01:39:15 +02:00
parent 11120bedca
commit c0f7e662be
76 changed files with 4368 additions and 210 deletions
+91
View File
@@ -0,0 +1,91 @@
package audit
import (
"log/slog"
"path/filepath"
"testing"
"time"
)
// TestNopRecorder covers the disabled-auditing no-op implementation.
func TestNopRecorder(t *testing.T) {
rec := Nop()
rec.Record(Event{Action: "x"}) // must not panic
got, err := rec.Query(Filter{})
if err != nil {
t.Fatalf("Nop Query: %v", err)
}
if len(got) != 0 {
t.Errorf("Nop Query returned %d events, want 0", len(got))
}
if err := rec.Close(); err != nil {
t.Errorf("Nop Close: %v", err)
}
}
// TestQueryFilters covers the End, DS, and Signal (LIKE) filter branches plus
// the default-outcome and zero-time stamping in Record.
func TestQueryFilters(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()
// Anchor base in the past so the zero-Time 'c' record (stamped with now)
// sorts after a/b and stays out of the End window below.
base := time.Now().Add(-time.Hour)
rec.Record(Event{Time: base, Actor: "a", ActorType: ActorUser, Action: "signal.write", DS: "epics", Signal: "PV:TEMP"})
rec.Record(Event{Time: base.Add(time.Second), Actor: "b", ActorType: ActorUser, Action: "signal.write", DS: "synthetic", Signal: "PV:FLOW"})
// Zero Time and empty Outcome exercise the defaulting branches in Record.
rec.Record(Event{Actor: "c", ActorType: ActorUser, Action: "interface.update"})
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()
// End filter: only events at or before base.
upTo, err := rec.Query(Filter{End: base.Add(500 * time.Millisecond)})
if err != nil {
t.Fatal("Query end:", err)
}
if len(upTo) != 1 || upTo[0].Actor != "a" {
t.Errorf("end filter = %+v, want one 'a' event", upTo)
}
// DS filter.
byDS, err := rec.Query(Filter{DS: "synthetic"})
if err != nil {
t.Fatal("Query ds:", err)
}
if len(byDS) != 1 || byDS[0].Signal != "PV:FLOW" {
t.Errorf("ds filter = %+v, want one PV:FLOW event", byDS)
}
// Signal LIKE filter (substring match).
bySignal, err := rec.Query(Filter{Signal: "TEMP"})
if err != nil {
t.Fatal("Query signal:", err)
}
if len(bySignal) != 1 || bySignal[0].DS != "epics" {
t.Errorf("signal filter = %+v, want one epics event", bySignal)
}
// The zero-time/empty-outcome record was persisted with a default outcome.
def, err := rec.Query(Filter{Actor: "c"})
if err != nil {
t.Fatal("Query actor c:", err)
}
if len(def) != 1 || def[0].Outcome != OutcomeOK {
t.Errorf("defaulted record = %+v, want one event with outcome ok", def)
}
if def[0].Time.IsZero() {
t.Error("zero Time should have been stamped with now")
}
}