-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathtest_locations.py
More file actions
196 lines (164 loc) · 6.61 KB
/
test_locations.py
File metadata and controls
196 lines (164 loc) · 6.61 KB
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
import pytest
from unittest.mock import AsyncMock, patch
from src.models.history_data import CachedLocation
MOCK_LAT = 40.7128
MOCK_LON = -74.0060
class TestLocationRoutes:
"""
Integration tests for /api/v1/locations/ routes.
Uses the in-memory MongoDB (AsyncMongoMockClient) via the app fixture.
Data is inserted directly into the mock DB before each test that needs it.
"""
# Runs after every test to keep the DB clean.
@pytest.fixture(autouse=True)
async def clean_db(self):
yield
await CachedLocation.find_all().delete()
# Inserts a real CachedLocation document into the mock DB.
# Returns the inserted document so tests can reference its id.
async def _insert_location(self, location:dict, name: str = "Test Location"):
doc = CachedLocation(name=name, location=location)
await doc.insert()
return doc
@pytest.mark.anyio
async def test_list_locations_returns_200_with_empty_db(
self, async_client, auth_headers
):
response = await async_client.get(
"/api/v1/locations/locations/", headers=auth_headers
)
assert response.status_code == 200
assert response.json() == []
@pytest.mark.anyio
async def test_list_locations_returns_inserted_documents(
self, async_client, auth_headers, mock_location
):
await self._insert_location(mock_location, "Location A")
await self._insert_location(mock_location, "Location B")
response = await async_client.get(
"/api/v1/locations/locations/", headers=auth_headers
)
assert response.status_code == 200
assert len(response.json()) == 2
names = [loc["name"] for loc in response.json()]
assert "Location A" in names
assert "Location B" in names
@pytest.mark.anyio
async def test_list_locations_returns_403_without_auth(self, async_client):
response = await async_client.get("/api/v1/locations/locations/")
assert response.status_code == 403
@pytest.mark.anyio
async def test_get_location_by_coordinates_returns_200(
self, async_client, auth_headers, mock_location
):
await self._insert_location(mock_location)
response = await async_client.get(
"/api/v1/locations/locations/by-coordinates/",
params={"lat": MOCK_LAT, "lon": MOCK_LON},
headers=auth_headers,
)
assert response.status_code == 200
assert response.json()["lat"] == MOCK_LAT
assert response.json()["lon"] == MOCK_LON
@pytest.mark.anyio
async def test_get_location_by_coordinates_returns_404_when_not_found(
self, async_client, auth_headers
):
# Nothing inserted — DB is empty
response = await async_client.get(
"/api/v1/locations/locations/by-coordinates/",
params={"lat": MOCK_LAT, "lon": MOCK_LON},
headers=auth_headers,
)
assert response.status_code == 404
@pytest.mark.anyio
async def test_get_location_by_coordinates_returns_403_without_auth(
self, async_client
):
response = await async_client.get(
"/api/v1/locations/locations/by-coordinates/",
params={"lat": MOCK_LAT, "lon": MOCK_LON},
)
assert response.status_code == 403
@pytest.mark.skip(
reason="Uses MongoDB $near geospatial query — not supported by mongomock. "
"Requires a real MongoDB instance to test meaningfully."
)
async def test_check_location_exists_in_radius(self):
pass
@pytest.mark.anyio
async def test_add_locations_returns_200_and_inserts(
self, async_client, auth_headers
):
payload = {
"locations": [{"name": "Farm A", "lat": MOCK_LAT, "lon": MOCK_LON}]
}
with patch(
"src.api.api_v1.endpoints.locations.fetch_and_cache_last_month",
new_callable=AsyncMock
):
response = await async_client.post(
"/api/v1/locations/locations/",
json=payload,
headers=auth_headers,
)
assert response.status_code == 200
# Verify it actually landed in the DB
docs = await CachedLocation.find_all().to_list()
assert len(docs) == 1
assert docs[0].name == "Farm A"
@pytest.mark.anyio
async def test_add_locations_skips_existing_location(
self, async_client, auth_headers, mock_location
):
await self._insert_location(mock_location, "Farm A")
payload = {
"locations": [{"name": "Farm A", "lat": MOCK_LAT, "lon": MOCK_LON}]
}
with patch(
"src.api.api_v1.endpoints.locations.fetch_and_cache_last_month",
new_callable=AsyncMock
):
response = await async_client.post(
"/api/v1/locations/locations/",
json=payload,
headers=auth_headers,
)
assert response.status_code == 200
# Still only one document — duplicate was skipped
docs = await CachedLocation.find_all().to_list()
assert len(docs) == 1
@pytest.mark.anyio
async def test_add_locations_returns_403_without_auth(self, async_client):
payload = {
"locations": [{"name": "Farm A", "lat": MOCK_LAT, "lon": MOCK_LON}]
}
response = await async_client.post("/api/v1/locations/locations/", json=payload)
assert response.status_code == 403
@pytest.mark.skip(
reason="Uses dao.find_location_nearby which relies on MongoDB $near "
"geospatial query — not supported by mongomock."
)
async def test_add_unique_locations(self):
pass
@pytest.mark.anyio
async def test_delete_location_returns_200(
self, async_client, auth_headers, mock_location
):
doc = await self._insert_location(mock_location)
with patch(
"src.api.api_v1.endpoints.locations.scheduler"
) as mock_scheduler:
mock_scheduler.get_job.return_value = None
response = await async_client.delete(
f"/api/v1/locations/locations/{doc.id}/",
headers=auth_headers,
)
assert response.status_code == 200
# Verify it was actually removed from the DB
remaining = await CachedLocation.find_all().to_list()
assert len(remaining) == 0
@pytest.mark.anyio
async def test_delete_location_returns_403_without_auth(self, async_client):
response = await async_client.delete("/api/v1/locations/locations/some-id/")
assert response.status_code == 403