forked from molecule-ai/molecule-core
test(e2e): fix /registry/register payload — id (not workspace_id) + agent_card
The new external-runtime regression test had two payload bugs that made
step 5 fail with HTTP 400 on its first run:
1. Field name: sent {"workspace_id":...} but RegisterPayload (workspace-
server/internal/models/workspace.go:58) declares `id` with
binding:"required" — workspace_id is the heartbeat payload's field,
not register's.
2. Missing required field: agent_card has binding:"required" and was
absent. ShouldBindJSON 400'd before any handler logic ran, which is
why the body said nothing useful.
Why this got past local verification: the test was written from memory
of the heartbeat shape, never run end-to-end before pushing, and curl
with --fail-with-body prints the body to stdout but exit-22's under
set -e — the body was suppressed before the log line could fire.
Fix:
- Send `id` + a minimal valid agent_card ({name, skills:[{id,name}]})
matching the canonical shape from tests/e2e/test_api.sh:96.
- Pull the body into REGISTER_BODY shared between steps 5 and 7 so
drift between the two register calls is impossible.
- Drop --fail-with-body for these two calls and append HTTP_CODE via
curl -w so the body is always visible when the call non-200s. The
explicit grep for HTTP_CODE=200 + ||true on curl preserves the
fail-fast contract.
- Inline payload contract comment pointing at RegisterPayload so the
next person editing this doesn't repeat the heartbeat-confusion
mistake.
The url=https://example.invalid:443 is fine: runtime=external resolves
to poll mode (registry.go:resolveDeliveryMode case 3), and validateAgentURL
only fires for push.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
56a1b659b1
commit
eacc229e91
@ -257,12 +257,25 @@ ok "DB row stored as awaiting_agent (proof migration 046 applied)"
|
||||
# PR #2382.
|
||||
log "5/8 Registering workspace via /registry/register..."
|
||||
[ -z "$WS_AUTH_TOKEN" ] && fail "No workspace auth token returned — register impossible"
|
||||
REGISTER_RESP=$(curl "${CURL_COMMON[@]}" -X POST "$TENANT_URL/registry/register" \
|
||||
# Payload contract (workspace-server/internal/models/workspace.go RegisterPayload):
|
||||
# id — required, the workspace UUID (NOT "workspace_id" — that's the
|
||||
# heartbeat payload field; mixing them yields a 400 from
|
||||
# ShouldBindJSON because `id` has binding:"required").
|
||||
# agent_card — required (binding:"required"); minimal valid card is name+skills.
|
||||
# url — only validated for push-mode workspaces; runtime=external
|
||||
# resolves to poll (registry.go:resolveDeliveryMode), so
|
||||
# example.invalid is accepted as a placeholder URL the
|
||||
# platform never dispatches to.
|
||||
REGISTER_BODY=$(printf '{"id":"%s","url":"https://example.invalid:443","agent_card":{"name":"e2e-ext","skills":[{"id":"echo","name":"Echo"}]}}' "$WS_ID")
|
||||
# Disable --fail-with-body for this one call so a 4xx surfaces the response
|
||||
# body (the bare CURL_COMMON would `set -e`-kill before we could log it).
|
||||
REGISTER_RESP=$(curl -sS --max-time 30 -w "\nHTTP_CODE=%{http_code}" -X POST "$TENANT_URL/registry/register" \
|
||||
-H "Authorization: Bearer $WS_AUTH_TOKEN" \
|
||||
-H "X-Molecule-Org-Id: $ORG_ID" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"workspace_id\":\"$WS_ID\",\"url\":\"https://example.invalid:443\"}")
|
||||
log " register response: $(echo "$REGISTER_RESP" | head -c 200)"
|
||||
-d "$REGISTER_BODY") || true
|
||||
log " register response: $(echo "$REGISTER_RESP" | head -c 300)"
|
||||
echo "$REGISTER_RESP" | grep -q "HTTP_CODE=200" || fail "register returned non-200 — see body above"
|
||||
|
||||
GET_RESP=$(tenant_call GET "/workspaces/$WS_ID")
|
||||
ONLINE_STATUS=$(echo "$GET_RESP" | python3 -c "import json,sys; print(json.load(sys.stdin).get('status',''))")
|
||||
@ -296,12 +309,15 @@ ok "Heartbeat-staleness sweep transitioned online → awaiting_agent (proof heal
|
||||
# This proves the awaiting_agent state is recoverable (re-registrable),
|
||||
# which is the whole point of using it instead of 'offline'.
|
||||
log "7/8 Re-registering after stale → confirming recovery to online..."
|
||||
REREG_RESP=$(curl "${CURL_COMMON[@]}" -X POST "$TENANT_URL/registry/register" \
|
||||
# Same payload contract as step 5 (id + agent_card both required). See note
|
||||
# there for why workspace_id would 400.
|
||||
REREG_RESP=$(curl -sS --max-time 30 -w "\nHTTP_CODE=%{http_code}" -X POST "$TENANT_URL/registry/register" \
|
||||
-H "Authorization: Bearer $WS_AUTH_TOKEN" \
|
||||
-H "X-Molecule-Org-Id: $ORG_ID" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"workspace_id\":\"$WS_ID\",\"url\":\"https://example.invalid:443\"}")
|
||||
log " re-register response: $(echo "$REREG_RESP" | head -c 200)"
|
||||
-d "$REGISTER_BODY") || true
|
||||
log " re-register response: $(echo "$REREG_RESP" | head -c 300)"
|
||||
echo "$REREG_RESP" | grep -q "HTTP_CODE=200" || fail "re-register returned non-200 — see body above"
|
||||
|
||||
GET_RESP=$(tenant_call GET "/workspaces/$WS_ID")
|
||||
RECOVERED_STATUS=$(echo "$GET_RESP" | python3 -c "import json,sys; print(json.load(sys.stdin).get('status',''))")
|
||||
|
||||
Loading…
Reference in New Issue
Block a user