Files
byre/internal/store/review_test.go
T

103 lines
3.7 KiB
Go

package store_test
import (
"context"
"errors"
"path/filepath"
"testing"
"time"
"g.fc.run/misc/byre/internal/api"
"g.fc.run/misc/byre/internal/store"
)
func TestReviewLifecycle(t *testing.T) {
ctx := context.Background()
st, err := store.Open(filepath.Join(t.TempDir(), "byre.db"), store.DefaultPortFirst, func(api.Event) {})
if err != nil {
t.Fatalf("open store: %v", err)
}
t.Cleanup(func() { st.Close() })
now := time.Now().UTC()
_, err = st.EnsureUser(ctx, "alice", "Alice")
if err != nil {
t.Fatalf("ensure user: %v", err)
}
err = st.CreateProject(ctx, api.Project{Id: "p1", Name: "demo", RepoPath: "/nonexistent", DefaultBranch: "main", Remote: "none", CreatedBy: "alice", CreatedAt: now})
if err != nil {
t.Fatalf("create project: %v", err)
}
err = st.CreateTask(ctx, api.Task{Id: "t1", ProjectId: "p1", Title: "t1", Branch: "t1", WorktreePath: "/nonexistent", BaseRef: "x", Status: api.TaskStatusActive, CreatedBy: "alice", CreatedAt: now}, "alice")
if err != nil {
t.Fatalf("create task: %v", err)
}
for _, s := range []struct {
id string
role api.AgentSessionRole
}{{"impl", api.Implementer}, {"rev1", api.Reviewer}, {"rev2", api.Reviewer}} {
err = st.CreateSession(ctx, api.AgentSession{Id: s.id, TaskId: "t1", Vendor: api.Claude, VendorSessionId: s.id, State: api.AgentSessionStateIdle, Role: s.role, CreatedBy: "alice", CreatedAt: now}, "p1")
if err != nil {
t.Fatalf("create session: %v", err)
}
}
sessions, err := st.ListSessions(ctx, "t1")
if err != nil || len(sessions) != 1 || sessions[0].Id != "impl" {
t.Fatalf("task sessions %+v %v, want only the implementer", sessions, err)
}
snap := func(n int, at time.Time) {
t.Helper()
err := st.CreateSnapshot(ctx, api.Snapshot{Id: "s" + string(rune('0'+n)), TaskId: "t1", AgentSessionId: "impl", N: n, CommitSha: "c", TreeSha: "tree" + string(rune('0'+n)), EventSeq: 1, Trigger: api.SnapshotTriggerTurnEnd, CreatedAt: at}, "p1")
if err != nil {
t.Fatalf("create snapshot %d: %v", n, err)
}
}
snap(1, now)
asked := now.Add(time.Second)
err = st.CreateInboxItem(ctx, api.InboxItem{Id: "q1", ProjectId: "p1", TaskId: "t1", AgentSessionId: "impl", ThreadId: "q1",
Kind: api.Question, Priority: api.Blocked, Blocking: true, Payload: map[string]any{}, State: api.Open, CreatedAt: asked})
if err != nil {
t.Fatalf("create question: %v", err)
}
snap(2, asked.Add(time.Second))
for _, r := range []api.Review{
{Id: "r1", TaskId: "t1", SnapshotN: 1, AgentSessionId: "rev1", Vendor: "codex", Model: "m", State: api.ReviewStateRunning, CreatedAt: now},
{Id: "r2", TaskId: "t1", SnapshotN: 2, AgentSessionId: "rev2", Vendor: "codex", Model: "m", State: api.ReviewStateRunning, CreatedAt: now},
} {
err = st.CreateReview(ctx, r)
if err != nil {
t.Fatalf("create review: %v", err)
}
}
byRev, err := st.ReviewBySession(ctx, "rev2")
if err != nil || byRev.Id != "r2" {
t.Fatalf("review by session %+v %v", byRev, err)
}
err = st.FinishReview(ctx, "r2", api.ReviewStateDone, map[string]any{"summary": "fine", "findings": []any{}}, "")
if err != nil {
t.Fatalf("finish: %v", err)
}
err = st.FinishReview(ctx, "r2", api.ReviewStateFailed, nil, "late")
if !errors.Is(err, store.ErrNotFound) {
t.Fatalf("finishing a finished review: %v, want not found", err)
}
item, err := st.GetInboxItem(ctx, "q1")
if err != nil {
t.Fatalf("get question: %v", err)
}
if len(item.Reviews) != 1 || item.Reviews[0].Id != "r2" || item.Reviews[0].Result == nil || (*item.Reviews[0].Result)["summary"] != "fine" {
t.Fatalf("question's reviews %+v, want the review of the snapshot after it", item.Reviews)
}
running, err := st.RunningReviews(ctx)
if err != nil || len(running) != 1 || running[0].Id != "r1" {
t.Fatalf("running reviews %+v %v", running, err)
}
}