Harden inbox JSON validation and claim conflicts

This commit is contained in:
2026-03-19 03:35:37 +08:00
parent f315d2330d
commit 02d98a78dd
3 changed files with 257 additions and 16 deletions
+107
View File
@@ -0,0 +1,107 @@
package store
import (
"context"
"errors"
"path/filepath"
"testing"
"time"
dbpkg "ai-workflow-skill/internal/db"
)
func TestClaimThreadReturnsLeaseConflictAfterBusyWrite(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
dbPath := filepath.Join(t.TempDir(), "coord.db")
sqlDB, err := dbpkg.Open(ctx, dbPath)
if err != nil {
t.Fatalf("open base db: %v", err)
}
defer sqlDB.Close()
if err := dbpkg.ApplyMigrations(ctx, sqlDB); err != nil {
t.Fatalf("apply migrations: %v", err)
}
baseStore := NewInboxStore(sqlDB)
thread, _, err := baseStore.Send(ctx, SendInput{
FromAgent: "leader",
ToAgent: "worker-a",
Subject: "race claim",
Summary: "race claim",
})
if err != nil {
t.Fatalf("seed thread: %v", err)
}
lockerDB, err := dbpkg.Open(ctx, dbPath)
if err != nil {
t.Fatalf("open locker db: %v", err)
}
defer lockerDB.Close()
lockTx, err := lockerDB.BeginTx(ctx, nil)
if err != nil {
t.Fatalf("begin locker tx: %v", err)
}
now := nowUTC()
if _, err := lockTx.ExecContext(
ctx,
`INSERT INTO leases (
thread_id, agent_id, lease_token, claimed_at, expires_at, released_at
) VALUES (?, ?, ?, ?, ?, NULL)`,
thread.ThreadID,
"worker-a",
"lease_locked",
formatTime(now),
formatTime(now.Add(5*time.Minute)),
); err != nil {
t.Fatalf("seed active lease in tx: %v", err)
}
if _, err := lockTx.ExecContext(
ctx,
`UPDATE threads
SET status = ?, assigned_to = ?, latest_message_id = ?, updated_at = ?
WHERE thread_id = ?`,
"claimed",
"worker-a",
"msg_locked",
formatTime(now),
thread.ThreadID,
); err != nil {
t.Fatalf("seed claimed thread in tx: %v", err)
}
commitDone := make(chan error, 1)
go func() {
time.Sleep(100 * time.Millisecond)
commitDone <- lockTx.Commit()
}()
claimDB, err := dbpkg.Open(ctx, dbPath)
if err != nil {
t.Fatalf("open claim db: %v", err)
}
defer claimDB.Close()
claimStore := NewInboxStore(claimDB)
_, err = claimStore.ClaimThread(ctx, ClaimInput{
ThreadID: thread.ThreadID,
Agent: "worker-b",
LeaseSeconds: 300,
})
if !errors.Is(err, ErrLeaseConflict) {
t.Fatalf("expected lease conflict after busy retry, got %v", err)
}
if err := <-commitDone; err != nil {
t.Fatalf("commit locker tx: %v", err)
}
}