220 lines
5.1 KiB
Go
220 lines
5.1 KiB
Go
package orch
|
|
|
|
import (
|
|
"path/filepath"
|
|
"testing"
|
|
)
|
|
|
|
func TestOrchAnswerAcceptsPayloadJSONWithoutBody(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
dbPath := filepath.Join(t.TempDir(), "coord.db")
|
|
threadID := seedBlockedTaskForAnswerCleanupEdgeTests(t, dbPath, "run_blog_answer_001", "T2", "worker-b")
|
|
|
|
answerOut := runOrchCommand(
|
|
t,
|
|
"--db", dbPath,
|
|
"--json",
|
|
"answer",
|
|
"--run", "run_blog_answer_001",
|
|
"--task", "T2",
|
|
"--payload-json", `{"decision":"stdout","source":"leader"}`,
|
|
)
|
|
|
|
var answerResp map[string]any
|
|
mustDecodeJSON(t, answerOut, &answerResp)
|
|
message, ok := nestedValue(t, answerResp, "data", "message").(map[string]any)
|
|
if !ok {
|
|
t.Fatalf("expected answer message object, got %#v", nestedValue(t, answerResp, "data", "message"))
|
|
}
|
|
if got, _ := message["kind"].(string); got != "answer" {
|
|
t.Fatalf("expected answer message kind, got %#v", message["kind"])
|
|
}
|
|
payload, ok := message["payload_json"].(map[string]any)
|
|
if !ok {
|
|
t.Fatalf("expected payload_json object, got %#v", message["payload_json"])
|
|
}
|
|
if got, _ := payload["decision"].(string); got != "stdout" {
|
|
t.Fatalf("expected payload decision stdout, got %#v", payload["decision"])
|
|
}
|
|
if got, _ := payload["source"].(string); got != "leader" {
|
|
t.Fatalf("expected payload source leader, got %#v", payload["source"])
|
|
}
|
|
|
|
showOut := runInboxCommand(
|
|
t,
|
|
"--db", dbPath,
|
|
"--json",
|
|
"show",
|
|
"--thread", threadID,
|
|
)
|
|
|
|
var showResp map[string]any
|
|
mustDecodeJSON(t, showOut, &showResp)
|
|
messages := nestedArray(t, showResp, "data", "messages")
|
|
if len(messages) == 0 {
|
|
t.Fatalf("expected messages in thread %s", threadID)
|
|
}
|
|
lastMessage, ok := messages[len(messages)-1].(map[string]any)
|
|
if !ok {
|
|
t.Fatalf("expected last message object, got %#v", messages[len(messages)-1])
|
|
}
|
|
if got, _ := lastMessage["kind"].(string); got != "answer" {
|
|
t.Fatalf("expected latest message kind answer, got %#v", lastMessage["kind"])
|
|
}
|
|
lastPayload, ok := lastMessage["payload_json"].(map[string]any)
|
|
if !ok {
|
|
t.Fatalf("expected latest payload_json object, got %#v", lastMessage["payload_json"])
|
|
}
|
|
if got, _ := lastPayload["decision"].(string); got != "stdout" {
|
|
t.Fatalf("expected latest payload decision stdout, got %#v", lastPayload["decision"])
|
|
}
|
|
}
|
|
|
|
func TestOrchAnswerRejectsEmptyBodyAndPayload(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
dbPath := filepath.Join(t.TempDir(), "coord.db")
|
|
_ = seedBlockedTaskForAnswerCleanupEdgeTests(t, dbPath, "run_blog_answer_002", "T2", "worker-b")
|
|
|
|
stdout, _, exitCode := executeOrchCommand(
|
|
"--db", dbPath,
|
|
"--json",
|
|
"answer",
|
|
"--run", "run_blog_answer_002",
|
|
"--task", "T2",
|
|
)
|
|
if exitCode != 30 {
|
|
t.Fatalf("expected exit code 30, got %d\nstdout:\n%s", exitCode, stdout)
|
|
}
|
|
assertErrorJSON(t, stdout, "invalid_input")
|
|
}
|
|
|
|
func TestOrchCleanupRejectsAttemptWithoutTask(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
dbPath := filepath.Join(t.TempDir(), "coord.db")
|
|
|
|
runOrchCommand(
|
|
t,
|
|
"--db", dbPath,
|
|
"--json",
|
|
"run", "init",
|
|
"--run", "run_blog_cleanup_002",
|
|
"--goal", "Validate cleanup selectors",
|
|
)
|
|
|
|
stdout, _, exitCode := executeOrchCommand(
|
|
"--db", dbPath,
|
|
"--json",
|
|
"cleanup",
|
|
"--run", "run_blog_cleanup_002",
|
|
"--attempt", "1",
|
|
)
|
|
if exitCode != 30 {
|
|
t.Fatalf("expected exit code 30, got %d\nstdout:\n%s", exitCode, stdout)
|
|
}
|
|
assertErrorJSON(t, stdout, "invalid_input")
|
|
}
|
|
|
|
func TestOrchCleanupReturnsNoMatchingWorkWhenFiltersMiss(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
dbPath := filepath.Join(t.TempDir(), "coord.db")
|
|
|
|
runOrchCommand(
|
|
t,
|
|
"--db", dbPath,
|
|
"--json",
|
|
"run", "init",
|
|
"--run", "run_blog_cleanup_003",
|
|
"--goal", "Validate cleanup empty result",
|
|
)
|
|
runOrchCommand(
|
|
t,
|
|
"--db", dbPath,
|
|
"--json",
|
|
"task", "add",
|
|
"--run", "run_blog_cleanup_003",
|
|
"--task", "T1",
|
|
"--title", "Prepare cleanup target",
|
|
)
|
|
|
|
stdout, _, exitCode := executeOrchCommand(
|
|
"--db", dbPath,
|
|
"--json",
|
|
"cleanup",
|
|
"--run", "run_blog_cleanup_003",
|
|
"--task", "T1",
|
|
)
|
|
if exitCode != 10 {
|
|
t.Fatalf("expected exit code 10, got %d\nstdout:\n%s", exitCode, stdout)
|
|
}
|
|
assertErrorJSON(t, stdout, "no_matching_work")
|
|
}
|
|
|
|
func seedBlockedTaskForAnswerCleanupEdgeTests(t *testing.T, dbPath, runID, taskID, agent string) string {
|
|
t.Helper()
|
|
|
|
runOrchCommand(
|
|
t,
|
|
"--db", dbPath,
|
|
"--json",
|
|
"run", "init",
|
|
"--run", runID,
|
|
"--goal", "Prepare blocked task for answer edge tests",
|
|
)
|
|
runOrchCommand(
|
|
t,
|
|
"--db", dbPath,
|
|
"--json",
|
|
"task", "add",
|
|
"--run", runID,
|
|
"--task", taskID,
|
|
"--title", "Build frontend",
|
|
"--default-to", agent,
|
|
)
|
|
|
|
dispatchOut := runOrchCommand(
|
|
t,
|
|
"--db", dbPath,
|
|
"--json",
|
|
"dispatch",
|
|
"--run", runID,
|
|
"--task", taskID,
|
|
)
|
|
|
|
var dispatchResp map[string]any
|
|
mustDecodeJSON(t, dispatchOut, &dispatchResp)
|
|
threadID := nestedString(t, dispatchResp, "data", "attempt", "thread_id")
|
|
|
|
runInboxCommand(
|
|
t,
|
|
"--db", dbPath,
|
|
"--json",
|
|
"claim",
|
|
"--agent", agent,
|
|
"--thread", threadID,
|
|
)
|
|
runInboxCommand(
|
|
t,
|
|
"--db", dbPath,
|
|
"--json",
|
|
"update",
|
|
"--agent", agent,
|
|
"--thread", threadID,
|
|
"--status", "blocked",
|
|
"--summary", "Need logging decision",
|
|
"--payload-json", `{"question":"stdout or stderr?"}`,
|
|
)
|
|
runOrchCommand(
|
|
t,
|
|
"--db", dbPath,
|
|
"--json",
|
|
"reconcile",
|
|
"--run", runID,
|
|
)
|
|
|
|
return threadID
|
|
}
|