This commit is contained in:
Mateusz Gruszczyński committed 2026-11-07 13:13:25 +01:00
1 parent 3a384baa6b
commit 672c84bc13
21 files changed
+450 -70

No files matched your search

+95
View File
@@ -0,0 +1,95 @@
#!/usr/bin/env python3
"""Static integrity checks for the embedded administration interface.
The test intentionally uses only the Python standard library. It verifies the
actual HTML assembly and JavaScript files embedded by src/admin/router.rs; it is
not a replacement for Rust/browser integration tests.
"""
from __future__ import annotations
from collections import Counter
from pathlib import Path
import re
ROOT = Path(__file__).resolve().parents[1]
WEB = ROOT / "src/admin/web"
ROUTER = (ROOT / "src/admin/router.rs").read_text(encoding="utf-8")
def assembled_html() -> str:
html = (WEB / "index.html").read_text(encoding="utf-8")
metrics = (WEB / "partials/overview-metrics.html").read_text(encoding="utf-8")
charts = (WEB / "partials/overview-charts.html").read_text(encoding="utf-8")
metrics_main, metrics_web = metrics.split("<!-- RP_METRICS_SPLIT -->", 1)
charts_main, charts_web = charts.split("<!-- RP_CHARTS_SPLIT -->", 1)
return (
html.replace("<!-- RP_METRICS_MAIN -->", metrics_main)
.replace("<!-- RP_METRICS_WEB -->", metrics_web)
.replace("<!-- RP_CHARTS_MAIN -->", charts_main)
.replace("<!-- RP_CHARTS_WEB -->", charts_web)
)
def embedded_app_sources() -> list[Path]:
start = ROUTER.index("fn admin_app_javascript()")
end = ROUTER.index("fn admin_vhosts_javascript()", start)
app_block = ROUTER[start:end]
paths = [WEB / rel for rel in re.findall(r'include_str!\("web/([^"\n]+\.js)"\)', app_block)]
vstart = end
vend = ROUTER.index("pub fn router", vstart)
vhost_block = ROUTER[vstart:vend]
vhost_paths = [WEB / rel for rel in re.findall(r'include_str!\("web/([^"\n]+\.js)"\)', vhost_block)]
result: list[Path] = []
for path in [*paths, *vhost_paths]:
if path not in result:
result.append(path)
return result
def attribute_values(html: str, name: str) -> set[str]:
return set(re.findall(rf'\b{re.escape(name)}=["\']([^"\']+)', html))
html = assembled_html()
ids = re.findall(r'\bid=["\']([^"\']+)', html)
duplicates = sorted(name for name, count in Counter(ids).items() if count > 1)
assert not duplicates, f"duplicate panel DOM ids: {duplicates}"
id_set = set(ids)
sources = embedded_app_sources()
assert sources, "no embedded administration JavaScript sources found"
missing_files = [str(path.relative_to(ROOT)) for path in sources if not path.is_file()]
assert not missing_files, f"missing embedded JS sources: {missing_files}"
literal_refs: dict[str, set[str]] = {}
patterns = [
re.compile(r'\$\(["\']([^"\']+)["\']\)'),
re.compile(r'document\.getElementById\(["\']([^"\']+)["\']\)'),
]
for path in sources:
source = path.read_text(encoding="utf-8")
for pattern in patterns:
for dom_id in pattern.findall(source):
literal_refs.setdefault(dom_id, set()).add(str(path.relative_to(ROOT)))
missing_refs = {dom_id: sorted(paths) for dom_id, paths in literal_refs.items() if dom_id not in id_set}
assert not missing_refs, f"embedded panel JS references missing DOM ids: {missing_refs}"
# Every visible primary navigation target must have a panel section. filelogs is
# intentionally opened from the Logs menu rather than the main navigation.
panel_targets = attribute_values(html, "data-panel")
panel_sections = {value.removeprefix("panel-") for value in id_set if value.startswith("panel-")}
assert panel_targets <= panel_sections, f"navigation targets without panels: {sorted(panel_targets - panel_sections)}"
assert panel_sections - panel_targets <= {"filelogs"}, f"unexpected orphan panels: {sorted(panel_sections - panel_targets)}"
# Tab/page contracts used by the generic tab handlers in the embedded JS.
for prefix in ("settings", "policy-settings", "cache-settings", "logging-settings", "traffic"):
tabs = attribute_values(html, f"data-{prefix}-tab")
pages = attribute_values(html, f"data-{prefix}-page")
assert tabs == pages, f"{prefix} tab/page mismatch: tabs={sorted(tabs - pages)}, pages={sorted(pages - tabs)}"
print(
f"Panel interface contract: OK ({len(ids)} unique DOM ids, "
f"{len(literal_refs)} literal JS references, {len(sources)} embedded JS files)"
)