Incidents and Archive get a from/to date range (native date inputs, local-day bounds). Incidents filters in the Firestore query; Archive passes date_from/date_to to GET /calls/search, which applies them as a started_at range — both ride the existing org_id/started_at index. Also fixes /calls/search and /calls/eval-queue paging: the cursor went to Firestore as a raw ISO string against a timestamp field, which compares by type rather than time, so "Load more" re-read the first page. Cursor and range bounds are now parsed to datetimes (400 on garbage). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
36 lines
1.0 KiB
Python
36 lines
1.0 KiB
Python
"""calls._parse_ts — cursor/date bounds must reach Firestore as datetimes.
|
|
|
|
A raw ISO string compared against a timestamp field sorts by type, not time,
|
|
which made the Archive's "Load more" return the first page again.
|
|
"""
|
|
from datetime import datetime, timezone
|
|
|
|
import pytest
|
|
from fastapi import HTTPException
|
|
|
|
from app.routers.calls import _parse_ts
|
|
|
|
|
|
def test_empty_is_none():
|
|
assert _parse_ts(None, "cursor") is None
|
|
assert _parse_ts("", "cursor") is None
|
|
|
|
|
|
def test_z_suffix_parses_as_utc():
|
|
assert _parse_ts("2026-09-20T12:00:00Z", "date_from") == datetime(2026, 9, 20, 12, tzinfo=timezone.utc)
|
|
|
|
|
|
def test_naive_is_assumed_utc():
|
|
assert _parse_ts("2026-09-20T12:00:00", "date_to").tzinfo == timezone.utc
|
|
|
|
|
|
def test_round_trips_isoformat_cursor():
|
|
dt = datetime(2026, 9, 20, 12, 30, 5, 123456, tzinfo=timezone.utc)
|
|
assert _parse_ts(dt.isoformat(), "cursor") == dt
|
|
|
|
|
|
def test_garbage_is_400():
|
|
with pytest.raises(HTTPException) as exc:
|
|
_parse_ts("yesterday", "date_from")
|
|
assert exc.value.status_code == 400
|