189 lines
8.6 KiB
Python
189 lines
8.6 KiB
Python
"""Tests for CLI retention command."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from datetime import UTC, datetime
|
|
from unittest.mock import AsyncMock, MagicMock
|
|
|
|
import pytest
|
|
|
|
from noteflow.cli.retention import main, run_cleanup, show_status
|
|
|
|
|
|
class TestRunCleanup:
|
|
@pytest.mark.asyncio
|
|
async def test_run_cleanup_disabled_without_dry_run_returns_1(
|
|
self,
|
|
mock_retention_settings_disabled: MagicMock,
|
|
mock_retention_uow_factory: MagicMock,
|
|
) -> None:
|
|
assert mock_retention_settings_disabled is not None, (
|
|
"Retention settings fixture should be provided"
|
|
)
|
|
assert mock_retention_uow_factory is not None, "Retention UOW fixture should be provided"
|
|
result = await run_cleanup(dry_run=False)
|
|
assert result == 1, "Should return 1 when retention disabled and not dry-run"
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_run_cleanup_dry_run_proceeds_when_disabled(
|
|
self,
|
|
mock_retention_settings_disabled: MagicMock,
|
|
mock_retention_uow_factory: MagicMock,
|
|
mock_retention_service: MagicMock,
|
|
mock_retention_console: MagicMock,
|
|
) -> None:
|
|
assert mock_retention_settings_disabled is not None, (
|
|
"Retention settings fixture should be provided"
|
|
)
|
|
assert mock_retention_uow_factory is not None, "Retention UOW fixture should be provided"
|
|
assert mock_retention_console is not None, "Retention console fixture should be provided"
|
|
mock_retention_service.run_cleanup = AsyncMock(
|
|
return_value=MagicMock(meetings_checked=5, meetings_deleted=0, errors=[])
|
|
)
|
|
result = await run_cleanup(dry_run=True)
|
|
assert result == 0, "Dry-run should succeed even when retention disabled"
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_run_cleanup_success_returns_0(
|
|
self,
|
|
mock_retention_settings: MagicMock,
|
|
mock_retention_uow_factory: MagicMock,
|
|
mock_retention_service: MagicMock,
|
|
mock_retention_console: MagicMock,
|
|
) -> None:
|
|
assert mock_retention_settings is not None, "Retention settings fixture should be provided"
|
|
assert mock_retention_uow_factory is not None, "Retention UOW fixture should be provided"
|
|
assert mock_retention_console is not None, "Retention console fixture should be provided"
|
|
mock_retention_service.run_cleanup = AsyncMock(
|
|
return_value=MagicMock(meetings_checked=10, meetings_deleted=3, errors=[])
|
|
)
|
|
result = await run_cleanup(dry_run=False)
|
|
assert result == 0, "Should return 0 on successful cleanup"
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_run_cleanup_with_errors_returns_1(
|
|
self,
|
|
mock_retention_settings: MagicMock,
|
|
mock_retention_uow_factory: MagicMock,
|
|
mock_retention_service: MagicMock,
|
|
mock_retention_console: MagicMock,
|
|
) -> None:
|
|
assert mock_retention_settings is not None, "Retention settings fixture should be provided"
|
|
assert mock_retention_uow_factory is not None, "Retention UOW fixture should be provided"
|
|
assert mock_retention_console is not None, "Retention console fixture should be provided"
|
|
mock_retention_service.run_cleanup = AsyncMock(
|
|
return_value=MagicMock(
|
|
meetings_checked=10, meetings_deleted=2, errors=["Error 1", "Error 2"]
|
|
)
|
|
)
|
|
result = await run_cleanup(dry_run=False)
|
|
assert result == 1, "Should return 1 when errors occurred"
|
|
|
|
|
|
class TestShowStatus:
|
|
@pytest.mark.asyncio
|
|
async def test_show_status_returns_0(
|
|
self,
|
|
mock_retention_settings: MagicMock,
|
|
mock_retention_uow_factory: MagicMock,
|
|
mock_retention_service: MagicMock,
|
|
mock_retention_console: MagicMock,
|
|
) -> None:
|
|
assert mock_retention_settings is not None, "Retention settings fixture should be provided"
|
|
assert mock_retention_uow_factory is not None, "Retention UOW fixture should be provided"
|
|
assert mock_retention_console is not None, "Retention console fixture should be provided"
|
|
mock_retention_service.find_expired_meetings = AsyncMock(return_value=[])
|
|
result = await show_status()
|
|
assert result == 0, "Status should always return 0"
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_show_status_with_expired_meetings(
|
|
self,
|
|
mock_retention_settings: MagicMock,
|
|
mock_retention_uow_factory: MagicMock,
|
|
mock_retention_service: MagicMock,
|
|
mock_retention_console: MagicMock,
|
|
) -> None:
|
|
assert mock_retention_settings is not None, "Retention settings fixture should be provided"
|
|
assert mock_retention_uow_factory is not None, "Retention UOW fixture should be provided"
|
|
assert mock_retention_console is not None, "Retention console fixture should be provided"
|
|
meeting = MagicMock()
|
|
meeting.id = "test-id"
|
|
meeting.title = "Test Meeting"
|
|
meeting.ended_at = datetime(2024, 1, 1, tzinfo=UTC)
|
|
mock_retention_service.find_expired_meetings = AsyncMock(return_value=[meeting])
|
|
result = await show_status()
|
|
assert result == 0, "Status should return 0 even with pending deletions"
|
|
|
|
|
|
class TestMain:
|
|
def test_main_no_command_exits_with_1(self, argv_retention_no_command: None) -> None:
|
|
assert argv_retention_no_command is None, (
|
|
"argv_retention_no_command fixture should provide None"
|
|
)
|
|
with pytest.raises(SystemExit, match="1") as exc_info:
|
|
main()
|
|
assert exc_info.value.code == 1, "Should exit with 1 when no command"
|
|
|
|
def test_main_cleanup_command_calls_run_cleanup(
|
|
self,
|
|
argv_retention_cleanup: None,
|
|
mock_retention_settings: MagicMock,
|
|
mock_retention_uow_factory: MagicMock,
|
|
mock_retention_service: MagicMock,
|
|
mock_retention_console: MagicMock,
|
|
) -> None:
|
|
assert argv_retention_cleanup is None, "argv_retention_cleanup fixture should provide None"
|
|
assert mock_retention_settings is not None, "Retention settings fixture should be provided"
|
|
assert mock_retention_uow_factory is not None, "Retention UOW fixture should be provided"
|
|
assert mock_retention_console is not None, "Retention console fixture should be provided"
|
|
mock_retention_service.run_cleanup = AsyncMock(
|
|
return_value=MagicMock(meetings_checked=0, meetings_deleted=0, errors=[])
|
|
)
|
|
with pytest.raises(SystemExit, match="0") as exc_info:
|
|
main()
|
|
assert exc_info.value.code == 0, "Cleanup should exit with 0 on success"
|
|
|
|
def test_main_cleanup_dry_run_passes_flag(
|
|
self,
|
|
argv_retention_cleanup_dry_run: None,
|
|
mock_retention_settings_disabled: MagicMock,
|
|
mock_retention_uow_factory: MagicMock,
|
|
mock_retention_service: MagicMock,
|
|
mock_retention_console: MagicMock,
|
|
) -> None:
|
|
assert argv_retention_cleanup_dry_run is None, (
|
|
"argv_retention_cleanup_dry_run fixture should provide None"
|
|
)
|
|
assert mock_retention_settings_disabled is not None, (
|
|
"Retention settings fixture should be provided"
|
|
)
|
|
assert mock_retention_uow_factory is not None, "Retention UOW fixture should be provided"
|
|
assert mock_retention_console is not None, "Retention console fixture should be provided"
|
|
mock_retention_service.run_cleanup = AsyncMock(
|
|
return_value=MagicMock(meetings_checked=0, meetings_deleted=0, errors=[])
|
|
)
|
|
with pytest.raises(SystemExit, match="0") as exc_info:
|
|
main()
|
|
assert exc_info.value.code == 0, "Dry-run should succeed"
|
|
mock_retention_service.run_cleanup.assert_called_once_with(dry_run=True)
|
|
|
|
def test_main_status_command_calls_show_status(
|
|
self,
|
|
argv_retention_status_cmd: None,
|
|
mock_retention_settings: MagicMock,
|
|
mock_retention_uow_factory: MagicMock,
|
|
mock_retention_service: MagicMock,
|
|
mock_retention_console: MagicMock,
|
|
) -> None:
|
|
assert argv_retention_status_cmd is None, (
|
|
"argv_retention_status_cmd fixture should provide None"
|
|
)
|
|
assert mock_retention_settings is not None, "Retention settings fixture should be provided"
|
|
assert mock_retention_uow_factory is not None, "Retention UOW fixture should be provided"
|
|
assert mock_retention_console is not None, "Retention console fixture should be provided"
|
|
mock_retention_service.find_expired_meetings = AsyncMock(return_value=[])
|
|
with pytest.raises(SystemExit, match="0") as exc_info:
|
|
main()
|
|
assert exc_info.value.code == 0, "Status should exit with 0"
|