from __future__ import annotations from dataclasses import dataclass from datetime import UTC, datetime, timedelta import pytest from backup_tool.retention import RetentionError, RetentionPolicy, retained_ids @dataclass class Backup: id: str created_at: datetime pinned: bool = False tombstoned_at: datetime | None = None def test_retention_is_union_and_protects_newest() -> None: now = datetime(2026, 7, 29, tzinfo=UTC) backups = [Backup(str(index), now - timedelta(days=index)) for index in range(6)] backups[-1].pinned = True kept = retained_ids(backups, RetentionPolicy(keep_last=2, keep_daily=3), now) assert {"0", "1", "2", "5"} <= kept def test_newest_is_kept_even_when_policy_is_zero() -> None: now = datetime(2026, 7, 29, tzinfo=UTC) assert retained_ids([Backup("new", now)], RetentionPolicy(keep_last=0), now) == {"new"} @pytest.mark.parametrize("policy", [{"keep_last": -1}, {"unknown": 1}, {"keep_days": True}]) def test_invalid_retention_policy_is_rejected(policy: dict[str, object]) -> None: with pytest.raises(RetentionError): RetentionPolicy.from_dict(policy)