Files
hermes-webui/tests/test_dashboard_poll_visibility.py
7a1a122e6e Release Batch C: hidden-tab dashboard poll + SSE write-deadline + rate-limit map bound (#5840, #5841, #5842) (#5847)
Phase 2 low-risk backend/perf batch (ai-ag2026 reliability cluster). Each byte-verified
vs PR head, Codex SAFE, 33 own + 720 regression tests pass, disjoint routes.py regions.

- #5840: skip dashboard status poll while tab hidden (perf; forced polls unaffected)
- #5841: arm write deadline on session-events invalidation SSE (stuck-client teardown)
- #5842: bound client rate-limit maps by sweeping stale keys (long-uptime memory)

Co-authored-by: t <a@b>
Co-authored-by: ai-ag2026 <ai-ag2026@users.noreply.github.com>
2026-07-09 10:38:47 -07:00

105 lines
4.1 KiB
Python

"""Regression test — the dashboard status poll is skipped while the tab is hidden.
`_initDashboardLinkProbe` sets `setInterval(refreshDashboardStatus, 60000)`, and
the interval equals `DASHBOARD_STATUS_TTL_MS`, so every background tick was a
real `/api/dashboard/status` fetch that never hit the cache — a needless wakeup
on a tab nobody is looking at. It was the only frontend poll without a
`document.hidden` guard (the gateway / streaming / hidden-stream polls all skip
while hidden, #4704/#2476).
`refreshDashboardStatus` now short-circuits an unforced call while hidden, and
`_initDashboardLinkProbe` refreshes once on `visibilitychange` back to visible.
Forced calls (settings save, init, the catch-up) still run.
"""
import pathlib
import shutil
import subprocess
import tempfile
import textwrap
import pytest
REPO = pathlib.Path(__file__).parent.parent
UI_JS = (REPO / "static" / "ui.js").read_text(encoding="utf-8")
NODE = shutil.which("node")
requires_node = pytest.mark.skipif(NODE is None, reason="node not on PATH")
def test_guard_and_catchup_present():
# Guard lives inside refreshDashboardStatus (keeps the setInterval anchor).
assert "setInterval(refreshDashboardStatus,DASHBOARD_STATUS_TTL_MS)" in UI_JS
assert "if(!force&&typeof document!=='undefined'&&document.hidden){" in UI_JS
assert "visibilitychange" in UI_JS
_DRIVER = textwrap.dedent(
"""\
const fs = require('fs');
function extractFn(src, name) {
const markers = [`async function ${name}(`, `function ${name}(`];
let start = -1;
for (const m of markers) { start = src.indexOf(m); if (start >= 0) break; }
if (start < 0) throw new Error(`${name}() not found`);
let i = src.indexOf('{', start), depth = 0, s = null, esc = false, lc = false, bc = false;
for (; i < src.length; i++) {
const ch = src[i], nx = src[i + 1] || '';
if (lc) { if (ch === '\\n') lc = false; continue; }
if (bc) { if (ch === '*' && nx === '/') bc = false; continue; }
if (s) { if (esc) esc = false; else if (ch === '\\\\') esc = true; else if (ch === s) s = null; continue; }
if (ch === '/' && nx === '/') { lc = true; continue; }
if (ch === '/' && nx === '*') { bc = true; continue; }
if (ch === '\\'' || ch === '"' || ch === '`') { s = ch; continue; }
if (ch === '{') depth += 1;
if (ch === '}') { depth -= 1; if (depth === 0) return src.slice(start, i + 1); }
}
throw new Error(`could not extract ${name}`);
}
const uiSrc = fs.readFileSync(process.argv[2], 'utf8');
const hidden = process.argv[3] === 'hidden';
let fetches = 0;
global.document = { hidden };
global._dashboardStatusCache = null;
global._dashboardStatusFetchedAt = 0;
global.DASHBOARD_STATUS_TTL_MS = 60000;
global._applyDashboardStatus = () => {};
global.api = (url) => { if (String(url) === '/api/dashboard/status') fetches += 1; return Promise.resolve({ running: true }); };
eval(extractFn(uiSrc, 'refreshDashboardStatus'));
(async () => {
// Unforced call (what the interval does).
await refreshDashboardStatus();
// Forced call always runs regardless of visibility.
await refreshDashboardStatus(true);
console.log(JSON.stringify({ fetches }));
})();
"""
)
def _run(hidden):
with tempfile.NamedTemporaryFile("w", suffix=".js", delete=False) as f:
f.write(_DRIVER)
driver = f.name
out = subprocess.run(
[NODE, driver, str(REPO / "static" / "ui.js"), "hidden" if hidden else "visible"],
capture_output=True, text=True, timeout=30,
)
assert out.returncode == 0, out.stderr
import json
return json.loads(out.stdout.strip())
@requires_node
def test_hidden_tab_skips_unforced_poll_but_forced_still_runs():
r = _run(hidden=True)
# Only the forced call fetched; the unforced (interval) call was skipped.
assert r["fetches"] == 1, "hidden tab should skip the unforced poll"
@requires_node
def test_visible_tab_polls_normally():
r = _run(hidden=False)
# Both the unforced and forced calls fetched while visible.
assert r["fetches"] == 2, "visible tab should poll on both calls"