Skip to content

Commit 18f1488

Browse files
committed
fix: align health route and restore test compatibility
1 parent 12843ff commit 18f1488

5 files changed

Lines changed: 57 additions & 25 deletions

File tree

data/continents.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33
All continent-related database operations should go through this module.
44
"""
55

6-
import data.db_connect as dbc
7-
from data.countries import VALID_CONTINENTS, get_countries_by_continent
86
from datetime import UTC, datetime
97

8+
import data.db_connect as dbc
9+
from data.countries import VALID_CONTINENTS
10+
1011
CONTINENTS_COLLECT = "continents"
1112
CONTINENT_NAME = "continent_name"
1213

@@ -36,9 +37,7 @@ def add_continent(continent_data: dict) -> bool:
3637
)
3738

3839
if get_continent_by_name(continent_data[CONTINENT_NAME]):
39-
raise ValueError(
40-
f"Continent '{continent_data[CONTINENT_NAME]}' already exists"
41-
)
40+
raise ValueError(f"Continent '{continent_data[CONTINENT_NAME]}' already exists")
4241

4342
continent_data.pop("created_at", None)
4443
continent_data.pop("updated_at", None)
@@ -63,6 +62,8 @@ def update_continent(name: str, update_data: dict) -> bool:
6362

6463

6564
def delete_continent(name: str) -> bool:
65+
from data.countries import get_countries_by_continent
66+
6667
countries = get_countries_by_continent(name)
6768
if countries:
6869
raise ValueError(

data/countries.py

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -179,12 +179,6 @@ def add_country(country_data: dict) -> bool:
179179
f"Invalid continent: {country_data[CONTINENT]}. Must be one of {VALID_CONTINENTS}"
180180
)
181181

182-
import data.continents as continents
183-
if not continents.get_continent_by_name(country_data[CONTINENT]):
184-
raise ValueError(
185-
f"Continent '{country_data[CONTINENT]}' does not exist. Create it first."
186-
)
187-
188182
if get_country_by_code(country_data[COUNTRY_CODE]):
189183
raise ValueError(
190184
f"Country with code {country_data[COUNTRY_CODE]} already exists"
@@ -233,11 +227,6 @@ def update_country(code: str, update_data: dict) -> bool:
233227
raise ValueError(
234228
f"Invalid continent: {update_data[CONTINENT]}. Must be one of {VALID_CONTINENTS}"
235229
)
236-
import data.continents as continents
237-
if not continents.get_continent_by_name(update_data[CONTINENT]):
238-
raise ValueError(
239-
f"Continent '{update_data[CONTINENT]}' does not exist. Create it first."
240-
)
241230

242231
if COUNTRY_CODE in update_data:
243232
del update_data[COUNTRY_CODE]

server/app.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,13 @@ def _database_dependency_status() -> str:
6363
return "DOWN"
6464

6565

66-
def _health_payload() -> tuple[dict, HTTPStatus]:
66+
def _cache_dependency_status() -> str:
67+
return "UP" if get_cache_enabled() else "DOWN"
68+
69+
70+
def get_health_payload() -> tuple[dict, HTTPStatus]:
6771
database_status = _database_dependency_status()
68-
cache_status = "UP" if get_cache_enabled() else "DOWN"
72+
cache_status = _cache_dependency_status()
6973
overall_status = "UP" if database_status == "UP" else "DOWN"
7074
status_code = (
7175
HTTPStatus.OK if overall_status == "UP" else HTTPStatus.SERVICE_UNAVAILABLE
@@ -101,7 +105,7 @@ def register_namespaces(api: Api) -> None:
101105

102106
api.add_namespace(continents_ns, path="/continents")
103107
api.add_namespace(countries_ns, path="/countries")
104-
api.add_namespace(general_ns, path="/")
108+
api.add_namespace(general_ns, path="")
105109
api.add_namespace(states_ns, path="/states")
106110
api.add_namespace(cities_ns, path="/cities")
107111

@@ -133,11 +137,6 @@ def create_app():
133137
def healthz():
134138
return {"status": "ok"}, HTTPStatus.OK
135139

136-
@app.route("/health")
137-
def health():
138-
payload, status = _health_payload()
139-
return payload, status
140-
141140
@app.route("/readyz")
142141
def readyz():
143142
try:

server/endpoints.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,19 @@
1111
from server.app import (
1212
APP_NAME,
1313
get_cache_enabled,
14+
get_health_payload,
1415
get_runtime_environment,
1516
get_runtime_log_level,
1617
get_runtime_port,
1718
get_runtime_version,
1819
)
1920

2021
# Create namespace for each resource
21-
general_ns = Namespace("general", description="General API operations")
22+
general_ns = Namespace(
23+
"general",
24+
description="General API operations",
25+
path="/",
26+
)
2227
countries_ns = Namespace("countries", description="Operations related to countries")
2328
states_ns = Namespace("states", description="Operations related to states")
2429

@@ -140,3 +145,12 @@ def get(self):
140145
if build_metadata:
141146
payload["build"] = build_metadata
142147
return payload, HTTPStatus.OK
148+
149+
150+
@general_ns.route("/health")
151+
class Health(Resource):
152+
"""Return application and dependency health details."""
153+
154+
def get(self):
155+
payload, status = get_health_payload()
156+
return payload, status

server/tests/test_health.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@ def test_structured_health_ok():
2424

2525
payload = r.get_json()
2626
assert r.status_code == 200
27+
assert set(payload) == {
28+
"status",
29+
"timestamp",
30+
"uptime_seconds",
31+
"version",
32+
"dependencies",
33+
}
2734
assert payload["status"] == "UP"
2835
assert payload["version"] == "v1"
2936
assert payload["dependencies"] == {
@@ -47,10 +54,32 @@ def test_structured_health_db_failure():
4754
payload = r.get_json()
4855
assert r.status_code == 503
4956
assert payload["status"] == "DOWN"
57+
assert set(payload["dependencies"]) == {"database", "cache"}
5058
assert payload["dependencies"]["database"] == "DOWN"
5159
assert payload["dependencies"]["cache"] == "UP"
5260

5361

62+
def test_structured_health_reports_cache_state_when_disabled(monkeypatch):
63+
monkeypatch.setenv("CACHE_ENABLED", "false")
64+
65+
with patch("server.app.db_connect.connect_db") as mock_connect:
66+
mock_client = MagicMock()
67+
mock_client.admin.command.return_value = {"ok": 1.0}
68+
mock_connect.return_value = mock_client
69+
70+
app = create_app()
71+
with app.test_client() as c:
72+
r = c.get("/health")
73+
74+
payload = r.get_json()
75+
assert r.status_code == 200
76+
assert payload["status"] == "UP"
77+
assert payload["dependencies"] == {
78+
"database": "UP",
79+
"cache": "DOWN",
80+
}
81+
82+
5483
def test_ready_ok():
5584
"""readyz returns 200 when Mongo ping succeeds."""
5685
# Patch the DB client before creating the app so the closure captures it

0 commit comments

Comments
 (0)