Guard against stale due_time overwrite (Feature 07 fix) (#87)
This commit was merged in pull request #87.
This commit is contained in:
@@ -545,7 +545,7 @@ def test_materialize_uses_single_presence_snapshot_mid_walk(tmp_path) -> None:
|
||||
_with_db(tmp_path, "materialize-presence-snapshot.db")(_body)
|
||||
|
||||
|
||||
def test_materialize_stores_snapshot_due_time_not_live(tmp_path) -> None:
|
||||
def test_materialize_skips_stale_due_time_mid_walk(tmp_path) -> None:
|
||||
async def _body(database):
|
||||
children = ChildrenDao(database)
|
||||
child = await children.create("Ada", NOW)
|
||||
@@ -566,21 +566,64 @@ def test_materialize_stores_snapshot_due_time_not_live(tmp_path) -> None:
|
||||
)
|
||||
|
||||
# The window's due_time is edited to 10:15 between the input
|
||||
# snapshot and the insert. The walk must store the SNAPSHOT's
|
||||
# 09:00, not the live 10:15 — the batch is governed entirely by
|
||||
# the coherent snapshot it read.
|
||||
# snapshot and the insert. The walk's snapshotted 09:00 no
|
||||
# longer matches the live 10:15, so the tuple is SKIPPED rather
|
||||
# than writing a due_time that has already been superseded.
|
||||
count = await _materialize_with_change(
|
||||
database, start_iso, end_iso, _edit_due_time
|
||||
)
|
||||
assert count == 3
|
||||
assert count == 0
|
||||
assert await QuestInstancesDao(database).list_by_date_range(
|
||||
child.id, start_iso, end_iso
|
||||
) == []
|
||||
return count
|
||||
|
||||
_with_db(tmp_path, "materialize-stale-due-time.db")(_body)
|
||||
|
||||
|
||||
def test_materialize_does_not_overwrite_regenerated_due_time(tmp_path) -> None:
|
||||
async def _body(database):
|
||||
children = ChildrenDao(database)
|
||||
child = await children.create("Ada", NOW)
|
||||
|
||||
today = datetime.date.today()
|
||||
start_iso = today.isoformat()
|
||||
end_iso = (today + datetime.timedelta(days=2)).isoformat()
|
||||
|
||||
created = await create_quest_definition(
|
||||
database,
|
||||
"Daily chore",
|
||||
ScheduleRule(rule_type=RuleType.DAILY, start_date=start_iso),
|
||||
[child.id],
|
||||
[("morning", "09:00")],
|
||||
)
|
||||
|
||||
async def _edit_and_regenerate():
|
||||
# A window-time edit + regeneration land after the stale walk
|
||||
# read its input snapshot: the window moves to 10:15 and the
|
||||
# regeneration upserts the newer due_time across the horizon.
|
||||
await QuestDefinitionsDao(database).upsert_window(
|
||||
created.definition.id, "morning", due_time="10:15"
|
||||
)
|
||||
await regenerate_for_definition(database, created.definition.id)
|
||||
|
||||
# The stale walk (snapshot due_time 09:00) then resumes. It must
|
||||
# SKIP these tuples — its snapshotted 09:00 no longer matches the
|
||||
# live 10:15 — so the regeneration's newer due_time survives and
|
||||
# is NOT overwritten by the stale value.
|
||||
count = await _materialize_with_change(
|
||||
database, start_iso, end_iso, _edit_and_regenerate
|
||||
)
|
||||
assert count == 0
|
||||
|
||||
records = await QuestInstancesDao(database).list_by_date_range(
|
||||
child.id, start_iso, end_iso
|
||||
)
|
||||
assert len(records) == 3
|
||||
assert {r.due_time for r in records} == {"09:00"}
|
||||
assert {r.due_time for r in records} == {"10:15"}
|
||||
return records
|
||||
|
||||
_with_db(tmp_path, "materialize-snapshot-due-time.db")(_body)
|
||||
_with_db(tmp_path, "materialize-regenerated-due-time.db")(_body)
|
||||
|
||||
|
||||
def test_materialize_honours_overrides(tmp_path) -> None:
|
||||
|
||||
Reference in New Issue
Block a user