diff --git a/tests/applications/modelling_e2e/test_handler.py b/tests/applications/modelling_e2e/test_handler.py index 511fc3d69..2a01e258f 100644 --- a/tests/applications/modelling_e2e/test_handler.py +++ b/tests/applications/modelling_e2e/test_handler.py @@ -386,6 +386,73 @@ def test_skipped_cohort_certs_fail_the_subtask_but_the_plan_is_still_saved() -> mock_uow.commit.assert_called_once() +def test_skipped_cohort_certs_are_logged_and_handler_does_not_raise() -> None: + """Unmappable cohort certs are logged but do not raise — the coordinator + SubTask completes normally and the property plan is committed.""" + from repositories.comparable_properties.epc_comparable_properties_repository import ( + SkippedCohortCert, + ) + + mock_engine = _engine_mock([PROPERTY_ID], [UPRN], [POSTCODE]) + mock_plan = _plan_mock() + mock_uow = MagicMock() + skipped = [ + SkippedCohortCert( + certificate_number="8257-7539-1649-0633-4992", + error="ValueError: RdSapSchema17_1: missing required field 'window'", + ) + ] + + with ExitStack() as stack: + stack.enter_context(patch("applications.modelling_e2e.handler.os.environ", _ENV)) + stack.enter_context( + patch("applications.modelling_e2e.handler._get_engine", return_value=mock_engine) + ) + stack.enter_context( + patch("applications.modelling_e2e.handler.EpcClientService") + ).return_value.get_by_uprn.return_value = MagicMock() + stack.enter_context(patch("applications.modelling_e2e.handler.GeospatialS3Repository")) + stack.enter_context(patch("applications.modelling_e2e.handler.GoogleSolarApiClient")) + stack.enter_context( + patch("applications.modelling_e2e.handler._spatial_for", return_value=None) + ) + stack.enter_context( + patch("applications.modelling_e2e.handler._solar_insights_for", return_value=None) + ) + stack.enter_context( + patch("applications.modelling_e2e.handler.overlays_from", return_value=[]) + ) + stack.enter_context(patch("applications.modelling_e2e.handler.PropertyOverridesPostgresReader")) + stack.enter_context( + patch("applications.modelling_e2e.handler.ScenarioPostgresRepository") + ).return_value.get_many.return_value = [MagicMock()] + stack.enter_context(patch("applications.modelling_e2e.handler.catalogue_with_off_catalogue_overrides")) + stack.enter_context(patch("applications.modelling_e2e.handler.Session")) + stack.enter_context( + patch("applications.modelling_e2e.handler.run_modelling", return_value=mock_plan) + ) + stack.enter_context( + patch("applications.modelling_e2e.handler.EpcComparablePropertiesRepository") + ).return_value.skipped = skipped + MockUoW = stack.enter_context(patch("applications.modelling_e2e.handler.PostgresUnitOfWork")) + MockUoW.return_value.__enter__.return_value = mock_uow + MockUoW.return_value.__exit__.return_value = False + mock_logger = stack.enter_context( + patch("applications.modelling_e2e.handler.logger") + ) + + # Act — must not raise even though cohort certs were skipped + _call_handler(_BODY) + + # Assert — plan committed; skipped cert number surfaced in a log call + mock_uow.plan.save.assert_called_once() + mock_uow.commit.assert_called_once() + logged_messages = " ".join( + str(c.args) + str(c.kwargs) for c in mock_logger.info.call_args_list + ) + assert "8257-7539-1649-0633-4992" in logged_messages + + # --------------------------------------------------------------------------- # EPC Prediction path # ---------------------------------------------------------------------------