Spaces:
Sleeping
Sleeping
| """Tests for the in-memory WebSocket ConnectionManager. | |
| We can't easily exercise full WS connect/disconnect in unit tests without | |
| running uvicorn — but the routing decisions (does this volunteer get this | |
| alert? does the skill match extend the radius?) are async-callable on the | |
| manager directly. | |
| """ | |
| from __future__ import annotations | |
| import json | |
| from typing import Any | |
| import pytest | |
| from app.services.websocket import ( | |
| CATEGORY_PREFERRED_SKILLS, | |
| DEFAULT_RADIUS_KM, | |
| SKILL_RADIUS_KM, | |
| ConnectionManager, | |
| ) | |
| class FakeWS: | |
| """Tiny stand-in for FastAPI's WebSocket — records sent payloads.""" | |
| def __init__(self): | |
| self.sent: list[dict[str, Any]] = [] | |
| self.closed = False | |
| async def send_text(self, text: str) -> None: | |
| if self.closed: | |
| raise RuntimeError("WS closed") | |
| self.sent.append(json.loads(text)) | |
| def _alert(category: str, lng: float, lat: float, oid: str = "abc") -> dict: | |
| return { | |
| "id": oid, | |
| "category": category, | |
| "urgency": "HIGH", | |
| "location": {"type": "Point", "coordinates": [lng, lat]}, | |
| } | |
| def manager(): | |
| return ConnectionManager() | |
| def test_count_reflects_active_connections(manager): | |
| assert manager.count() == 0 | |
| manager.register("u1", FakeWS(), [76.7, 30.7]) | |
| manager.register("u2", FakeWS(), [76.8, 30.8]) | |
| assert manager.count() == 2 | |
| manager.disconnect("u1") | |
| assert manager.count() == 1 | |
| async def test_volunteer_within_default_radius_receives_alert(manager): | |
| ws = FakeWS() | |
| # Volunteer at the same coords as the alert | |
| manager.register("v1", ws, [76.7794, 30.7333]) | |
| alert = _alert("medical", 76.7794, 30.7333) | |
| await manager.broadcast_nearby(alert) | |
| assert len(ws.sent) == 1 | |
| payload = ws.sent[0] | |
| assert payload["id"] == "abc" | |
| assert payload["your_distance_km"] == pytest.approx(0.0, abs=0.01) | |
| assert payload["is_skill_match"] is False # no skills registered | |
| async def test_volunteer_outside_default_radius_skipped(manager): | |
| ws = FakeWS() | |
| # Place volunteer ~50 km away — well outside the 5 km default | |
| manager.register("v1", ws, [77.5, 30.7]) | |
| alert = _alert("medical", 76.7794, 30.7333) | |
| await manager.broadcast_nearby(alert) | |
| assert ws.sent == [] | |
| async def test_skill_match_extends_radius(manager): | |
| """A medical-tagged volunteer 10 km away (outside default 5 km) should | |
| still get a medical alert because the skill match bumps the radius.""" | |
| assert "medical" in CATEGORY_PREFERRED_SKILLS["medical"] | |
| assert DEFAULT_RADIUS_KM < 10 < SKILL_RADIUS_KM | |
| ws = FakeWS() | |
| # 10 km east of the alert (longitude offset ≈ 0.1° at latitude 30°) | |
| manager.register("v1", ws, [76.7794 + 0.105, 30.7333], skills=["medical"]) | |
| alert = _alert("medical", 76.7794, 30.7333) | |
| await manager.broadcast_nearby(alert) | |
| assert len(ws.sent) == 1 | |
| assert ws.sent[0]["is_skill_match"] is True | |
| async def test_unrelated_skill_does_not_extend_radius(manager): | |
| ws = FakeWS() | |
| # 10 km away, but volunteer has a swim skill — not preferred for medical | |
| manager.register("v1", ws, [76.7794 + 0.105, 30.7333], skills=["swim"]) | |
| alert = _alert("medical", 76.7794, 30.7333) | |
| await manager.broadcast_nearby(alert) | |
| # Outside default radius and skill doesn't help → no broadcast | |
| assert ws.sent == [] | |
| async def test_disconnects_after_send_failure(manager): | |
| ws = FakeWS() | |
| ws.closed = True # any send will raise | |
| manager.register("v1", ws, [76.7794, 30.7333]) | |
| alert = _alert("medical", 76.7794, 30.7333) | |
| await manager.broadcast_nearby(alert) | |
| # Manager should have removed the failing connection so it doesn't | |
| # keep raising on subsequent broadcasts. | |
| assert manager.count() == 0 | |
| async def test_payload_includes_vehicle_flag(manager): | |
| ws = FakeWS() | |
| manager.register("v1", ws, [76.7794, 30.7333], has_vehicle=True) | |
| alert = _alert("medical", 76.7794, 30.7333) | |
| await manager.broadcast_nearby(alert) | |
| assert ws.sent[0]["your_has_vehicle"] is True | |