37 lines
1.1 KiB
Python
37 lines
1.1 KiB
Python
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)
|