package agentapi import ( "context" "net/http" "net/http/httptest" "strings" "testing" "time" ) // R-1254 H2: the agent's claim/confirm may take its whole upload timeout (30 s) plus the hub question (15 s) before it // answers. The controller's agent client gives up at 15 s — and a claim the controller abandons can still complete on // the agent: the hub then holds a package whose code nobody saw. The two calls carry their own, longer timeout. // RED-PROOF: send claim/confirm through the plain 15 s client again → the slow agent below times them out → FAILS. func TestR1254_ClaimAndConfirmOutwaitTheAgentsUpload(t *testing.T) { if escrowCallTimeout < 45*time.Second+10*time.Second { t.Fatalf("escrowCallTimeout %s must outlast the agent's upload (30 s) + hub question (15 s) with room", escrowCallTimeout) } mux := http.NewServeMux() mux.HandleFunc("POST /escrow/ceremony/claim", func(w http.ResponseWriter, r *http.Request) { time.Sleep(300 * time.Millisecond) _, _ = w.Write([]byte(`{"ok":true,"data":{"recovery_code":"a-b-c"}}`)) }) mux.HandleFunc("POST /escrow/ceremony/confirm", func(w http.ResponseWriter, r *http.Request) { time.Sleep(300 * time.Millisecond) _, _ = w.Write([]byte(`{"ok":true,"data":{"uploaded":true}}`)) }) s := httptest.NewTLSServer(mux) defer s.Close() c := clientFor(t, s, strings.TrimPrefix(s.URL, "https://")) c.hc.Timeout = 100 * time.Millisecond // the client's own short timeout, scaled down old := escrowCallTimeout escrowCallTimeout = 5 * time.Second defer func() { escrowCallTimeout = old }() if claim, st, err := c.EscrowCeremonyClaim(context.Background()); err != nil || st != http.StatusOK || claim.Code != "a-b-c" { t.Fatalf("a slow claim was abandoned: %+v %d %v", claim, st, err) } if st, err := c.EscrowCeremonyConfirm(context.Background(), []string{"a", "c"}); err != nil || st != http.StatusOK { t.Fatalf("a slow confirm was abandoned: %d %v", st, err) } }