OffGridSchedula / tests /test_agent_endpoint.py
ParetoOptimal's picture
Initial Commit
0366d65
Raw
History Blame Contribute Delete
3.62 kB
"""The /agent endpoint + autonomous /ingest (route functions called directly)."""
import base64
import pytest
from fastapi import HTTPException
import app as app_module
from app import agent, ingest
from calendar_out.ics import events_to_ics
from server import dedup, events as bus
from server.pipeline import AgentRequest
from server.schema import Event
TOKEN = "Bearer test-token" # matches conftest INGEST_TOKEN
@pytest.fixture(autouse=True)
def _clean():
dedup.reset()
yield
dedup.reset()
def test_agent_requires_token():
with pytest.raises(HTTPException) as e:
agent(AgentRequest(thread="lunch 1pm tomorrow"), authorization="")
assert e.value.status_code == 401
def test_agent_returns_plan():
resp = agent(AgentRequest(thread="lunch 1pm tomorrow"), authorization=TOKEN)
assert len(resp.plan.events) == 1
assert resp.plan.events[0].start # ISO start present
def test_agent_return_ics():
resp = agent(AgentRequest(thread="lunch 1pm tomorrow", return_ics=True), authorization=TOKEN)
assert resp.ics_base64
assert b"BEGIN:VEVENT" in base64.b64decode(resp.ics_base64)
def test_agent_detects_conflict_from_existing_ics():
# stub turns "lunch 1pm tomorrow" (now=Jun 5) into Jun 6 13:00-14:00
busy_ics = events_to_ics([Event(title="Standup", start="2026-06-06T13:00:00",
end="2026-06-06T14:00:00")])
resp = agent(
AgentRequest(
thread="lunch 1pm tomorrow",
now="2026-06-05T09:00:00",
existing_ics=base64.b64encode(busy_ics).decode(),
),
authorization=TOKEN,
)
assert resp.plan.conflicts
assert resp.plan.conflicts[0].severity == "overlap"
def _msg(text, chat="Mom"):
return {"chat": chat, "sender": chat, "text": text, "timestamp": "2026-06-05T10:00:00", "images": []}
def _ingest_and_flush(batch, authorization):
"""Call the route directly, then run its queued background tasks —
autonomous work now happens off the request (collector-timeout fix)."""
from fastapi import BackgroundTasks
bt = BackgroundTasks()
out = ingest(batch, bt, authorization=authorization)
for task in bt.tasks:
task.func(*task.args, **task.kwargs)
return out
def test_ingest_requires_token():
from app import IngestBatch
from fastapi import BackgroundTasks
with pytest.raises(HTTPException):
ingest(IngestBatch(messages=[]), BackgroundTasks(), authorization="")
def test_autonomous_ingest_dedupes(monkeypatch, tmp_path):
from app import IngestBatch
import calendar_out.gcal as gcal
monkeypatch.setattr(app_module, "AUTONOMOUS", True)
monkeypatch.setattr(app_module, "TRIGGER_ON", "any") # this test isn't about direction
monkeypatch.setattr(app_module, "FEED_PATH", tmp_path / "feed.json")
# events are only marked seen after a SUCCESSFUL push — stub one in
monkeypatch.setattr(gcal, "push_events",
lambda evs, calendar_id="primary": [""] * len(evs))
_ingest_and_flush(
IngestBatch(messages=[app_module.IngestMessage(**_msg("dinner 6pm tomorrow"))]),
authorization=TOKEN)
seen_after_first = len(dedup._load())
assert seen_after_first >= 1
# a follow-up message in the same chat must not re-create the same event
_ingest_and_flush(
IngestBatch(messages=[app_module.IngestMessage(**_msg("see you then"))]),
authorization=TOKEN)
assert len(dedup._load()) == seen_after_first