"""HTML report for pulumi hybrid lab suite (pulumi-vsphere + REST + SOAP).""" from __future__ import annotations import html from datetime import UTC, datetime from pathlib import Path from typing import Any def _esc(value: Any) -> str: return html.escape(str(value), quote=True) def _section_rest(summary: dict[str, Any]) -> str: rest = summary.get("rest") or {} majors = rest.get("majors") or [] by_verb = rest.get("by_verb") or {} failures = rest.get("failures") or [] coverage = rest.get("coverage_line") or f"{(rest.get('probed') or 0) - (rest.get('critical') or 0)}/{rest.get('declared') or rest.get('total') or 0}" critical = rest.get("critical", rest.get("failed", 0)) major_rows = [] for m in majors: buckets = m.get("buckets") or {} deep = m.get("deep_vs_stub") or {} major_rows.append( "" f"{_esc(m.get('major'))}" f"{_esc(m.get('version'))}" f"{_esc(m.get('declared'))}" f"{_esc(m.get('probed'))}" f"{_esc(m.get('coverage_line') or '—')}" f"{_esc(m.get('critical', m.get('failed')))}" f"{_esc(buckets.get('success_2xx', 0))}" f"{_esc(buckets.get('client_4xx', 0))}" f"{_esc(buckets.get('server_5xx', 0))}" f"{_esc(deep.get('deep', 0))}/{_esc(deep.get('stub', 0))}" "" ) verb_bits = " · ".join(f"{_esc(k)}={_esc(v)}" for k, v in sorted(by_verb.items())) fail_rows = [] for f in failures[:40]: fail_rows.append( "" f"{_esc(f.get('major'))}" f"{_esc(f.get('verb'))}" f"{_esc(f.get('path'))}" f"{_esc(f.get('kind'))}" f"{_esc(f.get('status'))}" f"{_esc((f.get('body') or f.get('expected') or '')[:180])}" "" ) return f"""

REST HTTP contract matrix (Layer A)

coverage {_esc(coverage)} · critical={_esc(critical)} · probed={_esc(rest.get("probed") or rest.get("total"))} · declared={_esc(rest.get("declared"))} · verbs: {verb_bits or "—"}
100% = HTTP matrix (IMPLEMENTED × majors + HEAD), not pulumi-vsphere resource count.

{"".join(major_rows) or ''}
MajorVersionDeclaredProbedCoverage Critical2xx4xx5xxdeep/stub

REST critical failures (sample)

{"".join(fail_rows) or ''}
MajorVerbPathKindStatusDetail
none
""" def _section_crud(summary: dict[str, Any]) -> str: crud = summary.get("crud") or {} flows = crud.get("flows") or [] rows = [] for f in flows: rows.append( f"" f"{_esc(f.get('flow'))}" f"{_esc(f.get('step'))}" f"{_esc(f.get('status'))}" f"{_esc(f.get('error') or '—')}" f"" ) return f"""

Deep REST CRUD

total={_esc(crud.get("total"))} · failed={_esc(crud.get("failed"))}

{"".join(rows) or ''}
FlowStepStatusDetail
— (smoke skips CRUD)
""" def _section_soap(summary: dict[str, Any]) -> str: soap = summary.get("soap") or {} ops = soap.get("ops") or [] rows = [] for op in ops: status = "passed" if op.get("ok") else "failed" rows.append( f"" f"{_esc(op.get('op'))}" f"{_esc(op.get('status'))}" f"{_esc(status)}" f"{_esc(op.get('error') or '—')}" f"" ) return f"""

SOAP WSDL ops

total={_esc(soap.get("total"))} · failed={_esc(soap.get("failed"))}

{"".join(rows) or ''}
OperationHTTPStatusDetail
— (smoke skips SOAP)
""" def render_html(summary: dict[str, Any]) -> str: generated = summary.get("generated_at") or datetime.now(UTC).isoformat() cases = summary.get("cases") or [] total = len(cases) passed = sum(1 for c in cases if c.get("status") == "passed") failed = sum(1 for c in cases if c.get("status") == "failed") skipped = sum(1 for c in cases if c.get("status") == "skipped") rest = summary.get("rest") or {} crud = summary.get("crud") or {} soap = summary.get("soap") or {} rows = [] for case in cases: status = case.get("status") or "" outs = case.get("outputs") or {} out_html = "
".join(f"{_esc(k)}={_esc(v)}" for k, v in outs.items()) err = _esc(case.get("error") or "") rows.append( f"" f"{_esc(case.get('id'))}" f"{_esc(case.get('title'))}" f"{_esc(status)}" f"{out_html or '—'}" f"{err or '—'}" f"" ) return f""" pulumi hybrid lab report

pulumi hybrid lab suite

Generated {_esc(generated)} · server {_esc(summary.get("vsphere_server"))} · base {_esc(summary.get("vsphere_base"))} · smoke={_esc(summary.get("smoke"))}
Cases{total}
Passed{passed}
Failed{failed}
REST failed{_esc(rest.get("failed", 0))} / {_esc(rest.get("total", 0))} probes
CRUD failed{_esc(crud.get("failed", 0))} / {_esc(crud.get("total", 0))} flows
SOAP failed{_esc(soap.get("failed", 0))} / {_esc(soap.get("total", 0))} ops

Suite cases

{"".join(rows)}
IDTitleStatusOutputsError
{_section_rest(summary)} {_section_crud(summary)} {_section_soap(summary)}
""" def write_report(summary: dict[str, Any], path: Path) -> None: path.parent.mkdir(parents=True, exist_ok=True) path.write_text(render_html(summary), encoding="utf-8")