Files
ai-workflow-skill/internal/cli/orch/command_contracts_edges_test.go
T

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
}