184 lines
4.9 KiB
Go
184 lines
4.9 KiB
Go
package inbox
|
|
|
|
import (
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestListFiltersByStatus(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
dbPath := filepath.Join(t.TempDir(), "coord.db")
|
|
runInboxCommand(t, "--db", dbPath, "--json", "init")
|
|
|
|
createThreadForList(t, dbPath, "leader", "worker-d", "Task pending", "Pending task")
|
|
blockedThreadID := createThreadForList(t, dbPath, "leader", "worker-d", "Task blocked", "Blocked task")
|
|
runInboxCommand(t, "--db", dbPath, "--json", "claim", "--agent", "worker-d", "--thread", blockedThreadID)
|
|
runInboxCommand(
|
|
t,
|
|
"--db", dbPath,
|
|
"--json",
|
|
"update",
|
|
"--agent", "worker-d",
|
|
"--thread", blockedThreadID,
|
|
"--status", "blocked",
|
|
"--summary", "Need policy decision",
|
|
)
|
|
|
|
listOut := runInboxCommand(
|
|
t,
|
|
"--db", dbPath,
|
|
"--json",
|
|
"list",
|
|
"--agent", "worker-d",
|
|
"--status", "pending,blocked",
|
|
)
|
|
|
|
var listResp map[string]any
|
|
mustDecodeJSON(t, listOut, &listResp)
|
|
threads, ok := nestedValue(t, listResp, "data", "threads").([]any)
|
|
if !ok || len(threads) < 2 {
|
|
t.Fatalf("expected at least two matching threads, got %#v", nestedValue(t, listResp, "data", "threads"))
|
|
}
|
|
for _, raw := range threads {
|
|
thread, ok := raw.(map[string]any)
|
|
if !ok {
|
|
t.Fatalf("expected thread object, got %#v", raw)
|
|
}
|
|
status, _ := thread["status"].(string)
|
|
if status != "pending" && status != "blocked" {
|
|
t.Fatalf("expected status pending or blocked, got %#v", status)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestListFiltersByCreatedBy(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
dbPath := filepath.Join(t.TempDir(), "coord.db")
|
|
runInboxCommand(t, "--db", dbPath, "--json", "init")
|
|
|
|
createThreadForList(t, dbPath, "leader", "worker-d", "Leader task", "From leader")
|
|
createThreadForList(t, dbPath, "planner", "worker-d", "Planner task", "From planner")
|
|
|
|
listOut := runInboxCommand(
|
|
t,
|
|
"--db", dbPath,
|
|
"--json",
|
|
"list",
|
|
"--created-by", "leader",
|
|
"--assigned-to", "worker-d",
|
|
)
|
|
|
|
var listResp map[string]any
|
|
mustDecodeJSON(t, listOut, &listResp)
|
|
threads, ok := nestedValue(t, listResp, "data", "threads").([]any)
|
|
if !ok || len(threads) == 0 {
|
|
t.Fatalf("expected matching leader-created threads, got %#v", nestedValue(t, listResp, "data", "threads"))
|
|
}
|
|
for _, raw := range threads {
|
|
thread, ok := raw.(map[string]any)
|
|
if !ok {
|
|
t.Fatalf("expected thread object, got %#v", raw)
|
|
}
|
|
if got := thread["created_by"]; got != "leader" {
|
|
t.Fatalf("expected created_by leader, got %#v", got)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestListFiltersByAssignedTo(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
dbPath := filepath.Join(t.TempDir(), "coord.db")
|
|
runInboxCommand(t, "--db", dbPath, "--json", "init")
|
|
|
|
createThreadForList(t, dbPath, "leader", "worker-d", "Worker D task", "For worker-d")
|
|
createThreadForList(t, dbPath, "leader", "worker-e", "Worker E task", "For worker-e")
|
|
|
|
listOut := runInboxCommand(
|
|
t,
|
|
"--db", dbPath,
|
|
"--json",
|
|
"list",
|
|
"--assigned-to", "worker-d",
|
|
"--status", "pending",
|
|
)
|
|
|
|
var listResp map[string]any
|
|
mustDecodeJSON(t, listOut, &listResp)
|
|
threads, ok := nestedValue(t, listResp, "data", "threads").([]any)
|
|
if !ok || len(threads) == 0 {
|
|
t.Fatalf("expected assigned-to match, got %#v", nestedValue(t, listResp, "data", "threads"))
|
|
}
|
|
for _, raw := range threads {
|
|
thread, ok := raw.(map[string]any)
|
|
if !ok {
|
|
t.Fatalf("expected thread object, got %#v", raw)
|
|
}
|
|
if got := thread["assigned_to"]; got != "worker-d" {
|
|
t.Fatalf("expected assigned_to worker-d, got %#v", got)
|
|
}
|
|
if got := thread["status"]; got != "pending" {
|
|
t.Fatalf("expected pending status, got %#v", got)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestListRespectsLimit(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
dbPath := filepath.Join(t.TempDir(), "coord.db")
|
|
runInboxCommand(t, "--db", dbPath, "--json", "init")
|
|
|
|
createThreadForList(t, dbPath, "leader", "worker-d", "Task 1", "Earlier task")
|
|
time.Sleep(20 * time.Millisecond)
|
|
createThreadForList(t, dbPath, "leader", "worker-d", "Task 2", "Latest task")
|
|
|
|
listOut := runInboxCommand(
|
|
t,
|
|
"--db", dbPath,
|
|
"--json",
|
|
"list",
|
|
"--assigned-to", "worker-d",
|
|
"--limit", "1",
|
|
)
|
|
|
|
var listResp map[string]any
|
|
mustDecodeJSON(t, listOut, &listResp)
|
|
threads, ok := nestedValue(t, listResp, "data", "threads").([]any)
|
|
if !ok {
|
|
t.Fatalf("expected threads array, got %#v", nestedValue(t, listResp, "data", "threads"))
|
|
}
|
|
if len(threads) != 1 {
|
|
t.Fatalf("expected exactly one row for limit=1, got %d", len(threads))
|
|
}
|
|
thread, ok := threads[0].(map[string]any)
|
|
if !ok {
|
|
t.Fatalf("expected thread object, got %#v", threads[0])
|
|
}
|
|
if got := thread["subject"]; got != "Task 2" {
|
|
t.Fatalf("expected latest thread subject Task 2, got %#v", got)
|
|
}
|
|
}
|
|
|
|
func createThreadForList(t *testing.T, dbPath, from, to, subject, summary string) string {
|
|
t.Helper()
|
|
|
|
sendOut := runInboxCommand(
|
|
t,
|
|
"--db", dbPath,
|
|
"--json",
|
|
"send",
|
|
"--from", from,
|
|
"--to", to,
|
|
"--subject", subject,
|
|
"--summary", summary,
|
|
)
|
|
var sendResp map[string]any
|
|
mustDecodeJSON(t, sendOut, &sendResp)
|
|
return nestedString(t, sendResp, "data", "thread", "thread_id")
|
|
}
|
|
|