Download tests/test_api.py from Affaad/birdie: direct link, hf CLI and curl.
- Browser
- Download file 5.15 kB
-
https://huggingface.co/spaces/Affaad/birdie/resolve/main/tests/test_api.py
- Command line
-
hf download hf://spaces/Affaad/birdie/tests/test_api.py
-
curl -L -o test_api.py https://huggingface.co/spaces/Affaad/birdie/resolve/main/tests/test_api.py
5.15 kB
| from datetime import datetime | |
| from fastapi.testclient import TestClient | |
| from birdie.api import _counts, _status, create_app, mount_mobile_web | |
| from birdie.models import Seat, SeatSnapshot, SeatState, Venue, VenueConfig, VenueSource, VenueType | |
| from birdie.service import BirdieService | |
| from birdie.storage import Repository | |
| def test_public_api_reports_unknown_seats_as_not_free_and_hides_camera_polygons(clock): | |
| venue = Venue( | |
| venue_id="v", name="Venue", area="Doha", type=VenueType.cowork, | |
| lat=0, lon=0, zones=["open"], source=VenueSource.recorded, | |
| ) | |
| seat = Seat( | |
| seat_id="A", venue_id="v", zone="open", | |
| polygon=[(0, 0), (1, 0), (1, 1)], | |
| ) | |
| svc = BirdieService( | |
| repo=Repository(":memory:"), clock=clock, | |
| venues={"v": VenueConfig(venue=venue, seats=[seat])}, | |
| detector=lambda image, threshold: [], persist_venues=False, | |
| ) | |
| client = TestClient(create_app(svc)) | |
| listed = client.get("/api/venues").json()[0] | |
| detail = client.get("/api/venues/v").json() | |
| assert listed["counts"]["free"] == 0 | |
| assert listed["counts"]["unknown"] == 1 | |
| assert listed["counts"]["taken"] == 0 | |
| assert detail["seats"][0]["state"] == SeatState.UNKNOWN.value | |
| assert detail["seats"][0]["status"] == "checking" | |
| assert "polygon" not in detail["seats"][0] | |
| assert client.get("/api/venues/missing").status_code == 404 | |
| def test_public_availability_has_three_groups_and_a_checking_indicator(): | |
| assert {state: _status(state) for state in SeatState} == { | |
| SeatState.UNKNOWN: "checking", SeatState.FREE: "free", SeatState.OCCUPIED: "taken", | |
| SeatState.HELD: "held", SeatState.REVIEW_REQUIRED: "held", SeatState.UNAVAILABLE: "taken", | |
| } | |
| now = datetime.fromisoformat("2026-11-07T12:00:00+00:00") | |
| states = [SeatState.FREE, SeatState.OCCUPIED, SeatState.UNAVAILABLE, SeatState.HELD, | |
| SeatState.REVIEW_REQUIRED, SeatState.UNKNOWN] | |
| snapshots = [SeatSnapshot(venue_id="v", seat_id=str(i), zone="open", has_outlet=False, | |
| state=state, since=now, updated_at=now) for i, state in enumerate(states)] | |
| counts = _counts(snapshots) | |
| assert (counts["free"], counts["taken"], counts["held_or_review"], counts["checking"]) == (1, 2, 2, 1) | |
| assert counts["free"] + counts["taken"] + counts["held_or_review"] + counts["checking"] == counts["total"] | |
| def test_mobile_web_is_served_after_api_routes(clock): | |
| venue = Venue( | |
| venue_id="v", name="Venue", area="Doha", type=VenueType.cowork, | |
| lat=0, lon=0, zones=["open"], source=VenueSource.recorded, | |
| ) | |
| svc = BirdieService( | |
| repo=Repository(":memory:"), clock=clock, | |
| venues={"v": VenueConfig(venue=venue, seats=[])}, persist_venues=False, | |
| detector=lambda image, threshold: [], | |
| ) | |
| app = create_app(svc) | |
| mount_mobile_web(app) | |
| client = TestClient(app) | |
| assert "Birdie" in client.get("/").text | |
| assert client.get("/api/venues").status_code == 200 | |
| def test_staff_override_requires_token_and_changes_availability(clock, monkeypatch): | |
| venue = Venue( | |
| venue_id="v", name="Venue", area="Doha", type=VenueType.cowork, | |
| lat=0, lon=0, zones=["open"], source=VenueSource.recorded, | |
| ) | |
| seat = Seat(seat_id="A", venue_id="v", zone="open") | |
| svc = BirdieService( | |
| repo=Repository(":memory:"), clock=clock, | |
| venues={"v": VenueConfig(venue=venue, seats=[seat])}, | |
| detector=lambda image, threshold: [], persist_venues=False, | |
| ) | |
| client = TestClient(create_app(svc)) | |
| monkeypatch.setenv("BIRDIE_ADMIN_TOKEN", "test-token") | |
| response = client.put("/api/venues/v/seats/A/unavailable", json={"unavailable": True}) | |
| assert response.status_code == 401 | |
| response = client.put( | |
| "/api/venues/v/seats/A/unavailable", json={"unavailable": True}, | |
| headers={"Authorization": "Bearer test-token"}, | |
| ) | |
| assert response.status_code == 200 | |
| assert response.json()["state"] == SeatState.UNAVAILABLE.value | |
| assert svc.counts("v")[SeatState.FREE] == 0 | |
| def test_forecast_starts_from_the_live_count_and_covers_three_hours(clock): | |
| venue = Venue( | |
| venue_id="v", name="Venue", area="Doha", type=VenueType.library, | |
| lat=0, lon=0, zones=["open"], source=VenueSource.simulated, drive_minutes=15, | |
| ) | |
| seats = [Seat(seat_id=f"A{i}", venue_id="v", zone="open") for i in range(1, 9)] | |
| svc = BirdieService( | |
| repo=Repository(":memory:"), clock=clock, | |
| venues={"v": VenueConfig(venue=venue, seats=seats)}, | |
| detector=lambda image, threshold: [], persist_venues=False, | |
| ) | |
| client = TestClient(create_app(svc)) | |
| listed = client.get("/api/venues").json()[0]["forecast"] | |
| detail = client.get("/api/venues/v").json() | |
| timeline = detail["forecast"]["timeline"] | |
| assert listed["arrival"]["minutes"] == 15 | |
| assert "timeline" not in listed | |
| assert [p["minutes"] for p in timeline] == [0, 30, 60, 90, 120, 150, 180] | |
| assert timeline[0]["expected_free"] == detail["counts"]["usable_study_spaces"] | |
| assert all(0 <= p["low"] <= p["expected_free"] <= p["high"] <= 8 for p in timeline) | |