Files
the-nexus/tests/test_mempalace_retain_closets.py

140 lines
4.3 KiB
Python
Raw Normal View History

"""
Tests for mempalace/retain_closets.py 90-day closet retention enforcement.
Refs: #1083, #1075
"""
from __future__ import annotations
import json
import time
from pathlib import Path
import pytest
from mempalace.retain_closets import (
RetentionResult,
_file_age_days,
enforce_retention,
)
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
def _write_closet(directory: Path, name: str, age_days: float) -> Path:
"""Create a *.closet.json file with a mtime set to *age_days* ago."""
p = directory / name
p.write_text(json.dumps({"drawers": [{"text": "summary", "closet": True}]}))
# Set mtime to simulate age
mtime = time.time() - age_days * 86400.0
import os
os.utime(p, (mtime, mtime))
return p
# ---------------------------------------------------------------------------
# _file_age_days
# ---------------------------------------------------------------------------
def test_file_age_days_recent(tmp_path):
p = tmp_path / "recent.closet.json"
p.write_text("{}")
age = _file_age_days(p)
assert 0 <= age < 1 # just created
def test_file_age_days_old(tmp_path):
p = _write_closet(tmp_path, "old.closet.json", age_days=100)
age = _file_age_days(p)
assert 99 < age < 101
# ---------------------------------------------------------------------------
# enforce_retention — dry_run
# ---------------------------------------------------------------------------
def test_dry_run_does_not_delete(tmp_path):
old = _write_closet(tmp_path, "old.closet.json", age_days=100)
_write_closet(tmp_path, "new.closet.json", age_days=10)
result = enforce_retention(tmp_path, retention_days=90, dry_run=True)
# File still exists after dry-run
assert old.exists()
assert result.removed == 1 # counted but not actually removed
assert result.kept == 1
assert result.ok
def test_dry_run_keeps_recent_files(tmp_path):
_write_closet(tmp_path, "recent.closet.json", age_days=5)
result = enforce_retention(tmp_path, retention_days=90, dry_run=True)
assert result.removed == 0
assert result.kept == 1
# ---------------------------------------------------------------------------
# enforce_retention — live mode
# ---------------------------------------------------------------------------
def test_live_removes_old_closets(tmp_path):
old = _write_closet(tmp_path, "old.closet.json", age_days=100)
new = _write_closet(tmp_path, "new.closet.json", age_days=10)
result = enforce_retention(tmp_path, retention_days=90, dry_run=False)
assert not old.exists()
assert new.exists()
assert result.removed == 1
assert result.kept == 1
assert result.ok
def test_live_keeps_files_within_window(tmp_path):
f = _write_closet(tmp_path, "edge.closet.json", age_days=89)
result = enforce_retention(tmp_path, retention_days=90, dry_run=False)
assert f.exists()
assert result.removed == 0
assert result.kept == 1
def test_empty_directory_is_ok(tmp_path):
result = enforce_retention(tmp_path, retention_days=90)
assert result.scanned == 0
assert result.removed == 0
assert result.ok
def test_subdirectory_closets_are_pruned(tmp_path):
"""enforce_retention should recurse into subdirs (wing directories)."""
sub = tmp_path / "bezalel"
sub.mkdir()
old = _write_closet(sub, "hermes.closet.json", age_days=120)
result = enforce_retention(tmp_path, retention_days=90, dry_run=False)
assert not old.exists()
assert result.removed == 1
def test_non_closet_files_ignored(tmp_path):
"""Non-closet files should not be counted or touched."""
(tmp_path / "readme.txt").write_text("hello")
(tmp_path / "data.drawer.json").write_text("{}")
result = enforce_retention(tmp_path, retention_days=90)
assert result.scanned == 0
# ---------------------------------------------------------------------------
# RetentionResult.ok
# ---------------------------------------------------------------------------
def test_retention_result_ok_with_no_errors():
r = RetentionResult(scanned=5, removed=2, kept=3)
assert r.ok is True
def test_retention_result_not_ok_with_errors():
r = RetentionResult(errors=["could not stat file"])
assert r.ok is False