Revert "fix(events): tolerate corrupt end_dt + reject end<=start at write time"
This reverts commit 94b169f31c.
This commit is contained in:
@@ -124,92 +124,6 @@ async def test_update_event_fires_caldav_push():
|
||||
assert mock_task.called
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_event_rejects_end_before_start():
|
||||
"""Write-side validation: end_dt <= start_dt must raise rather than
|
||||
persisting invalid data. Discovered 2026-04-29: a tool-call mishap
|
||||
left an event with end_dt 32 days BEFORE start_dt; the bad data then
|
||||
made the event invisible to the upcoming-list filter. Catching at
|
||||
the boundary prevents the same shape from recurring."""
|
||||
from fabledassistant.services.events import create_event
|
||||
start = datetime(2026, 5, 1, 12, 0, tzinfo=timezone.utc)
|
||||
end_before = datetime(2026, 3, 30, 12, 0, tzinfo=timezone.utc)
|
||||
with pytest.raises(ValueError, match="must be after start_dt"):
|
||||
await create_event(
|
||||
user_id=1, title="Bad",
|
||||
start_dt=start, end_dt=end_before,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_event_rejects_end_equal_to_start():
|
||||
"""Equal start/end is also invalid (zero-duration); pass end=None
|
||||
for point events instead."""
|
||||
from fabledassistant.services.events import create_event
|
||||
same = datetime(2026, 5, 1, 12, 0, tzinfo=timezone.utc)
|
||||
with pytest.raises(ValueError, match="must be after start_dt"):
|
||||
await create_event(
|
||||
user_id=1, title="Zero",
|
||||
start_dt=same, end_dt=same,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_update_event_rejects_post_state_with_end_before_start():
|
||||
"""update_event must validate against the *post-update* state, not
|
||||
just the field passed in. A user changing only start_dt to a value
|
||||
after the existing end_dt would otherwise sneak past validation."""
|
||||
mock_event = _make_mock_event() # start = 2026-03-25 10:00, end = 11:00
|
||||
mock_session = _make_mock_session()
|
||||
mock_result = MagicMock()
|
||||
mock_result.scalar_one_or_none.return_value = mock_event
|
||||
mock_session.execute = AsyncMock(return_value=mock_result)
|
||||
|
||||
with patch("fabledassistant.services.events.async_session") as mock_cls:
|
||||
mock_cls.return_value = mock_session
|
||||
from fabledassistant.services.events import update_event
|
||||
# Push start_dt past the existing end_dt (without touching end_dt)
|
||||
with pytest.raises(ValueError, match="must be after start_dt"):
|
||||
await update_event(
|
||||
user_id=1, event_id=1,
|
||||
start_dt=datetime(2026, 3, 25, 12, 0, tzinfo=timezone.utc),
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_list_events_returns_event_with_invalid_end_dt():
|
||||
"""Filter robustness: an event whose end_dt landed before start_dt
|
||||
(corrupt data state from earlier bugs) must still surface in the
|
||||
upcoming list when its start_dt is in range. Without this, the
|
||||
event becomes invisible everywhere except via direct id lookup."""
|
||||
mock_event = _make_mock_event()
|
||||
# Corrupt state: end is 32 days BEFORE start
|
||||
mock_event.start_dt = datetime(2026, 5, 1, 12, 0, tzinfo=timezone.utc)
|
||||
mock_event.end_dt = datetime(2026, 3, 30, 12, 0, tzinfo=timezone.utc)
|
||||
mock_event.to_dict.return_value = {
|
||||
"id": 1, "title": "Corrupt event",
|
||||
"start_dt": mock_event.start_dt.isoformat(),
|
||||
"end_dt": mock_event.end_dt.isoformat(),
|
||||
}
|
||||
mock_session = _make_mock_session()
|
||||
mock_result = MagicMock()
|
||||
mock_result.scalars.return_value.all.return_value = [mock_event]
|
||||
mock_session.execute = AsyncMock(return_value=mock_result)
|
||||
|
||||
with patch("fabledassistant.services.events.async_session") as mock_cls:
|
||||
mock_cls.return_value = mock_session
|
||||
from fabledassistant.services.events import list_events
|
||||
# Window covers start_dt (May 1) but not end_dt (March 30).
|
||||
results = await list_events(
|
||||
user_id=1,
|
||||
date_from=datetime(2026, 4, 29, tzinfo=timezone.utc),
|
||||
date_to=datetime(2026, 5, 27, tzinfo=timezone.utc),
|
||||
)
|
||||
# Pre-fix: filter would exclude this event. Post-fix: present.
|
||||
assert len(results) == 1
|
||||
assert results[0]["id"] == 1
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_tools_calendar_always_available():
|
||||
"""Calendar tools must appear in get_tools_for_user even without CalDAV."""
|
||||
|
||||
Reference in New Issue
Block a user