Skip to content

Commit e7a25f5

Browse files
test(fetch): make Test 13 reproduce the repeated car_energy_reported_load warning (#5318 review)
Test 13 stubbed both history readers empty, so the check cleared the flag whatever the switch said and only the call count told pass from fail. It now feeds a load series that excludes the charger, captures the log, and runs live cycle (switch On, warns) -> comparison run (save=False, switch Off) -> next live cycle. Without the gate the comparison run clears the flag and the next live cycle logs the warning a second time; with it the warning is logged once. The docstring now says the fetch still sets the process-wide metrics() gauges rather than claiming nothing leaks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent a2c0856 commit e7a25f5

1 file changed

Lines changed: 42 additions & 14 deletions

File tree

‎apps/predbat/tests/test_car_energy_reported_load.py‎

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -196,28 +196,56 @@ def _test_fetch_only_checks_live_plan():
196196
"""
197197
Test 13: fetch_sensor_data() runs the check for the live plan (save=True) but not for compare.py's per-tariff
198198
re-fetches (save=False). A comparison tariff that turns car_energy_reported_load Off must not clear the live
199-
warned flag, or the warning would re-arm and fire again every comparison cycle.
199+
warned flag, or the warning would re-arm and be logged again after every comparison run.
200200
201-
Drives the real fetch_sensor_data() on a fresh PredBat, so nothing it resets leaks into the shared fixture (#5079).
201+
Drives the real fetch_sensor_data() on a fresh PredBat, so the attributes it resets do not leak into the shared
202+
fixture (#5079). It does still set the process-wide metrics() gauges (load/import/export/PV today, data age), as
203+
every fetch does; the metrics tests set their own values before reading them.
202204
"""
203205
# Imported here: unit_test imports this module
204206
from unit_test import create_predbat
205207

206208
print("Test 13: fetch_sensor_data() only runs the check for the live plan, not compare.py's save=False runs")
207209
failed = False
208210
fresh = create_predbat()
209-
# The test HA history carries no last_updated, so stand in empty sensor history for the history readers
210-
with patch.object(fresh, "minute_data_load", return_value=({}, 0)), patch.object(fresh, "minute_data_import_export", return_value={}), patch.object(fresh, "check_car_energy_reported_load", wraps=fresh.check_car_energy_reported_load) as checked:
211-
# As a comparison tariff config with the switch Off would leave it, after the live cycle has warned
212-
fresh.car_energy_reported_load = False
213-
fresh.car_energy_reported_load_warned = True
214-
fresh.fetch_sensor_data(save=False)
215-
if checked.call_count != 0 or not fresh.car_energy_reported_load_warned:
216-
print("ERROR: t13 save=False ran the check {} times, warned flag {}".format(checked.call_count, fresh.car_energy_reported_load_warned))
217-
failed = True
211+
# Sensor history where the charger is evidently outside the load sensor. The test HA history carries no
212+
# last_updated, so the history readers are stood in for: load_today and car_charging_energy get these series,
213+
# everything else nothing.
214+
_setup(fresh, load_includes_car=False)
215+
load_series = dict(fresh.load_minutes)
216+
car_series = dict(fresh.car_charging_energy)
217+
logged = []
218+
219+
def minute_data_load(now_utc, entity_name, *args, **kwargs):
220+
"""
221+
Stand-in for minute_data_load(): the load series for load_today, nothing for anything else.
222+
"""
223+
return (dict(load_series) if entity_name == "load_today" else {}), 0
224+
225+
def minute_data_import_export(max_days_previous, now_utc, key, *args, **kwargs):
226+
"""
227+
Stand-in for minute_data_import_export(): the car series for car_charging_energy, nothing for anything else.
228+
"""
229+
return dict(car_series) if key == "car_charging_energy" else {}
218230

219-
fresh.fetch_sensor_data(save=True)
220-
if checked.call_count != 1 or fresh.car_energy_reported_load_warned:
221-
print("ERROR: t13 save=True ran the check {} times, warned flag {}".format(checked.call_count, fresh.car_energy_reported_load_warned))
231+
def step(name, save, switch, calls, warnings, warned):
232+
"""
233+
Run one fetch with the switch as given and check the running totals of check calls and warnings, and the flag.
234+
"""
235+
nonlocal failed
236+
fresh.car_energy_reported_load = switch
237+
fresh.fetch_sensor_data(save=save)
238+
result = (checked.call_count, len(_warnings(logged)), fresh.car_energy_reported_load_warned)
239+
if result != (calls, warnings, warned):
240+
print("ERROR: t13 {} gave (check calls, warnings, warned flag) {}, expected {}".format(name, result, (calls, warnings, warned)))
222241
failed = True
242+
243+
with patch.object(fresh, "minute_data_load", side_effect=minute_data_load), patch.object(fresh, "minute_data_import_export", side_effect=minute_data_import_export), patch.object(
244+
fresh, "log", side_effect=lambda message, *args, **kwargs: logged.append(message)
245+
), patch.object(fresh, "check_car_energy_reported_load", wraps=fresh.check_car_energy_reported_load) as checked:
246+
fresh.car_energy_reported_load_warned = False
247+
step("live cycle", save=True, switch=True, calls=1, warnings=1, warned=True)
248+
# A comparison tariff whose config turns the switch Off
249+
step("comparison run", save=False, switch=False, calls=1, warnings=1, warned=True)
250+
step("next live cycle", save=True, switch=True, calls=2, warnings=1, warned=True)
223251
return failed

0 commit comments

Comments
 (0)