Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions src/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,16 @@ async def lifespan(app: FastAPI):

@app.get("/api/war/status", tags=["War"])
async def get_war_status():
"""Get current war status"""
"""Get current war status. If DB is empty, fetches live and saves so Data Console/MCP get data on first request."""
data = db.get_latest_war_status()
if data:
return data
raise HTTPException(status_code=404, detail="No war status data available")
# No data yet (e.g. before first collector run): try live fetch so UI/MCP get something
data = scraper.get_war_status()
if data:
db.save_war_status(data)
return data
raise HTTPException(status_code=404, detail="No war status data available (upstream API may be unreachable)")


@app.post("/api/war/status/refresh", tags=["War"])
Expand Down Expand Up @@ -316,11 +321,15 @@ async def get_planet_history(planet_index: int, limit: int = Query(10, ge=1, le=

@app.get("/api/statistics", tags=["Statistics"])
async def get_statistics():
"""Get latest global statistics"""
"""Get latest global statistics. If DB is empty, fetches live and saves so Data Console/MCP get data."""
data = db.get_latest_statistics()
if data:
return data
raise HTTPException(status_code=404, detail="No statistics available")
data = scraper.get_statistics()
if data:
db.save_statistics(data)
return data
raise HTTPException(status_code=404, detail="No statistics available (upstream API may be unreachable)")


@app.get("/api/statistics/history", tags=["Statistics"])
Expand Down
40 changes: 36 additions & 4 deletions tests/test_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,30 @@ def test_get_war_status_success(self, mock_get, client):
data = response.json()
assert data["war_id"] == 1

@patch("src.app.scraper.get_war_status")
@patch("src.app.db.get_latest_war_status")
def test_get_war_status_not_found(self, mock_get, client):
"""Test getting war status when none exists"""
def test_get_war_status_not_found(self, mock_get, mock_scraper, client):
"""Test getting war status when DB empty and live fetch fails"""
mock_get.return_value = None
mock_scraper.return_value = None

response = client.get("/api/war/status")
assert response.status_code == 404

@patch("src.app.scraper.get_war_status")
@patch("src.app.db.save_war_status")
@patch("src.app.db.get_latest_war_status")
def test_get_war_status_live_when_db_empty(self, mock_get, mock_save, mock_scraper, client):
"""When DB has no row yet, GET uses live fetch and persists"""
mock_get.return_value = None
mock_scraper.return_value = {"war_id": 42, "status": "active"}
mock_save.return_value = True

response = client.get("/api/war/status")
assert response.status_code == 200
assert response.json()["war_id"] == 42
mock_save.assert_called_once()

@patch("src.app.scraper.get_war_status")
@patch("src.app.db.save_war_status")
def test_refresh_war_status_success(self, mock_save, mock_scraper, client):
Expand Down Expand Up @@ -173,14 +189,30 @@ def test_get_statistics_success(self, mock_get, client):
response = client.get("/api/statistics")
assert response.status_code == 200

@patch("src.app.scraper.get_statistics")
@patch("src.app.db.get_latest_statistics")
def test_get_statistics_not_found(self, mock_get, client):
"""Test getting statistics when none exists"""
def test_get_statistics_not_found(self, mock_get, mock_scraper, client):
"""Test getting statistics when DB empty and live fetch fails"""
mock_get.return_value = None
mock_scraper.return_value = None

response = client.get("/api/statistics")
assert response.status_code == 404

@patch("src.app.scraper.get_statistics")
@patch("src.app.db.save_statistics")
@patch("src.app.db.get_latest_statistics")
def test_get_statistics_live_when_db_empty(self, mock_get, mock_save, mock_scraper, client):
"""When DB has no row yet, GET uses live fetch and persists"""
mock_get.return_value = None
mock_scraper.return_value = {"total_players": 999}
mock_save.return_value = True

response = client.get("/api/statistics")
assert response.status_code == 200
assert response.json()["total_players"] == 999
mock_save.assert_called_once()

@patch("src.app.db.get_latest_statistics")
def test_get_statistics_history(self, mock_get, client):
"""Test getting statistics history"""
Expand Down
6 changes: 4 additions & 2 deletions tests/test_coverage_gaps.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,10 +187,12 @@ def test_refresh_statistics_none(self, mock_save, mock_scraper, client):
class TestDatabaseCoveragePaths:
"""Test database error and edge case paths"""

@patch("src.app.scraper.get_statistics")
@patch("src.app.db.get_latest_statistics")
def test_statistics_not_found(self, mock_get, client):
"""Test getting statistics when not found"""
def test_statistics_not_found(self, mock_get, mock_scraper, client):
"""Test getting statistics when DB empty and live fetch fails"""
mock_get.return_value = None
mock_scraper.return_value = None
response = client.get("/api/statistics")
assert response.status_code == 404

Expand Down
Loading