Skip to content

Commit cb6a6d5

Browse files
committed
test(haos): wait for Node-RED ingress readiness
1 parent e1f3662 commit cb6a6d5

2 files changed

Lines changed: 30 additions & 14 deletions

File tree

tests/src/e2e/haos_only/test_zz_manage_app_tls.py

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -52,25 +52,35 @@ def _require_tls_ca_path() -> str:
5252
return ca_path
5353

5454

55-
_DIRECT_PORT_READY_TIMEOUT_S = 240.0
55+
_NODERED_HTTP_READY_TIMEOUT_S = 240.0
5656

5757

58-
async def _direct_flows_request(mcp: Client, slug: str) -> dict[str, Any]:
59-
"""Call Node-RED's direct port, retrying while its HTTP server binds.
58+
async def _flows_request(
59+
mcp: Client, slug: str, *, port: int | None = None
60+
) -> dict[str, Any]:
61+
"""Call Node-RED, retrying while its HTTP stack settles after restart.
6062
6163
Supervisor reports ``started`` before the app's nginx binds the mapped
6264
direct port (CONNECTION_FAILED), and nginx binds before Node-RED itself
63-
listens on its upstream socket (502/503/504 with the front door open).
64-
Retry only those transient shapes until the app answers with a settled
65-
status; every other outcome goes back to the caller's assertions
65+
listens on its upstream socket (502/503/504). Core Ingress can expose the
66+
same window after Core's TLS restart, so both routes share this readiness
67+
gate. Retry only those transient shapes until the app answers with a
68+
settled status; every other outcome goes back to the caller's assertions
6669
unchanged.
6770
"""
68-
deadline = time.monotonic() + _DIRECT_PORT_READY_TIMEOUT_S
71+
deadline = time.monotonic() + _NODERED_HTTP_READY_TIMEOUT_S
72+
request: dict[str, Any] = {
73+
"slug": slug,
74+
"path": "/flows",
75+
"method": "GET",
76+
}
77+
if port is not None:
78+
request["port"] = port
6979
while True:
7080
payload = await safe_call_tool(
7181
mcp,
7282
"ha_manage_app",
73-
{"slug": slug, "path": "/flows", "method": "GET", "port": 1880},
83+
request,
7484
)
7585
error = payload.get("error")
7686
code = error.get("code") if isinstance(error, dict) else None
@@ -84,6 +94,16 @@ async def _direct_flows_request(mcp: Client, slug: str) -> dict[str, Any]:
8494
await asyncio.sleep(3)
8595

8696

97+
async def _direct_flows_request(mcp: Client, slug: str) -> dict[str, Any]:
98+
"""Call Node-RED's direct port after its HTTP stack is ready."""
99+
return await _flows_request(mcp, slug, port=1880)
100+
101+
102+
async def _ingress_flows_request(mcp: Client, slug: str) -> dict[str, Any]:
103+
"""Call Node-RED through Core Ingress after its HTTP stack is ready."""
104+
return await _flows_request(mcp, slug)
105+
106+
87107
async def _set_front_door(
88108
mcp: Client, assertions: MCPAssertions, slug: str, enabled: bool
89109
) -> None:
@@ -218,10 +238,7 @@ async def test_manage_app_reproduces_legacy_tls_failure_then_uses_fix(
218238
assert "IP address mismatch" in mismatch, mismatch
219239
assert "127.0.0.1" in mismatch, mismatch
220240

221-
fixed_ingress = await assertions.call_tool_success(
222-
"ha_manage_app",
223-
{"slug": slug, "path": "/flows", "method": "GET"},
224-
)
241+
fixed_ingress = await _ingress_flows_request(mcp, slug)
225242
assert fixed_ingress.get("success") is True, fixed_ingress
226243
assert fixed_ingress.get("status_code") == 200, fixed_ingress
227244
assert isinstance(fixed_ingress.get("response"), list), fixed_ingress

tests/src/unit/test_haos_supervisor_wait.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -768,8 +768,7 @@ def test_supervisor_update_retry_caps_sleep_to_remaining_budget() -> None:
768768
"/supervisor/update", method="post", timeout=1.0
769769
)
770770
assert [
771-
wait_call.kwargs["update_timeout"]
772-
for wait_call in wait_ready.call_args_list
771+
wait_call.kwargs["update_timeout"] for wait_call in wait_ready.call_args_list
773772
] == [1.0, 0.0]
774773
ws.reconnect.assert_called_once_with(deadline=1.0)
775774
sleep.assert_called_once_with(0.25)

0 commit comments

Comments
 (0)