Files
odysseus/tests/test_calendar_rrule.py
lekt8 80de69ebb0 feat: document rrule in the manage_calendar tool schema (#1320) (#1324)
* feat: document rrule in the manage_calendar tool schema (#1320)

The create_event handler already persists `rrule` (a single event carrying an
iCalendar RRULE), but the manage_calendar tool schema didn't list it, so the
agent had no documented way to make a recurring event and took a roundabout
path. Add `rrule?` to the create_event field list with examples
(FREQ=WEEKLY;BYDAY=MO etc.) and an explicit note to create ONE event with the
rule rather than looping.

Covered by tests/test_calendar_rrule.py: do_manage_calendar create_event with an
rrule stores one event with that recurrence; without it, the event is single.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test: restore SessionLocal via monkeypatch in #1320 rrule test (review)

Per review: the test patched core.database.SessionLocal at module import and
never restored it, which could leak the temp DB into later tests in the same
process. Move the patch into an autouse monkeypatch fixture so it is restored
after each test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 02:37:45 +09:00

80 lines
2.5 KiB
Python

"""Issue #1320 — the agent's manage_calendar tool can create a recurring event.
The create_event handler already persists `rrule`, but it wasn't documented in the
tool schema, so the agent took "a roundabout way". This pins the end-to-end path:
calling do_manage_calendar with an rrule stores a single event carrying that RRULE.
"""
import json
import tempfile
import uuid
import pytest
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.pool import NullPool
import core.database as cdb
from core.database import CalendarEvent
_TMPDB = tempfile.NamedTemporaryFile(suffix=".db", delete=False)
_ENGINE = create_engine(
f"sqlite:///{_TMPDB.name}",
connect_args={"check_same_thread": False},
poolclass=NullPool,
)
cdb.Base.metadata.create_all(_ENGINE)
_TS = sessionmaker(bind=_ENGINE, autoflush=False, autocommit=False)
@pytest.fixture(autouse=True)
def _bind_temp_db(monkeypatch):
# do_manage_calendar does `from core.database import SessionLocal` at call
# time, so patch the module attribute to our temp DB — via monkeypatch so it
# is RESTORED after each test and can't leak into later tests in the process.
monkeypatch.setattr(cdb, "SessionLocal", _TS)
yield
async def test_create_event_with_rrule_persists_recurrence():
from src.tool_implementations import do_manage_calendar
owner = "tester-" + uuid.uuid4().hex[:6]
rrule = "FREQ=WEEKLY;BYDAY=MO"
res = await do_manage_calendar(json.dumps({
"action": "create_event",
"summary": "Standup",
"dtstart": "2026-06-08T09:00:00Z",
"rrule": rrule,
}), owner=owner)
assert res.get("exit_code", 0) == 0, res
uid = res.get("uid")
assert uid, res
db = _TS()
try:
ev = db.query(CalendarEvent).filter(CalendarEvent.uid == uid).first()
assert ev is not None
assert ev.rrule == rrule # ONE event carrying the recurrence rule
assert ev.summary == "Standup"
finally:
db.close()
async def test_create_event_without_rrule_is_single():
from src.tool_implementations import do_manage_calendar
owner = "tester-" + uuid.uuid4().hex[:6]
res = await do_manage_calendar(json.dumps({
"action": "create_event",
"summary": "One-off",
"dtstart": "2026-06-09T10:00:00Z",
}), owner=owner)
assert res.get("exit_code", 0) == 0, res
db = _TS()
try:
ev = db.query(CalendarEvent).filter(CalendarEvent.uid == res["uid"]).first()
assert ev is not None and (ev.rrule or "") == ""
finally:
db.close()