mirror of
https://github.com/Akkudoktor-EOS/EOS.git
synced 2026-10-30 09:41:57 +00:00
fix(database): make delete_by_datetime(None, None) a true full wipe (#1476)
delete_by_datetime() with no bounds was documented as "delete all
records", but db_delete_records() assumed that
_db_ensure_loaded(start=None, end=None) loads every record into memory
before building the delete list. That is wrong: _db_ensure_loaded()
implements a NONE -> INITIAL -> FULL phase machine, and with both bounds
None in the NONE phase it loads only an *initial window* and leaves the
phase at INITIAL. Records outside that window never enter
_db_sorted_timestamps, so they are never marked for deletion and survive
in the physical store. Symptom: after a "wipe", db_count_records() still
returned N records (observed: 4 leftovers from a previous dense fixture).
A second delete_by_datetime() call happened to escalate INITIAL -> FULL
and deleted the rest, which is why the bug looked intermittent and why
stacked test runs accumulated rows.
Fix: in db_delete_records(), when both bounds are None, call
self._db_load_full() directly; otherwise keep the existing
_db_ensure_loaded(start, end) path. The delete list is then complete and
the "wipe" fixture actually wipes.
delete_by_datetime() remains a soft delete (rows are only added to
_db_deleted_timestamps; the physical DELETE happens on the next flush),
unchanged by this commit.
Besides this an additional fix was added:
* fix(tests): assert UTC-instant ordering in test_timestamps_remain_sorted
The test asserted `dts == sorted(dts)` on seq.records[].date_time, which
are tz-aware DateTime values in Europe/Berlin. Compaction buckets on a
UTC grid but records are materialized in local time, so across a DST
fall-back the local wall-clock sequence is non-monotonic even though the
UTC instants are ordered (e.g. 00:45 UTC -> 02:45 CEST, 01:00 UTC ->
02:00 CET). sorted() compares wall-clock fields, so it flags the pair at
the seam (index 1248 on 2026-10-25 for Europe/Berlin) as out of order.
The assertion is unsatisfiable for any 15-min grid spanning a fall-back
boundary when records are labelled in local time.
The actual invariant is "ascending by UTC instant", which is what
_db_sorted_timestamps guarantees and what the adjacent alignment tests
already assert via int(rec.date_time.timestamp()). Change the assertion
to compare integer UTC epochs:
epochs = [int(r.date_time.timestamp()) for r in seq.records if r.date_time]
assert epochs == sorted(epochs)
Note: this test was seasonally flaky. It only fails while a DST
transition lies inside the [now - 4 weeks, now] window used by
dense_energy_seq, which is why it newly started failing without any code
change. Upstream should ideally emit compacted records in UTC (or order
by UTC instant) so that wall-clock ordering is not silently assumed.
Signed-off-by: Bobby Noelte <b0661n0e17e@gmail.com>
This commit is contained in:
@@ -672,8 +672,15 @@ class TestDataSequenceCompactIntegrity:
|
||||
seq, _ = dense_energy_seq
|
||||
await seq.db_compact()
|
||||
|
||||
dts = [r.date_time for r in seq.records if r.date_time is not None]
|
||||
assert dts == sorted(dts)
|
||||
# Use UTC timestamp to account for DST change in records sequence
|
||||
epochs = [
|
||||
int(r.date_time.timestamp())
|
||||
for r in seq.records
|
||||
if r.date_time is not None
|
||||
]
|
||||
assert epochs == sorted(epochs), (
|
||||
"Records must be ascending by UTC instant after compaction"
|
||||
)
|
||||
|
||||
async def test_compacted_old_timestamps_on_1h_boundaries(self, dense_energy_seq):
|
||||
"""Records older than the floored 2-week cutoff must be on whole-hour UTC boundaries.
|
||||
|
||||
Reference in New Issue
Block a user