b194a9621d
executus CI / test (pull_request) Successful in 1m41s
db.Audit() satisfies audit.Storage (all 17 methods) over SQLite: one indexed row per run (+ a JSON inputs blob), one row per log event. Filter/list/walk queries are indexed on the columns they filter (skill_id, caller_id, parent_run_id, started_at); WalkParentChain follows parent_run_id with a seen-set guard; LastRunBySkills is a grouped MAX. Test covers run start/finish round-trip (inputs map + token roll-up), log append + ordered read, parent/child + ancestor-chain walks, caller listing, TopLevelOnly filter, and the last-run-per-skill map. contrib/store now backs ALL four store seams — budget + persona + skill + audit — so a host gets turnkey durable persistence (run history, budgets, agents, skills) with zero store code. Core go.sum still has 0 sqlite refs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
68 lines
2.2 KiB
Go
68 lines
2.2 KiB
Go
package store
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"gitea.stevedudenhoeffer.com/steve/executus/audit"
|
|
)
|
|
|
|
func TestSQLiteAuditStore(t *testing.T) {
|
|
ctx := context.Background()
|
|
db, err := Open(":memory:")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer db.Close()
|
|
st := db.Audit()
|
|
if err := st.Initialize(ctx); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
now := time.Now().UTC()
|
|
// parent run
|
|
if err := st.StartRun(ctx, audit.SkillRun{ID: "r1", SkillID: "agent-x", CallerID: "c1",
|
|
Inputs: map[string]any{"q": "hi"}, StartedAt: now}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// child run
|
|
st.StartRun(ctx, audit.SkillRun{ID: "r2", SkillID: "skill-y", CallerID: "c1", ParentRunID: "r1", StartedAt: now.Add(time.Second)})
|
|
|
|
st.AppendLog(ctx, audit.SkillRunLog{RunID: "r1", Sequence: 1, EventType: "step", Payload: map[string]any{"i": 1}, CreatedAt: now})
|
|
if err := st.FinishRun(ctx, "r1", audit.RunStats{Status: "ok", Output: "done", ToolCalls: 2, InputTokens: 10, OutputTokens: 5}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
got, err := st.GetRun(ctx, "r1")
|
|
if err != nil || got.Status != "ok" || got.Output != "done" || got.FinishedAt == nil ||
|
|
got.Inputs["q"] != "hi" || got.TotalInputTokens != 10 {
|
|
t.Fatalf("GetRun: %v %+v", err, got)
|
|
}
|
|
if logs, _ := st.ListLogsByRun(ctx, "r1"); len(logs) != 1 || logs[0].EventType != "step" {
|
|
t.Errorf("ListLogsByRun = %+v", logs)
|
|
}
|
|
if kids, _ := st.ListChildrenByParent(ctx, "r1"); len(kids) != 1 || kids[0].ID != "r2" {
|
|
t.Errorf("ListChildrenByParent = %+v", kids)
|
|
}
|
|
if chain, _ := st.WalkParentChain(ctx, "r2"); len(chain) != 2 || chain[1].ID != "r1" {
|
|
t.Errorf("WalkParentChain = %+v", chain)
|
|
}
|
|
if byCaller, _ := st.ListRunsByCaller(ctx, "c1", 10); len(byCaller) != 2 {
|
|
t.Errorf("ListRunsByCaller = %d, want 2", len(byCaller))
|
|
}
|
|
// filter: top-level only
|
|
tl, _ := st.ListRunsFiltered(ctx, audit.RunFilter{TopLevelOnly: true}, 0, 10)
|
|
if len(tl) != 1 || tl[0].ID != "r1" {
|
|
t.Errorf("TopLevelOnly filter = %+v", tl)
|
|
}
|
|
// last-run map
|
|
last, _ := st.LastRunBySkills(ctx, []string{"agent-x", "skill-y"}, true)
|
|
if _, ok := last["agent-x"]; !ok {
|
|
t.Errorf("LastRunBySkills missing agent-x: %+v", last)
|
|
}
|
|
if n, _ := st.CountRunsBySkill(ctx, "agent-x", false); n != 1 {
|
|
t.Errorf("CountRunsBySkill = %d, want 1", n)
|
|
}
|
|
}
|