5fa203019a
log_work tool now invokes maybe_consolidate(reason='log_added') after a successful create_log. The gate inside the consolidation service handles threshold + setting checks. update_note service snapshots old_status before mutation and fires maybe_consolidate(reason='task_closed') when the status transitions into 'done' or 'cancelled'. Re-saving an already-terminal status doesn't retrigger — only transitions count.
119 lines
3.9 KiB
Python
119 lines
3.9 KiB
Python
"""Tests for the status-terminal consolidation trigger in update_note."""
|
|
from unittest.mock import AsyncMock, MagicMock, patch
|
|
|
|
|
|
def _mock_session_for_update(mock_note):
|
|
mock_session = AsyncMock()
|
|
mock_result = MagicMock()
|
|
mock_result.scalars.return_value.first.return_value = mock_note
|
|
mock_session.execute = AsyncMock(return_value=mock_result)
|
|
mock_session.commit = AsyncMock()
|
|
mock_session.refresh = AsyncMock()
|
|
mock_session.__aenter__ = AsyncMock(return_value=mock_session)
|
|
mock_session.__aexit__ = AsyncMock(return_value=False)
|
|
return mock_session
|
|
|
|
|
|
async def test_update_note_to_done_triggers_consolidation():
|
|
"""status: in_progress → done should fire maybe_consolidate(task_closed)."""
|
|
mock_note = MagicMock()
|
|
mock_note.id = 42
|
|
mock_note.status = "in_progress" # pre-update state
|
|
mock_note.body = ""
|
|
mock_note.title = ""
|
|
mock_note.tags = []
|
|
mock_note.started_at = None
|
|
mock_note.completed_at = None
|
|
mock_note.recurrence_rule = None
|
|
mock_note.project_id = None
|
|
|
|
with patch(
|
|
"fabledassistant.services.notes.async_session",
|
|
return_value=_mock_session_for_update(mock_note),
|
|
), patch(
|
|
"fabledassistant.services.consolidation.maybe_consolidate",
|
|
new=AsyncMock(),
|
|
) as mock_mc:
|
|
from fabledassistant.services.notes import update_note
|
|
await update_note(1, 42, status="done")
|
|
|
|
mock_mc.assert_awaited_once_with(1, 42, reason="task_closed")
|
|
|
|
|
|
async def test_update_note_to_cancelled_triggers_consolidation():
|
|
mock_note = MagicMock()
|
|
mock_note.id = 42
|
|
mock_note.status = "in_progress"
|
|
mock_note.body = ""
|
|
mock_note.title = ""
|
|
mock_note.tags = []
|
|
mock_note.started_at = None
|
|
mock_note.completed_at = None
|
|
mock_note.recurrence_rule = None
|
|
mock_note.project_id = None
|
|
|
|
with patch(
|
|
"fabledassistant.services.notes.async_session",
|
|
return_value=_mock_session_for_update(mock_note),
|
|
), patch(
|
|
"fabledassistant.services.consolidation.maybe_consolidate",
|
|
new=AsyncMock(),
|
|
) as mock_mc:
|
|
from fabledassistant.services.notes import update_note
|
|
await update_note(1, 42, status="cancelled")
|
|
|
|
mock_mc.assert_awaited_once_with(1, 42, reason="task_closed")
|
|
|
|
|
|
async def test_update_note_to_in_progress_does_not_trigger_consolidation():
|
|
"""Non-terminal status changes don't fire the trigger."""
|
|
mock_note = MagicMock()
|
|
mock_note.id = 42
|
|
mock_note.status = "todo"
|
|
mock_note.body = ""
|
|
mock_note.title = ""
|
|
mock_note.tags = []
|
|
mock_note.started_at = None
|
|
mock_note.completed_at = None
|
|
mock_note.recurrence_rule = None
|
|
mock_note.project_id = None
|
|
|
|
with patch(
|
|
"fabledassistant.services.notes.async_session",
|
|
return_value=_mock_session_for_update(mock_note),
|
|
), patch(
|
|
"fabledassistant.services.consolidation.maybe_consolidate",
|
|
new=AsyncMock(),
|
|
) as mock_mc:
|
|
from fabledassistant.services.notes import update_note
|
|
await update_note(1, 42, status="in_progress")
|
|
|
|
mock_mc.assert_not_awaited()
|
|
|
|
|
|
async def test_update_note_already_done_does_not_retrigger():
|
|
"""If the status was already 'done' and update_note(status='done') runs
|
|
again, no fresh trigger fires — only transitions count."""
|
|
mock_note = MagicMock()
|
|
mock_note.id = 42
|
|
mock_note.status = "done"
|
|
mock_note.body = ""
|
|
mock_note.title = ""
|
|
mock_note.tags = []
|
|
mock_note.started_at = None
|
|
mock_note.completed_at = None
|
|
mock_note.recurrence_rule = None
|
|
mock_note.project_id = None
|
|
|
|
with patch(
|
|
"fabledassistant.services.notes.async_session",
|
|
return_value=_mock_session_for_update(mock_note),
|
|
), patch(
|
|
"fabledassistant.services.consolidation.maybe_consolidate",
|
|
new=AsyncMock(),
|
|
) as mock_mc:
|
|
from fabledassistant.services.notes import update_note
|
|
await update_note(1, 42, status="done")
|
|
|
|
mock_mc.assert_not_awaited()
|