File size: 7,056 Bytes
0e3b21f 77edebf 0e3b21f 77edebf 0e3b21f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 | """Unit tests for the report-proxy route and the inline iframe viewer.
The Space exposes two paths for the per-submission HTML report:
- ``/reports/{submission_id}.html`` (FastAPI route): re-serves the
file with ``Content-Type: text/html``. Works under Bearer auth
for programmatic clients; gets 404'd by HF's edge for logged-in
browser users on a private Space (no auth carryover across
same-origin pathname navigations). Kept as a backdoor / for the
future public migration.
- ``_format_detail_and_report`` (row-click handler): server-side
fetches the report via ``hf_hub_download`` and inlines it into
an ``<iframe srcdoc=...>``. No browser HTTP request → no edge
auth gate → renders for any logged-in user.
Tests stub the Hub fetch via monkeypatch so the suite has zero
network I/O.
"""
from __future__ import annotations
import re
import types
import pandas as pd
import app
def test_serve_report_returns_html_when_file_exists(monkeypatch):
"""Successful fetch -> 200 + text/html + body passthrough."""
monkeypatch.setattr(
app,
"_fetch_report_html",
lambda sid: b"<!DOCTYPE html><html><body>ok</body></html>",
)
resp = app.serve_report("sub-test")
assert resp.status_code == 200
assert resp.media_type.startswith("text/html")
assert resp.body == b"<!DOCTYPE html><html><body>ok</body></html>"
def test_serve_report_returns_404_when_file_missing(monkeypatch):
"""``_fetch_report_html`` returning None -> 404 with a small html body."""
monkeypatch.setattr(app, "_fetch_report_html", lambda sid: None)
resp = app.serve_report("sub-missing")
assert resp.status_code == 404
# 404 body is still HTML so the browser renders the message.
assert "Report not found" in resp.body.decode("utf-8")
def test_fetch_report_html_returns_none_on_hub_failure(monkeypatch):
"""A Hub-side exception is caught and surfaced as None.
The serve handler relies on this to keep a transient Hub blip
from leaking a stack trace into the Space's HTTP response.
"""
def boom(*a, **kw):
raise RuntimeError("simulated Hub failure")
monkeypatch.setattr(app, "hf_hub_download", boom)
# The lru_cache on _fetch_report_html caches by arg; use a unique
# id per test so prior runs don't shortcut this one.
assert app._fetch_report_html("sub-failure-probe-unique-1") is None
def test_proxy_route_is_registered():
"""The mounted FastAPI app exposes ``/reports/{submission_id}.html`` as GET.
Catches the regression where the ``add_api_route`` call moves
below ``mount_gradio_app`` (which would still register the route
but make this regression silent until someone tries to hit it).
"""
routes = [getattr(r, "path", None) for r in app.app.routes]
assert "/reports/{submission_id}.html" in routes
# --- Inline iframe viewer (_format_detail_and_report) ----------------
def _stub_row(**overrides):
base = {
"submission_id": "sub-test-x",
"submission_name": "Test Agent",
"submitter_name": "team-test",
"status": "completed",
"submitted_at": "2026-05-26T12:02:31Z",
"notes": None,
"model details (optional)": "_None_",
"submission_blob_url": "https://example.test/sub-test-x.zip",
"report_url": "/reports/sub-test-x.html",
"failure_reason": None,
}
base.update(overrides)
return pd.DataFrame([base])
def _fake_evt(idx=0):
"""Minimal stand-in for gr.SelectData with the .index attr we read."""
return types.SimpleNamespace(index=[idx, 0])
def test_iframe_viewer_inlines_report_for_modern_row(monkeypatch):
"""A completed modern row's HTML lands inside <iframe srcdoc>.
Confirms the fetched bytes are HTML-escaped (so `<html>` is not
re-parsed by the host page) and the iframe carries explicit
sizing so Gradio's column flex can't clip it vertically.
"""
monkeypatch.setattr(
app, "_fetch_report_html",
lambda sid: b"<!DOCTYPE html><body><h1>Report for " + sid.encode() + b"</h1></body>",
)
df = _stub_row()
md, iframe = app._format_detail_and_report(df, _fake_evt())
assert "### Test Agent" in md
assert iframe.startswith('<iframe srcdoc="')
# HTML-escaped content: literal "<!DOCTYPE html>" becomes
# "<!DOCTYPE html>" inside the attribute.
assert "<!DOCTYPE html>" in iframe
assert "sub-test-x" in iframe
assert 'style="width:100%; height:90vh; border:0; display:block;"' in iframe
def test_iframe_viewer_empty_for_pending_or_failed_row(monkeypatch):
"""Rows without a report_url get an empty viewer (no iframe at all).
Pending: still evaluating; no report exists yet. Failed: eval
crashed; no report uploaded. Legacy: pre-modern-pipeline; the
file genuinely doesn't exist on the dataset. All three are
handled by the same `report_url == ""` gate.
"""
monkeypatch.setattr(app, "_fetch_report_html", lambda sid: b"unused")
for row_overrides in [
{"status": "pending", "report_url": ""},
{"status": "failed", "report_url": "", "failure_reason": "boom"},
{"status": "completed", "report_url": ""}, # legacy
]:
df = _stub_row(**row_overrides)
md, iframe = app._format_detail_and_report(df, _fake_evt())
assert iframe == "", f"expected empty viewer for {row_overrides}"
# The metadata panel still renders.
assert "### Test Agent" in md
def test_iframe_viewer_falls_back_to_empty_when_fetch_fails(monkeypatch):
"""If _fetch_report_html returns None (Hub blip), no iframe is emitted.
Avoids surfacing a broken iframe on a transient failure.
"""
monkeypatch.setattr(app, "_fetch_report_html", lambda sid: None)
df = _stub_row()
_md, iframe = app._format_detail_and_report(df, _fake_evt())
assert iframe == ""
def test_iframe_viewer_returns_placeholder_on_null_event():
"""A null SelectData (no row clicked) returns placeholder + empty viewer."""
df = _stub_row()
fake = types.SimpleNamespace(index=None)
md, iframe = app._format_detail_and_report(df, fake)
assert md == app.DETAIL_PLACEHOLDER
assert iframe == ""
def test_iframe_escape_is_attribute_safe(monkeypatch):
"""Quotes / ampersands inside the report HTML are escaped properly.
A `"` inside the report would otherwise terminate the srcdoc
attribute prematurely and break parsing. Regression guard.
"""
monkeypatch.setattr(
app, "_fetch_report_html",
lambda sid: b'<html><body>tag: <a href="https://x.test">x</a> & co.</body></html>',
)
df = _stub_row()
_md, iframe = app._format_detail_and_report(df, _fake_evt())
# Within the srcdoc value, double-quotes must be HTML-escaped.
srcdoc = re.search(r'srcdoc="(.*)"\s+style=', iframe, re.DOTALL)
assert srcdoc is not None
inner = srcdoc.group(1)
# No unescaped " inside the attribute value.
assert '"' not in inner
assert """ in inner
assert "&" in inner
|