Raise server e2e run-terminal wait windows for slow CI #230

Merged
weichen merged 1 commits from fix/server-e2e-terminal-wait into main 2026-10-20 12:53:17 +00:00
2 changed files with 16 additions and 13 deletions
+14 -10
View File
@@ -200,6 +200,10 @@ func postMessage(t *testing.T, h http.Handler, convID, text string) string {
return run["id"].(string) return run["id"].(string)
} }
// testRunTerminalTimeout bounds run-terminal waits; slow, heavily parallel CI
// machines need far more than the typical few hundred milliseconds.
const testRunTerminalTimeout = 30 * time.Second
func waitRunTerminal(t *testing.T, h http.Handler, runID string, timeout time.Duration) map[string]any { func waitRunTerminal(t *testing.T, h http.Handler, runID string, timeout time.Duration) map[string]any {
deadline := time.Now().Add(timeout) deadline := time.Now().Add(timeout)
for time.Now().Before(deadline) { for time.Now().Before(deadline) {
@@ -253,7 +257,7 @@ func TestMockCardflowFullLoop(t *testing.T) {
h := srv.Handler() h := srv.Handler()
_, convID := setupConversation(t, h) _, convID := setupConversation(t, h)
runID := postMessage(t, h, convID, "#cardflow") runID := postMessage(t, h, convID, "#cardflow")
terminal := waitRunCompleted(t, h, st, convID, runID, 5*time.Second) terminal := waitRunCompleted(t, h, st, convID, runID, testRunTerminalTimeout)
if terminal["status"] != "completed" { if terminal["status"] != "completed" {
t.Fatalf("run status: %v", terminal["status"]) t.Fatalf("run status: %v", terminal["status"])
} }
@@ -306,7 +310,7 @@ func TestMockCardflowStreamLoop(t *testing.T) {
h := srv.Handler() h := srv.Handler()
_, convID := setupConversation(t, h) _, convID := setupConversation(t, h)
runID := postMessage(t, h, convID, "#cardstream") runID := postMessage(t, h, convID, "#cardstream")
terminal := waitRunCompleted(t, h, st, convID, runID, 5*time.Second) terminal := waitRunCompleted(t, h, st, convID, runID, testRunTerminalTimeout)
if terminal["status"] != "completed" { if terminal["status"] != "completed" {
t.Fatalf("run status: %v", terminal["status"]) t.Fatalf("run status: %v", terminal["status"])
} }
@@ -372,7 +376,7 @@ func TestMockConversationFlow(t *testing.T) {
h := srv.Handler() h := srv.Handler()
_, convID := setupConversation(t, h) _, convID := setupConversation(t, h)
runID := postMessage(t, h, convID, "你好,骨架测试") runID := postMessage(t, h, convID, "你好,骨架测试")
terminal := waitRunTerminal(t, h, runID, 5*time.Second) terminal := waitRunTerminal(t, h, runID, testRunTerminalTimeout)
if terminal["status"] != "completed" { if terminal["status"] != "completed" {
t.Fatalf("run status: %v", terminal["status"]) t.Fatalf("run status: %v", terminal["status"])
} }
@@ -461,7 +465,7 @@ func TestHITLChoiceFlow(t *testing.T) {
} }
mustCode(t, h, "POST", "/api/hitl/"+card.ID+"/resolve", map[string]any{"choiceId": "md"}) mustCode(t, h, "POST", "/api/hitl/"+card.ID+"/resolve", map[string]any{"choiceId": "md"})
terminal := waitRunTerminal(t, h, runID, 5*time.Second) terminal := waitRunTerminal(t, h, runID, testRunTerminalTimeout)
if terminal["status"] != "completed" { if terminal["status"] != "completed" {
t.Fatalf("run status after resolve: %v", terminal["status"]) t.Fatalf("run status after resolve: %v", terminal["status"])
} }
@@ -519,7 +523,7 @@ func TestConversationResumeSeq(t *testing.T) {
cardID := waiting["activeHitl"].([]any)[0].(map[string]any)["id"].(string) cardID := waiting["activeHitl"].([]any)[0].(map[string]any)["id"].(string)
mustCode(t, h, "POST", "/api/hitl/"+cardID+"/resolve", map[string]any{"choiceId": "md"}) mustCode(t, h, "POST", "/api/hitl/"+cardID+"/resolve", map[string]any{"choiceId": "md"})
terminal := waitRunTerminal(t, h, runID, 5*time.Second) terminal := waitRunTerminal(t, h, runID, testRunTerminalTimeout)
if terminal["status"] != "completed" { if terminal["status"] != "completed" {
t.Fatalf("run status after resolve: %v", terminal["status"]) t.Fatalf("run status after resolve: %v", terminal["status"])
} }
@@ -552,7 +556,7 @@ func TestHITLFreeTextPivot(t *testing.T) {
if out["pivoted"] != true { if out["pivoted"] != true {
t.Fatalf("expected pivot=true, got %v", out) t.Fatalf("expected pivot=true, got %v", out)
} }
terminal := waitRunTerminal(t, h, runID, 5*time.Second) terminal := waitRunTerminal(t, h, runID, testRunTerminalTimeout)
if terminal["status"] != "cancelled" { if terminal["status"] != "cancelled" {
t.Fatalf("suspended run should be cancelled on pivot, got %v", terminal["status"]) t.Fatalf("suspended run should be cancelled on pivot, got %v", terminal["status"])
} }
@@ -589,7 +593,7 @@ func TestArtifactFlow(t *testing.T) {
h := srv.Handler() h := srv.Handler()
projectID, convID := setupConversation(t, h) projectID, convID := setupConversation(t, h)
runID := postMessage(t, h, convID, "#doc") runID := postMessage(t, h, convID, "#doc")
waitRunTerminal(t, h, runID, 5*time.Second) waitRunTerminal(t, h, runID, testRunTerminalTimeout)
code, raw := doAny(t, h, "GET", "/api/projects/"+projectID+"/artifacts", nil) code, raw := doAny(t, h, "GET", "/api/projects/"+projectID+"/artifacts", nil)
if code != 200 { if code != 200 {
@@ -651,7 +655,7 @@ func TestArtifactFacadeCard(t *testing.T) {
h := srv.Handler() h := srv.Handler()
_, convID := setupConversation(t, h) _, convID := setupConversation(t, h)
runID := postMessage(t, h, convID, "#doc") runID := postMessage(t, h, convID, "#doc")
terminal := waitRunCompleted(t, h, st, convID, runID, 5*time.Second) terminal := waitRunCompleted(t, h, st, convID, runID, testRunTerminalTimeout)
if terminal["status"] != "completed" { if terminal["status"] != "completed" {
t.Fatalf("run status: %v", terminal["status"]) t.Fatalf("run status: %v", terminal["status"])
} }
@@ -972,7 +976,7 @@ func TestHITLIntentPivot(t *testing.T) {
if out["pivoted"] != true { if out["pivoted"] != true {
t.Fatalf("intent hit should pivot: %v", out) t.Fatalf("intent hit should pivot: %v", out)
} }
terminal := waitRunTerminal(t, h, runID, 5*time.Second) terminal := waitRunTerminal(t, h, runID, testRunTerminalTimeout)
if terminal["status"] != "cancelled" { if terminal["status"] != "cancelled" {
t.Fatalf("suspended run should cancel on intent pivot, got %v", terminal["status"]) t.Fatalf("suspended run should cancel on intent pivot, got %v", terminal["status"])
} }
@@ -1214,7 +1218,7 @@ func TestProjectInbox(t *testing.T) {
h := srv.Handler() h := srv.Handler()
projectID, convID := setupConversation(t, h) projectID, convID := setupConversation(t, h)
runID := postMessage(t, h, convID, "#cardflow") runID := postMessage(t, h, convID, "#cardflow")
terminal := waitRunTerminal(t, h, runID, 5*time.Second) terminal := waitRunTerminal(t, h, runID, testRunTerminalTimeout)
if terminal["status"] != "completed" { if terminal["status"] != "completed" {
t.Fatalf("run status: %v", terminal["status"]) t.Fatalf("run status: %v", terminal["status"])
} }
+2 -3
View File
@@ -5,7 +5,6 @@ import (
core "agent-system-core" core "agent-system-core"
"net/http" "net/http"
"testing" "testing"
"time"
) )
func TestWorkActionsAreNonblockingAndDoNotAppendReceipt(t *testing.T) { func TestWorkActionsAreNonblockingAndDoNotAppendReceipt(t *testing.T) {
@@ -30,7 +29,7 @@ func TestWorkActionsAreNonblockingAndDoNotAppendReceipt(t *testing.T) {
t.Fatalf("optional choice wrote chat messages: %v", messages) t.Fatalf("optional choice wrote chat messages: %v", messages)
} }
run := postMessage(t, h, convID, "现在聊聊别的事情") run := postMessage(t, h, convID, "现在聊聊别的事情")
waitRunTerminal(t, h, run, 5*time.Second) waitRunTerminal(t, h, run, testRunTerminalTimeout)
code, _ := doJSON(t, h, http.MethodPost, "/api/cards/"+card.ID+"/actions/work.read", map[string]any{"resultVersion": 2}) code, _ := doJSON(t, h, http.MethodPost, "/api/cards/"+card.ID+"/actions/work.read", map[string]any{"resultVersion": 2})
if code != http.StatusConflict { if code != http.StatusConflict {
t.Fatalf("version fence status %d", code) t.Fatalf("version fence status %d", code)
@@ -59,5 +58,5 @@ func TestExplicitWorkReferenceRejectsOtherConversationBeforeWriting(t *testing.T
t.Fatalf("valid reference %d %v", code, body) t.Fatalf("valid reference %d %v", code, body)
} }
run := body["run"].(map[string]any)["id"].(string) run := body["run"].(map[string]any)["id"].(string)
waitRunTerminal(t, h, run, 5*time.Second) waitRunTerminal(t, h, run, testRunTerminalTimeout)
} }