Files
kandev/apps/backend/internal/github/store_watch_disable_test.go

104 lines
2.9 KiB
Go

package github
import (
"context"
"testing"
"time"
)
// TestDisableIssueWatchWithError_StampsCauseAndDisables pins the self-heal
// contract for github_issue_watches: orphaned watcher is flipped to
// enabled=0 with a human-readable LastError + LastErrorAt timestamp.
func TestDisableIssueWatchWithError_StampsCauseAndDisables(t *testing.T) {
store := newTestStore(t)
ctx := context.Background()
iw := &IssueWatch{
WorkspaceID: "ws-1",
WorkflowID: "wf-1",
WorkflowStepID: "step-1",
AgentProfileID: "deleted-profile",
ExecutorProfileID: "exec-1",
Enabled: true,
}
if err := store.CreateIssueWatch(ctx, iw); err != nil {
t.Fatalf("create: %v", err)
}
const cause = `agent profile "Removed Kilo" (deleted-profile) was removed`
// Widen the window by 1s on each side to absorb SQLite second-precision
// timestamp rounding.
before := time.Now().UTC().Add(-time.Second)
if err := store.DisableIssueWatchWithError(ctx, iw.ID, cause); err != nil {
t.Fatalf("disable: %v", err)
}
after := time.Now().UTC().Add(time.Second)
got, err := store.GetIssueWatch(ctx, iw.ID)
if err != nil {
t.Fatalf("get: %v", err)
}
if got == nil {
t.Fatal("expected row, got nil")
}
if got.Enabled {
t.Error("Enabled should be false after self-heal")
}
if got.LastError != cause {
t.Errorf("LastError = %q, want %q", got.LastError, cause)
}
if got.LastErrorAt == nil {
t.Fatal("LastErrorAt should be set")
}
if got.LastErrorAt.Before(before) || got.LastErrorAt.After(after) {
t.Errorf("LastErrorAt %v outside [%v, %v]", got.LastErrorAt, before, after)
}
}
// TestDisableReviewWatchWithError_StampsCauseAndDisables mirrors the issue
// test for review watches.
func TestDisableReviewWatchWithError_StampsCauseAndDisables(t *testing.T) {
store := newTestStore(t)
ctx := context.Background()
rw := &ReviewWatch{
WorkspaceID: "ws-1",
WorkflowID: "wf-1",
WorkflowStepID: "step-1",
AgentProfileID: "deleted-profile",
ExecutorProfileID: "exec-1",
ReviewScope: "user_and_teams",
Enabled: true,
}
if err := store.CreateReviewWatch(ctx, rw); err != nil {
t.Fatalf("create: %v", err)
}
const cause = `agent profile "Removed Opencode" (deleted-profile) was removed`
before := time.Now().UTC().Add(-time.Second)
if err := store.DisableReviewWatchWithError(ctx, rw.ID, cause); err != nil {
t.Fatalf("disable: %v", err)
}
after := time.Now().UTC().Add(time.Second)
got, err := store.GetReviewWatch(ctx, rw.ID)
if err != nil {
t.Fatalf("get: %v", err)
}
if got == nil {
t.Fatal("expected row, got nil")
}
if got.Enabled {
t.Error("Enabled should be false after self-heal")
}
if got.LastError != cause {
t.Errorf("LastError = %q, want %q", got.LastError, cause)
}
if got.LastErrorAt == nil {
t.Fatal("LastErrorAt should be set")
}
if got.LastErrorAt.Before(before) || got.LastErrorAt.After(after) {
t.Errorf("LastErrorAt %v outside [%v, %v]", got.LastErrorAt, before, after)
}
}