# SPDX-License-Identifier: AGPL-3.0-only # Copyright (c) 2026 sol pbc from __future__ import annotations import threading import pytest import solstone.think.deferred_deletes as deferred_deletes @pytest.fixture(autouse=True) def cleanup_deferred_deletes(): yield for pending_id in list(deferred_deletes._TIMERS): deferred_deletes.cancel(pending_id) def test_schedule_runs_commit_once_after_ttl(): committed = [] done = threading.Event() def commit(): committed.append("ran") done.set() deferred_deletes.schedule(commit, ttl_seconds=0.05) assert done.wait(0.3) assert committed == ["ran"] def test_cancel_prevents_commit(): committed = [] deferred_id = deferred_deletes.schedule( lambda: committed.append("ran"), ttl_seconds=1.0, ) with deferred_deletes._LOCK: timer = deferred_deletes._TIMERS[deferred_id] assert deferred_deletes.cancel(deferred_id) is True timer.function(*timer.args, **timer.kwargs) assert committed == [] def test_double_cancel_returns_false_after_first(): deferred_id = deferred_deletes.schedule(lambda: None, ttl_seconds=1.0) assert deferred_deletes.cancel(deferred_id) is True assert deferred_deletes.cancel(deferred_id) is False def test_cancel_unknown_id_returns_false(): assert deferred_deletes.cancel("0" * 32) is False def test_cancel_commit_race_runs_at_most_once(): iterations = 50 for _ in range(iterations): commit_count = 0 commit_lock = threading.Lock() commit_event = threading.Event() start = threading.Event() cancel_results = [] def commit(): nonlocal commit_count with commit_lock: commit_count += 1 commit_event.set() deferred_id = deferred_deletes.schedule(commit, ttl_seconds=0.05) with deferred_deletes._LOCK: timer = deferred_deletes._TIMERS[deferred_id] def attempt_cancel(): start.wait() cancel_results.append(deferred_deletes.cancel(deferred_id)) threads = [threading.Thread(target=attempt_cancel) for _ in range(8)] for thread in threads: thread.start() start.set() for thread in threads: thread.join() true_cancels = sum(cancel_results) if true_cancels: timer.join(timeout=0.1) assert not timer.is_alive() assert not commit_event.is_set() else: assert commit_event.wait(0.1) assert commit_count in (0, 1) assert not (true_cancels and commit_count) assert (true_cancels == 1 and commit_count == 0) or ( true_cancels == 0 and commit_count == 1 ) def test_scheduled_timers_are_daemon_threads(): deferred_id = deferred_deletes.schedule(lambda: None, ttl_seconds=1.0) with deferred_deletes._LOCK: timer = deferred_deletes._TIMERS[deferred_id] assert timer.daemon is True