File size: 2,839 Bytes
49e9f9d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import pytest
from unittest.mock import AsyncMock, MagicMock
from bson import ObjectId
from app.core.security import create_token


def _token(role="reporter"):
    return create_token({"sub": str(ObjectId()), "role": role})


@pytest.mark.asyncio
async def test_stats_public_no_auth_needed(client):
    c, db = client
    db.alerts.count_documents = AsyncMock(return_value=0)

    async def empty_agg(*args, **kwargs):
        if False:
            yield
    db.alerts.aggregate = MagicMock(return_value=empty_agg())

    resp = await c.get("/api/stats/")
    assert resp.status_code == 200
    body = resp.json()
    assert "active_alerts" in body
    assert "critical_open" in body
    assert "last_24h" in body


@pytest.mark.asyncio
async def test_user_me_requires_auth(client):
    c, _ = client
    resp = await c.get("/api/users/me")
    # FastAPI's HTTPBearer returns 403 when the header is missing
    assert resp.status_code in (401, 403)


@pytest.mark.asyncio
async def test_update_location_requires_valid_coords(client):
    c, db = client
    db.users.find_one_and_update = AsyncMock(
        return_value={
            "_id": ObjectId(),
            "name": "x",
            "email": "x@x.com",
            "role": "reporter",
            "location": {"type": "Point", "coordinates": [76.7, 30.7]},
            "created_at": "2024-01-01T00:00:00",
        }
    )
    resp = await c.patch(
        "/api/users/me/location",
        json={"location": {"type": "Point", "coordinates": [999, 999]}},
        headers={"Authorization": f"Bearer {_token()}"},
    )
    # 422 — our validator rejects out-of-range coords
    assert resp.status_code == 422


@pytest.mark.asyncio
async def test_news_endpoint_structure(client, monkeypatch):
    c, _ = client
    # Patch the symbol where it's actually used (imported into the route module).
    from app.routes import news as news_route

    async def fake_fetch():
        return [
            {
                "source": "Test",
                "title": "Fire in city centre",
                "link": "https://example.com/a",
                "summary": "...",
                "published": "",
            }
        ]

    monkeypatch.setattr(news_route, "fetch_news", fake_fetch)

    resp = await c.get("/api/news/recent")
    assert resp.status_code == 200
    body = resp.json()
    assert body["count"] == 1
    assert body["items"][0]["title"] == "Fire in city centre"


@pytest.mark.asyncio
async def test_my_stats_reporter_shape(client):
    c, db = client
    db.alerts.count_documents = AsyncMock(return_value=3)
    resp = await c.get(
        "/api/users/me/stats",
        headers={"Authorization": f"Bearer {_token('reporter')}"},
    )
    assert resp.status_code == 200
    body = resp.json()
    assert body["role"] == "reporter"
    assert body["posted"] == 3