Skip to content

Commit 4e5268c

Browse files
test: make the plan expiry tests fail when the clock is wrong (#5079)
Copilot review on #5100: the two fixes made the tests pass, but not fail when the bug returns. Both clocks normally read close to the same value, and an expiry of now_utc + 8h is only wrong once they have drifted more than 8 hours apart - so between roughly 11:00 and 20:00 the buggy implementations passed as well, and a revert would go unnoticed for most of the working day. Confirmed by mutation test rather than assumed: reinstating the old save_plan() left plan_persistence passing. Each test now pins now_utc a year away from real time, in the direction that exposes its own mistake - back for the round trip (a now_utc-derived expiry is then already past, so the plan fails to load) and forward for the stale-plan check (a now_utc-derived "past" expiry is then still ahead of real time, so the plan loads when it should not). Both mutations are now caught at any hour. now_utc needs no restoring here: each test gets a fresh PredBat (#5102). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent 59e0e5a commit 4e5268c

1 file changed

Lines changed: 15 additions & 3 deletions

File tree

‎apps/predbat/tests/test_plan_persistence.py‎

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,14 @@ def test_plan_persistence(my_predbat):
4747
storage = _make_storage(my_predbat, tmpdir)
4848
my_predbat.components = _MockComponents(storage)
4949

50+
# Drive the fixture clock a long way from the real one for the round trip below. Both
51+
# clocks agreeing is what let the wrong-clock bug hide: an expiry of now_utc + 8h is
52+
# only wrong once the two have drifted more than 8 hours apart, so with the fixture
53+
# pinned near real time the test passed either way for most of the day. Pinned a year
54+
# back, save_plan() computing expiry from now_utc always writes an already-expired
55+
# plan and Test 1 fails at any hour.
56+
my_predbat.now_utc = datetime.now(timezone.utc) - timedelta(days=365)
57+
5058
# --- build a representative plan ---
5159
charge_windows = [{"start": 480, "end": 600, "average": 14.5}]
5260
charge_limits = [8.5]
@@ -165,6 +173,12 @@ def test_plan_persistence(my_predbat):
165173
storage3 = _make_storage(my_predbat, tmpdir3)
166174
my_predbat.components = _MockComponents(storage3)
167175

176+
# Opposite pin to Test 1: a fixture clock in the future, so building the "already
177+
# expired" timestamp from now_utc would put it ahead of real time and the plan
178+
# would load. That makes the wrong-clock version of the line below fail at any
179+
# hour rather than only before ~11:00 local.
180+
my_predbat.now_utc = datetime.now(timezone.utc) + timedelta(days=365)
181+
168182
plan_data = {
169183
"charge_window_best": [{"start": 120, "end": 240, "average": 10.0}],
170184
"charge_limit_best": [5.0],
@@ -174,9 +188,7 @@ def test_plan_persistence(my_predbat):
174188
"plan_last_updated_minutes": 60,
175189
}
176190
# Expiry has to be in the past relative to the clock storage.load() actually checks
177-
# against, which is the real one - my_predbat.now_utc is pinned to the fixture's
178-
# midday, so "an hour before that" is still in the future for any run before ~11:00
179-
# local, and the plan would load rather than be rejected as stale (#5079).
191+
# against, which is the real one rather than Predbat's (#5079).
180192
past_expiry = datetime.now(timezone.utc) - timedelta(hours=1)
181193
run_async(storage3.save("predbat", "plan", plan_data, format="json", expiry=past_expiry))
182194

0 commit comments

Comments
 (0)