Files
kandev/apps/backend/internal/agent/lifecycle/execution_store_test.go
T

81 lines
2.5 KiB
Go

package lifecycle
import (
"errors"
"testing"
)
// TestExecutionStore_AddRejectsDuplicateSession is the regression test for the
// process-leak bug where two paths created executions for the same session
// concurrently and Add silently overwrote the bySession index, orphaning the
// first execution's agent subprocess.
func TestExecutionStore_AddRejectsDuplicateSession(t *testing.T) {
store := NewExecutionStore()
first := &AgentExecution{ID: "exec-1", SessionID: "session-1"}
if err := store.Add(first); err != nil {
t.Fatalf("first Add: unexpected error: %v", err)
}
second := &AgentExecution{ID: "exec-2", SessionID: "session-1"}
err := store.Add(second)
if !errors.Is(err, ErrExecutionAlreadyExistsForSession) {
t.Fatalf("second Add: want ErrExecutionAlreadyExistsForSession, got %v", err)
}
got, ok := store.GetBySessionID("session-1")
if !ok {
t.Fatalf("GetBySessionID: not found")
}
if got.ID != "exec-1" {
t.Errorf("bySession index: want exec-1, got %s (overwrite was supposed to be rejected)", got.ID)
}
// Second execution must not be in the executions map either — otherwise
// it'd live as an unreachable orphan.
if _, ok := store.Get("exec-2"); ok {
t.Errorf("Get(exec-2): rejected execution must not be tracked")
}
}
func TestExecutionStore_AddSameExecutionTwiceIsIdempotent(t *testing.T) {
store := NewExecutionStore()
exec := &AgentExecution{ID: "exec-1", SessionID: "session-1"}
if err := store.Add(exec); err != nil {
t.Fatalf("first Add: %v", err)
}
if err := store.Add(exec); err != nil {
t.Errorf("re-adding the SAME execution must be a no-op, got %v", err)
}
}
func TestExecutionStore_AddReplaceAfterRemove(t *testing.T) {
store := NewExecutionStore()
first := &AgentExecution{ID: "exec-1", SessionID: "session-1"}
if err := store.Add(first); err != nil {
t.Fatalf("first Add: %v", err)
}
store.Remove("exec-1")
second := &AgentExecution{ID: "exec-2", SessionID: "session-1"}
if err := store.Add(second); err != nil {
t.Errorf("Add after Remove must succeed, got %v", err)
}
got, _ := store.GetBySessionID("session-1")
if got == nil || got.ID != "exec-2" {
t.Errorf("after Remove+Add: want exec-2, got %v", got)
}
}
func TestExecutionStore_AddNoSessionIDAlwaysSucceeds(t *testing.T) {
store := NewExecutionStore()
if err := store.Add(&AgentExecution{ID: "exec-a"}); err != nil {
t.Errorf("Add without SessionID: %v", err)
}
if err := store.Add(&AgentExecution{ID: "exec-b"}); err != nil {
t.Errorf("Add without SessionID (second): %v", err)
}
}