Add location search and polish running route planner

This commit is contained in:
Peter Stockings
2026-10-03 10:01:16 +10:00
parent 52943cd05b
commit 5ede1a01d2
7 changed files with 420 additions and 43 deletions
+85 -1
View File
@@ -7,7 +7,7 @@ import pytest
from app import create_app
from app.extensions import db
from app.models import PlannedRoute, User
from app.planner_engine import PlannerError, analyse, generate, validate
from app.planner_engine import PlannerError, analyse, generate, search_locations, validate
@pytest.fixture
@@ -223,3 +223,87 @@ def test_old_candidates_cleanup_and_saved_preservation(app, monkeypatch):
with app.app_context():
assert db.session.get(PlannedRoute, 1) is None
assert db.session.get(PlannedRoute, 2).saved
def test_location_search_contract_and_invalid_results(monkeypatch):
import json
from urllib.parse import parse_qs, urlsplit
calls = []
class Reply:
def __enter__(self):
return self
def __exit__(self, *_):
pass
def read(self, limit):
assert limit == 1_000_001
return json.dumps(
{
"features": [
{
"geometry": {"type": "Point", "coordinates": [151.2, -33.9]},
"properties": {"label": "Park & gardens, Sydney"},
},
{
"geometry": {"type": "Point", "coordinates": [0, 99]},
"properties": {"label": "Invalid"},
},
{"geometry": {"type": "LineString", "coordinates": []}, "properties": {}},
]
}
).encode()
def fake(req, timeout):
calls.append(req)
assert timeout == 8
return Reply()
monkeypatch.setattr("app.planner_engine.urlopen", fake)
locations = search_locations(
{"text": "Park & gardens", "focus": [151, -33]}, "private-test-key"
)
assert locations == [{"label": "Park & gardens, Sydney", "coordinates": [151.2, -33.9]}]
query = parse_qs(urlsplit(calls[0].full_url).query)
assert query["text"] == ["Park & gardens"]
assert query["size"] == ["5"] and query["focus.point.lon"] == ["151.0"]
assert "private-test-key" not in calls[0].full_url
assert calls[0].get_header("Authorization") == "private-test-key"
@pytest.mark.parametrize(
"data", [None, {}, {"text": "ab"}, {"text": "x" * 201}, {"text": "Sydney", "focus": [0, 99]}]
)
def test_location_search_validation(data):
with pytest.raises(PlannerError):
search_locations(data, "test")
def test_location_search_login_configuration_and_csrf(app, monkeypatch):
monkeypatch.setattr(
"app.planner.search_locations",
lambda data, key: [{"label": "Public park", "coordinates": [151, -33]}],
)
client = app.test_client()
assert client.post("/routes/search", json={"text": "Sydney"}).status_code == 302
login(client)
response = client.post("/routes/search", json={"text": "Sydney"})
assert response.status_code == 200 and response.json["locations"][0]["label"] == "Public park"
app.config["WTF_CSRF_ENABLED"] = True
assert client.post("/routes/search", json={"text": "Sydney"}).status_code == 400
with pytest.raises(PlannerError, match="not connected"):
search_locations({"text": "Sydney"}, None)
def test_location_search_failure_is_actionable(monkeypatch):
from urllib.error import URLError
def fail(*_, **__):
raise URLError("private provider internals")
monkeypatch.setattr("app.planner_engine.urlopen", fail)
with pytest.raises(PlannerError, match="selecting a point on the map") as error:
search_locations({"text": "Sydney"}, "private-key")
assert "private" not in str(error.value)