"""Tests for the metadata block added to /api/results//export. Pins the contract introduced by the migration-0014 PR: - Response includes a top-level ``metadata`` dict with ``ldr_version``, ``started_at`` (ISO-8601), and ``settings_snapshot``. - Pre-0014 rows return null for the new fields without crashing the JS. - ``success: True`` envelope is preserved (5 JS callsites depend on it — see benchmark_results.html lines 95, 348, 556, 661, 722). - ``started_at`` falls back to ``created_at`` when ``start_time`` is null (e.g. a run that was created but never reached IN_PROGRESS). - ``settings_snapshot`` round-trips as a JSON object — secrets are expected to already be redacted at insert time, but this endpoint doesn't re-redact, so we assert the round-trip preserves the dict. """ # allow: no-sut-import — exercises the SUT indirectly through helpers # (_make_app, _make_export_query_router, _patch_auth_and_db, …) imported # from tests.benchmarks.web_api.test_benchmark_routes_coverage, which in # turn imports from local_deep_research. from datetime import datetime, UTC from unittest.mock import MagicMock # Import helpers from the existing coverage suite. from tests.benchmarks.web_api.test_benchmark_routes_coverage import ( _FakeDatasetType, _make_app, _make_export_query_router, _make_run_mock, _patch_auth_and_db, ) def _result_row(): r = MagicMock() r.example_id = "ex0" r.dataset_type = _FakeDatasetType.SIMPLEQA r.question = "Q?" r.correct_answer = "A" r.extracted_answer = "A" r.is_correct = True r.confidence = 0.9 r.processing_time = 5.0 r.completed_at = datetime(2025, 1, 1, tzinfo=UTC) return r def test_metadata_includes_ldr_version(): app = _make_app() with _patch_auth_and_db() as (_svc, _mgr, mock_db): mock_db.query.side_effect = _make_export_query_router( run=_make_run_mock(ldr_version="1.6.10"), results=[_result_row()], ) with app.test_client() as client: with client.session_transaction() as sess: sess["username"] = "testuser" resp = client.get("/benchmark/api/results/1/export") assert resp.status_code == 200 body = resp.get_json() assert body["metadata"]["ldr_version"] == "1.6.10" def test_metadata_started_at_uses_start_time_when_set(): app = _make_app() start_dt = datetime(2026, 5, 1, 12, 30, 0, tzinfo=UTC) with _patch_auth_and_db() as (_svc, _mgr, mock_db): mock_db.query.side_effect = _make_export_query_router( run=_make_run_mock(start_time=start_dt), results=[_result_row()], ) with app.test_client() as client: with client.session_transaction() as sess: sess["username"] = "testuser" resp = client.get("/benchmark/api/results/1/export") body = resp.get_json() assert body["metadata"]["started_at"] == start_dt.isoformat() def test_metadata_started_at_falls_back_to_created_at(): """If a run was created but never started, started_at falls back to created_at so the YAML still has a date_tested anchor.""" app = _make_app() run = _make_run_mock() # start_time defaults to None with _patch_auth_and_db() as (_svc, _mgr, mock_db): mock_db.query.side_effect = _make_export_query_router( run=run, results=[_result_row()] ) with app.test_client() as client: with client.session_transaction() as sess: sess["username"] = "testuser" resp = client.get("/benchmark/api/results/1/export") body = resp.get_json() assert body["metadata"]["started_at"] == run.created_at.isoformat() def test_metadata_settings_snapshot_round_trip(): """The snapshot is returned only when opted in via ?include_settings=1.""" app = _make_app() snapshot = { "llm.model": {"value": "qwen3.6:27b", "ui_element": "select"}, "search.fetch.mode": { "value": "summary_focus_query", "ui_element": "select", }, } with _patch_auth_and_db() as (_svc, _mgr, mock_db): mock_db.query.side_effect = _make_export_query_router( run=_make_run_mock(settings_snapshot=snapshot), results=[_result_row()], ) with app.test_client() as client: with client.session_transaction() as sess: sess["username"] = "testuser" resp = client.get( "/benchmark/api/results/1/export?include_settings=1" ) body = resp.get_json() assert body["metadata"]["settings_snapshot"] == snapshot def test_metadata_settings_snapshot_omitted_by_default(): """Without the opt-in flag, the snapshot is NOT transferred — the default summary download stays lean and doesn't ship the full config.""" app = _make_app() snapshot = {"llm.model": {"value": "qwen3.6:27b", "ui_element": "select"}} with _patch_auth_and_db() as (_svc, _mgr, mock_db): mock_db.query.side_effect = _make_export_query_router( run=_make_run_mock(settings_snapshot=snapshot), results=[_result_row()], ) with app.test_client() as client: with client.session_transaction() as sess: sess["username"] = "testuser" resp = client.get("/benchmark/api/results/1/export") body = resp.get_json() assert body["metadata"]["settings_snapshot"] is None def test_pre_0014_row_returns_null_metadata_fields(): """A row with all new columns NULL must serialize as JSON null, not crash, and not omit the metadata block.""" app = _make_app() run = _make_run_mock() # all provenance fields default to None run.created_at = None # full pre-0014 — even created_at unset with _patch_auth_and_db() as (_svc, _mgr, mock_db): mock_db.query.side_effect = _make_export_query_router( run=run, results=[] ) with app.test_client() as client: with client.session_transaction() as sess: sess["username"] = "testuser" resp = client.get("/benchmark/api/results/1/export") body = resp.get_json() assert body["metadata"] == { "ldr_version": None, "started_at": None, "settings_snapshot": None, } def test_run_not_found_returns_null_metadata(): """Missing run still returns a metadata block (all None) so the JS code path doesn't need a separate not-found branch.""" app = _make_app() with _patch_auth_and_db() as (_svc, _mgr, mock_db): mock_db.query.side_effect = _make_export_query_router( run=None, results=[] ) with app.test_client() as client: with client.session_transaction() as sess: sess["username"] = "testuser" resp = client.get("/benchmark/api/results/1/export") assert resp.status_code == 200 body = resp.get_json() assert body["success"] is True assert body["metadata"]["ldr_version"] is None assert body["metadata"]["settings_snapshot"] is None assert body["results"] == [] def test_success_field_preserved_for_back_compat(): """5 JS callsites in benchmark_results.html check `data.success` — removing it would silently break the UI.""" app = _make_app() with _patch_auth_and_db() as (_svc, _mgr, mock_db): mock_db.query.side_effect = _make_export_query_router( run=_make_run_mock(ldr_version="1.6.10"), results=[_result_row()], ) with app.test_client() as client: with client.session_transaction() as sess: sess["username"] = "testuser" resp = client.get("/benchmark/api/results/1/export") body = resp.get_json() assert body["success"] is True