Skip to content
Draft
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: 10 additions & 7 deletions backend/main.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from fastapi import FastAPI, UploadFile, File, Form, HTTPException, Query, Request
from fastapi import FastAPI, UploadFile, File, Form, HTTPException, Query, Request, Response
from fastapi.responses import JSONResponse
from fastapi.middleware.cors import CORSMiddleware
from fastapi.middleware.gzip import GZipMiddleware
Expand Down Expand Up @@ -293,9 +293,10 @@ async def chat_endpoint(request: ChatRequest):
def get_recent_issues(db: Session = Depends(get_db)):
cached_data = recent_issues_cache.get()
if cached_data:
# Check if cached data is already serialized (list of dicts)
# We return JSONResponse directly to bypass FastAPI's Pydantic validation/serialization
# which is redundant for cached data that was already validated when stored.
# Check if cached data is already serialized (string)
if isinstance(cached_data, str):
return Response(content=cached_data, media_type="application/json")
# Fallback for legacy format (list of dicts) or if cache implementation changes
return JSONResponse(content=cached_data)

# Fetch last 10 issues
Expand Down Expand Up @@ -328,11 +329,13 @@ def get_recent_issues(db: Session = Depends(get_db)):
latitude=i.latitude,
longitude=i.longitude,
action_plan=action_plan_val
).model_dump(mode='json')) # Store as JSON-compatible dict in cache
).model_dump(mode='json')) # Store as JSON-compatible dict

recent_issues_cache.set(data)
# Serialize to JSON string and cache
json_data = json.dumps(data)
recent_issues_cache.set(json_data)

return data
return Response(content=json_data, media_type="application/json")

@app.post("/api/detect-pothole")
async def detect_pothole_endpoint(image: UploadFile = File(...)):
Expand Down
89 changes: 89 additions & 0 deletions tests/test_recent_issues.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import sys
import os
import json
from datetime import datetime
import pytest

# Adjust path to import backend
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'backend'))

from fastapi.testclient import TestClient
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.pool import StaticPool

# Import app and dependencies
from main import app, get_db
from database import Base
from models import Issue
from cache import recent_issues_cache

# Setup in-memory DB for testing
SQLALCHEMY_DATABASE_URL = "sqlite:///:memory:"

engine = create_engine(
SQLALCHEMY_DATABASE_URL,
connect_args={"check_same_thread": False},
poolclass=StaticPool,
)
TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

def override_get_db():
try:
db = TestingSessionLocal()
yield db
finally:
db.close()

app.dependency_overrides[get_db] = override_get_db

def test_recent_issues_caching():
# Clear cache
recent_issues_cache.invalidate()

# Create tables
Base.metadata.create_all(bind=engine)

# Add dummy data
db = TestingSessionLocal()
issue1 = Issue(
description="Test Issue 1",
category="Road",
status="open",
created_at=datetime(2023, 1, 1, 12, 0, 0),
action_plan=json.dumps({"step": "1"})
)
db.add(issue1)
db.commit()
db.close()

with TestClient(app) as client:
# First call - Cache Miss
response1 = client.get("/api/issues/recent")
assert response1.status_code == 200
data1 = response1.json()
assert len(data1) == 1
assert data1[0]["description"] == "Test Issue 1"

# Verify cache is populated
assert recent_issues_cache.get() is not None

# Second call - Cache Hit (String format)
response2 = client.get("/api/issues/recent")
assert response2.status_code == 200
data2 = response2.json()
assert data2 == data1
assert response2.headers["content-type"] == "application/json"

# Verify robustness with legacy format (List of dicts)
# Manually inject list into cache
recent_issues_cache.set([{"id": 999, "description": "Legacy", "category": "Road", "created_at": "2023-01-01T12:00:00", "status": "open", "upvotes": 0}])

response3 = client.get("/api/issues/recent")
assert response3.status_code == 200
data3 = response3.json()
assert len(data3) == 1
assert data3[0]["description"] == "Legacy"

if __name__ == "__main__":
test_recent_issues_caching()