from datetime import UTC, datetime, timedelta from pathlib import Path from unittest.mock import patch import pytest from pydantic import ValidationError from src import app from src.config import _Settings def get_cutoff_timestamp(retention_days: int) -> int: now = datetime.now(UTC) today_midnight = now.replace(hour=0, minute=0, second=0, microsecond=0) return int((today_midnight - timedelta(days=retention_days)).timestamp()) class TestSettings: def test_rejects_nonexistent_path(self) -> None: with pytest.raises(ValidationError): _Settings(EFS_PATH=Path("/nonexistent/path"), EFS_RETENTION_DAYS=7) class TestCleanupOldEfsDirectories: def test_ignores_non_directory_with_timestamp_name(self, tmp_path: Path) -> None: old_timestamp = get_cutoff_timestamp(8) file_path = tmp_path / str(old_timestamp) file_path.write_text("test") app.cleanup_old_efs_directories(tmp_path, 7) assert file_path.exists() def test_raises_error_for_non_numeric_directories(self, tmp_path: Path) -> None: non_numeric_dir = tmp_path / "some-delivery" non_numeric_dir.mkdir() with pytest.raises(RuntimeError, match="Non-numeric EFS directory name"): app.cleanup_old_efs_directories(tmp_path, 7) assert non_numeric_dir.exists() def test_deletes_directory_one_second_older_than_cutoff( self, tmp_path: Path ) -> None: cutoff = get_cutoff_timestamp(7) old_dir = tmp_path / str(cutoff - 1) old_dir.mkdir() (old_dir / "file.txt").write_text("test") app.cleanup_old_efs_directories(tmp_path, 7) assert not old_dir.exists() def test_keeps_directory_at_exact_cutoff(self, tmp_path: Path) -> None: cutoff = get_cutoff_timestamp(7) boundary_dir = tmp_path / str(cutoff) boundary_dir.mkdir() app.cleanup_old_efs_directories(tmp_path, 7) assert boundary_dir.exists() def test_raises_error_on_delete_failure(self, tmp_path: Path) -> None: cutoff = get_cutoff_timestamp(7) old_dir = tmp_path / str(cutoff - 1) old_dir.mkdir() with ( patch( "shutil.rmtree", side_effect=PermissionError("denied"), ), pytest.raises(RuntimeError, match="Failed to delete"), ): app.cleanup_old_efs_directories(tmp_path, 7) class TestHandler: def test_succeeds(self, tmp_path: Path) -> None: settings = _Settings(EFS_PATH=tmp_path, EFS_RETENTION_DAYS=7) with patch.object(app, "get_settings", return_value=settings): app.handler(None, None) def test_reraises_cleanup_failure(self, tmp_path: Path) -> None: settings = _Settings(EFS_PATH=tmp_path, EFS_RETENTION_DAYS=7) with ( patch.object(app, "get_settings", return_value=settings), patch.object( app, "cleanup_old_efs_directories", side_effect=RuntimeError("oopsies"), ), pytest.raises(RuntimeError, match="oopsies"), ): app.handler(None, None)