Files
hermes-webui/tests/test_issue1118_idle_session_retry.py
T

69 lines
3.1 KiB
Python

"""Tests for #1118 — api() retries on network errors (stale keep-alive after idle)."""
import re
def _src() -> str:
with open("static/workspace.js") as f:
return f.read()
class TestApiRetryOnNetworkError:
"""The api() function in workspace.js should retry on fetch TypeError (network failure)."""
def test_api_function_has_retry_loop(self):
"""api() must contain a retry loop (for/while with attempt counter)."""
src = _src()
assert re.search(r'for\s*\(\s*let\s+\w+\s*=\s*0\s*;', src), \
"api() must have a for loop with attempt counter"
def test_api_retries_on_typeerror(self):
"""api() must retry when fetch throws TypeError (network failure)."""
src = _src()
# Find the api function body
m = re.search(r'async function api\(path,opts.*?\n\}(?!\n[\s]*function)', src, re.DOTALL)
assert m, "api() function must exist"
body = m.group(0)
assert 'TypeError' in body, \
"api() must check for TypeError to detect network failures"
assert 'attempt' in body, \
"api() must track attempt count for retry logic"
def test_api_does_not_retry_http_errors(self):
"""api() must NOT retry on HTTP error responses (4xx/5xx) — only network failures."""
src = _src()
m = re.search(r'async function api\(path,opts.*?\n\}(?!\n[\s]*function)', src, re.DOTALL)
assert m, "api() function must exist"
body = m.group(0)
# The retry should be in catch block (after res.ok check), not in the ok path
# HTTP errors throw Error (not TypeError), so only TypeError triggers retry
assert 'e instanceof TypeError' in body, \
"api() retry must be limited to TypeError (network errors), not all errors"
def test_api_max_3_attempts(self):
"""api() must limit retries (max 3 attempts total = 1 initial + 2 retries)."""
src = _src()
m = re.search(r'async function api\(path,opts.*?\n\}(?!\n[\s]*function)', src, re.DOTALL)
assert m, "api() function must exist"
body = m.group(0)
# Should have attempt < 2 (0, 1, 2 = 3 attempts max)
assert re.search(r'attempt\s*<\s*2', body), \
"api() must limit to 3 attempts max (attempt < 2)"
def test_api_preserves_401_redirect(self):
"""api() must still redirect to login on 401 without escaping subpath mounts."""
src = _src()
assert "res.status===401" in src, \
"api() must still check for 401 status"
assert "login?next=" in src, \
"api() must still redirect to login on 401"
assert "/login?next=" not in src, \
"api() must not escape subpath mounts by redirecting to root /login"
def test_api_preserves_error_parsing(self):
"""api() must still parse JSON error bodies for non-200 responses."""
src = _src()
assert "JSON.parse(text)" in src, \
"api() must still parse JSON error responses"
assert "res.json()" in src, \
"api() must still parse JSON success responses"