test: add inbox command integration coverage
This commit is contained in:
@@ -0,0 +1,187 @@
|
||||
package inbox
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestFetchReturnsPendingThreadForTargetAgent(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
dbPath := initCommandTestDB(t)
|
||||
sendPendingThread(t, dbPath, "leader", "worker-a", "Implement task", "Create API endpoint")
|
||||
|
||||
fetchOut := runInboxCommand(
|
||||
t,
|
||||
"--db", dbPath,
|
||||
"--json",
|
||||
"fetch",
|
||||
"--agent", "worker-a",
|
||||
"--status", "pending",
|
||||
)
|
||||
|
||||
var fetchResp map[string]any
|
||||
mustDecodeJSON(t, fetchOut, &fetchResp)
|
||||
threads, ok := nestedValue(t, fetchResp, "data", "threads").([]any)
|
||||
if !ok || len(threads) < 1 {
|
||||
t.Fatalf("expected at least one fetched thread, got %#v", nestedValue(t, fetchResp, "data", "threads"))
|
||||
}
|
||||
thread, ok := threads[0].(map[string]any)
|
||||
if !ok {
|
||||
t.Fatalf("expected thread object, got %#v", threads[0])
|
||||
}
|
||||
if got, _ := thread["assigned_to"].(string); got != "worker-a" {
|
||||
t.Fatalf("expected assigned_to worker-a, got %#v", thread["assigned_to"])
|
||||
}
|
||||
if got, _ := thread["status"].(string); got != "pending" {
|
||||
t.Fatalf("expected pending status, got %#v", thread["status"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestFetchRespectsStatusAndLimitFilters(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
dbPath := initCommandTestDB(t)
|
||||
sendPendingThread(t, dbPath, "leader", "worker-a", "Task A", "Pending task")
|
||||
blockedThreadID := sendPendingThread(t, dbPath, "leader", "worker-a", "Task B", "Blocked task")
|
||||
|
||||
runInboxCommand(
|
||||
t,
|
||||
"--db", dbPath,
|
||||
"--json",
|
||||
"claim",
|
||||
"--agent", "worker-a",
|
||||
"--thread", blockedThreadID,
|
||||
)
|
||||
runInboxCommand(
|
||||
t,
|
||||
"--db", dbPath,
|
||||
"--json",
|
||||
"update",
|
||||
"--agent", "worker-a",
|
||||
"--thread", blockedThreadID,
|
||||
"--status", "blocked",
|
||||
"--summary", "Need decision",
|
||||
"--payload-json", `{"question":"continue?"}`,
|
||||
)
|
||||
|
||||
fetchOut := runInboxCommand(
|
||||
t,
|
||||
"--db", dbPath,
|
||||
"--json",
|
||||
"fetch",
|
||||
"--agent", "worker-a",
|
||||
"--status", "pending,blocked",
|
||||
"--limit", "1",
|
||||
)
|
||||
|
||||
var fetchResp map[string]any
|
||||
mustDecodeJSON(t, fetchOut, &fetchResp)
|
||||
threads, ok := nestedValue(t, fetchResp, "data", "threads").([]any)
|
||||
if !ok {
|
||||
t.Fatalf("expected threads array, got %#v", nestedValue(t, fetchResp, "data", "threads"))
|
||||
}
|
||||
if len(threads) > 1 {
|
||||
t.Fatalf("expected at most one thread with limit=1, got %d", len(threads))
|
||||
}
|
||||
if len(threads) == 0 {
|
||||
t.Fatalf("expected one thread with status filter, got empty result")
|
||||
}
|
||||
thread, ok := threads[0].(map[string]any)
|
||||
if !ok {
|
||||
t.Fatalf("expected thread object, got %#v", threads[0])
|
||||
}
|
||||
status, _ := thread["status"].(string)
|
||||
if status != "pending" && status != "blocked" {
|
||||
t.Fatalf("expected pending or blocked status, got %#v", thread["status"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestFetchUnreadUsesReadCursor(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
dbPath := initCommandTestDB(t)
|
||||
threadID := sendPendingThread(t, dbPath, "leader", "worker-e", "Review navbar copy", "Check top nav wording")
|
||||
|
||||
firstFetchOut := runInboxCommand(
|
||||
t,
|
||||
"--db", dbPath,
|
||||
"--json",
|
||||
"fetch",
|
||||
"--agent", "worker-e",
|
||||
"--status", "pending",
|
||||
"--unread",
|
||||
)
|
||||
|
||||
var firstFetchResp map[string]any
|
||||
mustDecodeJSON(t, firstFetchOut, &firstFetchResp)
|
||||
firstThreads, ok := nestedValue(t, firstFetchResp, "data", "threads").([]any)
|
||||
if !ok || len(firstThreads) != 1 {
|
||||
t.Fatalf("expected one unread thread before mark-read, got %#v", nestedValue(t, firstFetchResp, "data", "threads"))
|
||||
}
|
||||
|
||||
runInboxCommand(
|
||||
t,
|
||||
"--db", dbPath,
|
||||
"--agent", "worker-e",
|
||||
"--json",
|
||||
"show",
|
||||
"--thread", threadID,
|
||||
"--mark-read",
|
||||
)
|
||||
|
||||
stdout, _, exitCode := executeInboxCommand(
|
||||
"--db", dbPath,
|
||||
"--json",
|
||||
"fetch",
|
||||
"--agent", "worker-e",
|
||||
"--status", "pending",
|
||||
"--unread",
|
||||
)
|
||||
if exitCode != 10 {
|
||||
t.Fatalf("expected unread fetch to return no_matching_work after mark-read, got exit=%d stdout=%s", exitCode, stdout)
|
||||
}
|
||||
assertErrorJSON(t, stdout, "no_matching_work")
|
||||
|
||||
runInboxCommand(
|
||||
t,
|
||||
"--db", dbPath,
|
||||
"--json",
|
||||
"send",
|
||||
"--from", "leader",
|
||||
"--to", "worker-e",
|
||||
"--thread", threadID,
|
||||
"--summary", "Use sentence case",
|
||||
"--body", "Keep the nav labels in sentence case.",
|
||||
)
|
||||
|
||||
thirdFetchOut := runInboxCommand(
|
||||
t,
|
||||
"--db", dbPath,
|
||||
"--json",
|
||||
"fetch",
|
||||
"--agent", "worker-e",
|
||||
"--status", "pending",
|
||||
"--unread",
|
||||
)
|
||||
var thirdFetchResp map[string]any
|
||||
mustDecodeJSON(t, thirdFetchOut, &thirdFetchResp)
|
||||
thirdThreads, ok := nestedValue(t, thirdFetchResp, "data", "threads").([]any)
|
||||
if !ok || len(thirdThreads) != 1 {
|
||||
t.Fatalf("expected unread thread to reappear after new message, got %#v", nestedValue(t, thirdFetchResp, "data", "threads"))
|
||||
}
|
||||
}
|
||||
|
||||
func TestFetchReturnsNoMatchingWorkWhenEmpty(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
dbPath := initCommandTestDB(t)
|
||||
stdout, _, exitCode := executeInboxCommand(
|
||||
"--db", dbPath,
|
||||
"--json",
|
||||
"fetch",
|
||||
"--agent", "worker-z",
|
||||
"--status", "pending",
|
||||
)
|
||||
if exitCode != 10 {
|
||||
t.Fatalf("expected exit code 10, got %d", exitCode)
|
||||
}
|
||||
assertErrorJSON(t, stdout, "no_matching_work")
|
||||
}
|
||||
Reference in New Issue
Block a user