From 62c0151469948e2fb3c8f062612a1520ed089fbc Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Tue, 14 Jul 2026 13:49:02 +0000 Subject: [PATCH] =?UTF-8?q?Fill=20partial=20summaries=20best-effort,=20fai?= =?UTF-8?q?l=20loudly,=20skip=20evidence-only=20jobs,=20and=20retry=20on?= =?UTF-8?q?=20Coordination=20Hub=20=F0=9F=9F=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) --- .../tests/test_pashub_service.py | 113 ++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/backend/pashub_fetcher/tests/test_pashub_service.py b/backend/pashub_fetcher/tests/test_pashub_service.py index d92c10979..aa8b6e2ce 100644 --- a/backend/pashub_fetcher/tests/test_pashub_service.py +++ b/backend/pashub_fetcher/tests/test_pashub_service.py @@ -783,3 +783,116 @@ def test_run_overlays_full_lodged_performance_onto_saved_site_notes() -> None: assert saved.current_energy_efficiency_band == Epc.C assert saved.co2_emissions_current == 1.70 assert saved.energy_consumption_current == 117 + + +def test_run_overlays_only_present_fields_when_summary_partial() -> None: + # Arrange — only the SAP rating comes back; CO2 and PEUI are null + mock_client = _site_note_client( + summary=RdSapSummary( + pre_sap_rating=78.0, + pre_current_co2_emissions=None, + pre_current_energy_consumption=None, + ) + ) + parsed = make_epc_property_data() + service = make_service(pashub_client=mock_client) + + # Act + with ( + patch("backend.pashub_fetcher.pashub_service.upload_file_to_s3"), + patch( + "backend.pashub_fetcher.pashub_service.parse_site_notes_pdf", + return_value=parsed, + ), + patch( + "backend.pashub_fetcher.pashub_service.save_epc_property_data" + ) as mock_save, + patch("backend.pashub_fetcher.pashub_service.db_session"), + patch("backend.pashub_fetcher.pashub_service.os.remove"), + ): + service.run(make_request(uprn="12345")) + + # Assert + saved: EpcPropertyData = mock_save.call_args[0][1] + assert saved.energy_rating_current == 78 + assert saved.current_energy_efficiency_band == Epc.C + assert saved.co2_emissions_current is None + assert saved.energy_consumption_current is None + + +def test_run_raises_and_skips_persistence_when_summary_fetch_fails() -> None: + # Arrange — the RdSAP Site Note is present but its summary cannot be fetched + mock_client = _site_note_client() + mock_client.get_rdsap_summary_by_job_id.side_effect = RuntimeError("summary down") + service = make_service(pashub_client=mock_client) + + # Act / Assert + with ( + patch("backend.pashub_fetcher.pashub_service.upload_file_to_s3") as mock_s3, + patch( + "backend.pashub_fetcher.pashub_service.save_epc_property_data" + ) as mock_save, + patch("backend.pashub_fetcher.pashub_service.db_session"), + patch("backend.pashub_fetcher.pashub_service.os.remove"), + ): + with pytest.raises(RuntimeError): + service.run(make_request(uprn="12345")) + + mock_save.assert_not_called() + mock_s3.assert_called() # S3 upload happened before the loud site-note save + + +def test_run_does_not_fetch_summary_for_evidence_only_job() -> None: + # Arrange — a plain Site Note (not an RdSAP Site Note) carries no summary + mock_client = _site_note_client(core=["/tmp/SiteNote_001.pdf"]) + service = make_service(pashub_client=mock_client) + + # Act + with ( + patch("backend.pashub_fetcher.pashub_service.upload_file_to_s3"), + patch("backend.pashub_fetcher.pashub_service.db_session"), + patch("backend.pashub_fetcher.pashub_service.os.remove"), + ): + service.run(make_request(uprn="12345")) + + # Assert + mock_client.get_rdsap_summary_by_job_id.assert_not_called() + + +def test_run_fetches_summary_from_coordination_client_on_primary_auth_failure() -> None: + # Arrange — primary credentials 401 on the summary; coordination succeeds + pas_client = _site_note_client() + pas_client.get_rdsap_summary_by_job_id.side_effect = UnauthorizedError() + + coord_client = MagicMock(spec=PashubClient) + coord_client.get_rdsap_summary_by_job_id.return_value = RdSapSummary( + pre_sap_rating=78.0, + pre_current_co2_emissions=1.70, + pre_current_energy_consumption=117.0, + ) + factory = MagicMock(return_value=coord_client) + + parsed = make_epc_property_data() + service = make_service( + pashub_client=pas_client, coordination_client_factory=factory + ) + + # Act + with ( + patch("backend.pashub_fetcher.pashub_service.upload_file_to_s3"), + patch( + "backend.pashub_fetcher.pashub_service.parse_site_notes_pdf", + return_value=parsed, + ), + patch( + "backend.pashub_fetcher.pashub_service.save_epc_property_data" + ) as mock_save, + patch("backend.pashub_fetcher.pashub_service.db_session"), + patch("backend.pashub_fetcher.pashub_service.os.remove"), + ): + service.run(make_request(uprn="12345")) + + # Assert + coord_client.get_rdsap_summary_by_job_id.assert_called_once() + saved: EpcPropertyData = mock_save.call_args[0][1] + assert saved.energy_rating_current == 78