mirror of
https://github.com/Akkudoktor-EOS/EOS.git
synced 2026-10-29 09:11:57 +00:00
test: consolidate suites and remove redundant cases (#1459)
Regression tests were scattered across feature- and bug-specific files, and some suites repeated the same checks. Group tests by responsibility, isolate feature fixtures in test classes, and remove duplicate or obsolete cases. The review covered all 127 collected test modules on main. This reduces them and removes or combines definitions:. No application code changes.
This commit is contained in:
@@ -14,7 +14,11 @@ from akkudoktoreos.optimization.genetic.genetic import (
|
||||
_release_freed_memory,
|
||||
_unpack_genes,
|
||||
)
|
||||
from akkudoktoreos.utils.datetimeutil import to_datetime
|
||||
from akkudoktoreos.optimization.genetic.geneticparams import (
|
||||
GeneticEnergyManagementParameters,
|
||||
GeneticOptimizationParameters,
|
||||
)
|
||||
from akkudoktoreos.utils.datetimeutil import DateTime, compare_datetimes, to_datetime
|
||||
|
||||
|
||||
def _configure_hourly_grid(config_eos: ConfigEOS, *, start_hour: int = 0) -> None:
|
||||
@@ -527,3 +531,125 @@ def test_offspring_do_not_inherit_immigrant_protection(config_eos: ConfigEOS):
|
||||
]
|
||||
offspring = opt._make_offspring(parents, 8, mutation_probability=1.0)
|
||||
assert all(getattr(child, "immigrant_protection", 0) == 0 for child in offspring)
|
||||
|
||||
|
||||
def _warm_start_optimizer(
|
||||
config_eos: ConfigEOS,
|
||||
*,
|
||||
interval: int,
|
||||
optimize_ev: bool = False,
|
||||
n_appliance_genes: int = 0,
|
||||
) -> tuple[GeneticOptimization, DateTime]:
|
||||
config_eos.merge_settings_from_dict(
|
||||
{
|
||||
"prediction": {"hours": 48},
|
||||
"optimization": {
|
||||
"genetic": {"tail_horizon_hours": 0, "horizon_hours": 24, "interval_sec": interval}
|
||||
},
|
||||
}
|
||||
)
|
||||
slot0 = get_ems(init=True).set_start_datetime(to_datetime().set(hour=8, minute=0, second=0))
|
||||
opt = GeneticOptimization(fixed_seed=42)
|
||||
opt.optimize_ev = optimize_ev
|
||||
opt.appliance_layout = SimpleNamespace(n_genes=n_appliance_genes, genes=[]) # type: ignore[assignment]
|
||||
opt._slot0_datetime = slot0
|
||||
return opt, slot0
|
||||
|
||||
|
||||
def _warm_start_genes(start: int, stop: int) -> list[float]:
|
||||
return [float(value) for value in range(start, stop)]
|
||||
|
||||
|
||||
class TestWarmStartAlignment:
|
||||
def test_quarter_hour_warm_start_moves_one_slot_forward(self, config_eos: ConfigEOS):
|
||||
# 07:45 run: export genes (32) at 08:00 and 08:15. Unshifted, the 08:00 run
|
||||
# would read them as 08:15 and 08:30.
|
||||
opt, slot0 = _warm_start_optimizer(config_eos, interval=900)
|
||||
previous = [19.0, 32.0, 32.0, 14.0] + [36.0] * (opt.control_slots - 4)
|
||||
|
||||
aligned = opt._start_solution_for_run_start(previous, slot0.subtract(minutes=15))
|
||||
|
||||
assert aligned == [32, 32, 14] + [36] * (opt.control_slots - 3)
|
||||
|
||||
def test_elapsed_slots_are_dropped_per_block_and_appliance_genes_kept(self, config_eos: ConfigEOS):
|
||||
opt, slot0 = _warm_start_optimizer(config_eos, interval=3600, optimize_ev=True, n_appliance_genes=1)
|
||||
slots = opt.control_slots
|
||||
battery = _warm_start_genes(0, slots)
|
||||
ev = _warm_start_genes(100, 100 + slots)
|
||||
appliance = [3.0]
|
||||
|
||||
aligned = opt._start_solution_for_run_start(battery + ev + appliance, slot0.subtract(hours=3))
|
||||
|
||||
assert aligned == (
|
||||
_warm_start_genes(3, slots)
|
||||
+ [slots - 1.0] * 3
|
||||
+ _warm_start_genes(103, 100 + slots)
|
||||
+ [100 + slots - 1.0] * 3
|
||||
+ appliance
|
||||
)
|
||||
|
||||
def test_same_slot_or_unknown_start_keeps_warm_start(self, config_eos: ConfigEOS):
|
||||
opt, slot0 = _warm_start_optimizer(config_eos, interval=900)
|
||||
previous = _warm_start_genes(0, opt.control_slots)
|
||||
|
||||
assert opt._start_solution_for_run_start(previous, slot0) == previous
|
||||
assert opt._start_solution_for_run_start(previous, None) == previous
|
||||
assert opt._start_solution_for_run_start(None, slot0) is None
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"offset_minutes",
|
||||
[
|
||||
pytest.param(-24 * 60, id="all-control-slots-elapsed"),
|
||||
pytest.param(15, id="starts-after-this-run"),
|
||||
],
|
||||
)
|
||||
def test_unusable_warm_start_is_dropped(self, config_eos: ConfigEOS, offset_minutes: int):
|
||||
opt, slot0 = _warm_start_optimizer(config_eos, interval=900)
|
||||
previous = _warm_start_genes(0, opt.control_slots)
|
||||
|
||||
assert opt._start_solution_for_run_start(previous, slot0.add(minutes=offset_minutes)) is None
|
||||
|
||||
def test_start_datetime_falls_back_to_last_solution_of_this_server(self,
|
||||
config_eos: ConfigEOS, monkeypatch: pytest.MonkeyPatch
|
||||
):
|
||||
opt, slot0 = _warm_start_optimizer(config_eos, interval=900)
|
||||
last_start = slot0.subtract(minutes=15)
|
||||
monkeypatch.setattr(
|
||||
type(get_ems()),
|
||||
"_genetic_solution",
|
||||
SimpleNamespace(start_solution=[19.0, 32.0, 14.0], start_solution_datetime=last_start),
|
||||
)
|
||||
|
||||
same = SimpleNamespace(start_solution=[19, 32, 14], start_solution_datetime=None)
|
||||
other = SimpleNamespace(start_solution=[19, 32, 15], start_solution_datetime=None)
|
||||
explicit_start = slot0.subtract(minutes=30)
|
||||
explicit = SimpleNamespace(start_solution=[19, 32, 14], start_solution_datetime=explicit_start)
|
||||
|
||||
assert opt._resolve_start_solution_datetime(same) == last_start # type: ignore[arg-type]
|
||||
assert opt._resolve_start_solution_datetime(other) is None # type: ignore[arg-type]
|
||||
assert opt._resolve_start_solution_datetime(explicit) == explicit_start # type: ignore[arg-type]
|
||||
|
||||
def test_parameters_accept_iso_start_solution_datetime(self, config_eos: ConfigEOS):
|
||||
parameters = GeneticOptimizationParameters.model_validate(
|
||||
dict(
|
||||
ems=GeneticEnergyManagementParameters.model_validate(
|
||||
dict(
|
||||
pv_prognose_wh=[0.0, 0.0],
|
||||
strompreis_euro_pro_wh=[0.0, 0.0],
|
||||
einspeiseverguetung_euro_pro_wh=0.0,
|
||||
preis_euro_pro_wh_akku=0.0,
|
||||
gesamtlast=[0.0, 0.0],
|
||||
)
|
||||
),
|
||||
pv_akku=None,
|
||||
inverter=None,
|
||||
eauto=None,
|
||||
start_solution=[1.0, 2.0],
|
||||
start_solution_datetime="2026-09-14T07:45:00+02:00",
|
||||
)
|
||||
)
|
||||
|
||||
assert parameters.start_solution_datetime is not None
|
||||
assert compare_datetimes(
|
||||
parameters.start_solution_datetime, to_datetime("2026-09-14T07:45:00+02:00")
|
||||
).equal
|
||||
|
||||
Reference in New Issue
Block a user