Model/tests/repositories/scenario/test_scenario_postgres_repository.py
Khalim Conn-Kowlessar c18968ba3c refactor(modelling): consolidate scenario + installed_measure into the subpackage
Move the scenario and installed_measure tables into
infrastructure/postgres/modelling/ as full-parity SQLModel definitions
(ScenarioModel, InstalledMeasureModel + MeasureType), completing the cluster
consolidation. backend/app/db/models/recommendations.py is now a pure
re-export shim.

ScenarioModel.goal is the PortfolioGoal enum (legacy planning branches on it),
sourced from domain/modelling/portfolio_goal.py; the repo's to_domain maps it to
its value string, so domain Scenario.goal is now the value ("Increasing EPC")
consistent with the orchestrator's check — fixing the latent name-vs-value
inconsistency the old str column masked (the scenario repo test stored the enum
*name*). Parity columns are nullable (mirror convention; live NOT-NULLs owned by
Drizzle).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 22:52:35 +00:00

86 lines
2.6 KiB
Python

"""Behaviour of the Postgres-backed ScenarioRepository: reading the Scenarios
the Modelling stage scores a Property against, off the live ``scenario`` table.
The FE creates a Scenario in the scenario-builder and passes its id to the
pipeline (#1130); the orchestrator reads it back here at modelling time. Only
the fields modelling uses are mapped — goal / goal_value / budget / is_default;
the legacy file-path columns are ignored. See CONTEXT.md (Scenario) and
ADR-0017.
"""
from __future__ import annotations
import pytest
from sqlalchemy import Engine
from sqlmodel import Session
from domain.modelling.portfolio_goal import PortfolioGoal
from domain.modelling.scenario import Scenario
from infrastructure.postgres.modelling import ScenarioModel
from repositories.scenario.scenario_postgres_repository import (
ScenarioPostgresRepository,
)
def test_get_many_maps_live_scenario_rows_to_domain_in_input_order(
db_engine: Engine,
) -> None:
# Arrange
with Session(db_engine) as session:
session.add(
ScenarioModel(
id=7,
goal=PortfolioGoal.INCREASING_EPC,
goal_value="C",
budget=15000.0,
is_default=True,
)
)
session.add(
ScenarioModel(
id=9,
goal=PortfolioGoal.INCREASING_EPC,
goal_value="B",
budget=None,
is_default=False,
)
)
session.commit()
# Act
with Session(db_engine) as session:
scenarios: list[Scenario] = ScenarioPostgresRepository(session).get_many(
[9, 7]
)
# Assert — to_domain maps the PortfolioGoal enum to its value string
assert [s.id for s in scenarios] == [9, 7] # input order preserved
assert scenarios[0] == Scenario(
id=9, goal="Increasing EPC", goal_value="B", budget=None, is_default=False
)
assert scenarios[1] == Scenario(
id=7,
goal="Increasing EPC",
goal_value="C",
budget=15000.0,
is_default=True,
)
def test_get_many_raises_when_a_scenario_id_is_missing(db_engine: Engine) -> None:
# Arrange
with Session(db_engine) as session:
session.add(
ScenarioModel(
id=7,
goal=PortfolioGoal.INCREASING_EPC,
goal_value="C",
is_default=True,
)
)
session.commit()
# Act / Assert
with Session(db_engine) as session:
with pytest.raises(ValueError):
ScenarioPostgresRepository(session).get_many([7, 404])