c8559676ed
executus CI / test (push) Has been cancelled
Merges the skill half of the persona/skill pair plus the second nested module. (Squashed onto main from phase-4b-skill; the audit/budget/persona batteries it was stacked on already landed via the P4 merge.) - skill/: clean-redesign Skill noun + LEAN SkillStore (lifecycle/versions/ schedule only) + ToRunnable + Memory default. - contrib/store/: separate go.mod carrying modernc.org/sqlite, so the driver never enters the core go.sum. db.Budget()/Personas()/Skills()/Audit() back all four store seams (JSON-blob + indexed columns; round-trip tested). Includes the verified gadfly #5 fixes (AppendVersion tx+UNIQUE+error, Mark*ScheduledRun atomic json_set, busy_timeout, NaN guard). - CI: builds + tests the nested module and asserts it owns the sqlite driver. 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)
|
|
}
|
|
}
|