diff options
| author | Peter Stone <thepeterstone@gmail.com> | 2026-03-08 20:40:02 +0000 |
|---|---|---|
| committer | Peter Stone <thepeterstone@gmail.com> | 2026-03-08 20:40:02 +0000 |
| commit | 8777bf226529f45a1c29b3e63ba8efee916e1726 (patch) | |
| tree | cf0d6f8cd0f0b030bbd20fe5807dbd24642450df /internal/storage/db_test.go | |
| parent | 1f36e2312d316969db65a601ac7d9793fbc3bc4c (diff) | |
storage: enforce valid state transitions in UpdateTaskState
UpdateTaskState now validates the transition using ValidTransition inside
a transaction. Invalid transitions return an error rather than blindly
updating. Tests for retry-limit and running-task-rejection test setup
are updated to create tasks with the target state directly via CreateTask
to bypass the transition guard in setup code.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'internal/storage/db_test.go')
| -rw-r--r-- | internal/storage/db_test.go | 34 |
1 files changed, 33 insertions, 1 deletions
diff --git a/internal/storage/db_test.go b/internal/storage/db_test.go index fcdc529..2738a41 100644 --- a/internal/storage/db_test.go +++ b/internal/storage/db_test.go @@ -40,7 +40,7 @@ func TestCreateTask_AndGetTask(t *testing.T) { Claude: task.ClaudeConfig{ Model: "sonnet", Instructions: "do it", - WorkingDir: "/tmp", + ProjectDir: "/tmp", MaxBudgetUSD: 2.5, }, Priority: task.PriorityHigh, @@ -123,6 +123,38 @@ func TestUpdateTaskState_NotFound(t *testing.T) { } } +func TestUpdateTaskState_InvalidTransition(t *testing.T) { + db := testDB(t) + now := time.Now().UTC() + tk := &task.Task{ + ID: "task-invalid", + Name: "InvalidTransition", + Claude: task.ClaudeConfig{Instructions: "test"}, + Priority: task.PriorityNormal, + Retry: task.RetryConfig{MaxAttempts: 1, Backoff: "linear"}, + Tags: []string{}, + DependsOn: []string{}, + State: task.StatePending, + CreatedAt: now, + UpdatedAt: now, + } + if err := db.CreateTask(tk); err != nil { + t.Fatal(err) + } + + // PENDING → COMPLETED is not a valid transition. + err := db.UpdateTaskState("task-invalid", task.StateCompleted) + if err == nil { + t.Fatal("expected error for invalid state transition PENDING → COMPLETED") + } + + // State must not have changed. + got, _ := db.GetTask("task-invalid") + if got.State != task.StatePending { + t.Errorf("state must remain PENDING, got %v", got.State) + } +} + func TestListTasks_FilterByState(t *testing.T) { db := testDB(t) now := time.Now().UTC() |
