Adding features to find public toilets and shopping streets #41
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										42
									
								
								backend/src/tests/test_cache.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								backend/src/tests/test_cache.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | |||||||
|  | """Collection of tests to ensure correct handling of invalid input.""" | ||||||
|  |  | ||||||
|  | from fastapi.testclient import TestClient | ||||||
|  | import pytest | ||||||
|  |  | ||||||
|  | from .test_utils import load_trip_landmarks | ||||||
|  | from ..main import app | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.fixture(scope="module") | ||||||
|  | def client(): | ||||||
|  |     """Client used to call the app.""" | ||||||
|  |     return TestClient(app) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_cache(client, request):    # pylint: disable=redefined-outer-name | ||||||
|  |     """ | ||||||
|  |     Test n°1 : Custom test in Turckheim to ensure small villages are also supported. | ||||||
|  |  | ||||||
|  |     Args: | ||||||
|  |         client: | ||||||
|  |         request: | ||||||
|  |     """ | ||||||
|  |     duration_minutes = 15 | ||||||
|  |     response = client.post( | ||||||
|  |         "/trip/new", | ||||||
|  |         json={ | ||||||
|  |             "preferences": {"sightseeing": {"type": "sightseeing", "score": 5}, | ||||||
|  |             "nature": {"type": "nature", "score": 5}, | ||||||
|  |             "shopping": {"type": "shopping", "score": 5}, | ||||||
|  |             "max_time_minute": duration_minutes, | ||||||
|  |             "detour_tolerance_minute": 0}, | ||||||
|  |             "start": [48.084588, 7.280405] | ||||||
|  |             } | ||||||
|  |         ) | ||||||
|  |     result = response.json() | ||||||
|  |     landmarks = load_trip_landmarks(client, result['first_landmark_uuid']) | ||||||
|  |     landmarks_cached = load_trip_landmarks(client, result['first_landmark_uuid'], True) | ||||||
|  |  | ||||||
|  |     # checks : | ||||||
|  |     assert response.status_code == 200  # check for successful planning | ||||||
|  |     assert landmarks_cached == landmarks | ||||||
| @@ -2,8 +2,10 @@ | |||||||
| import logging | import logging | ||||||
| from typing import List | from typing import List | ||||||
| from fastapi import HTTPException | from fastapi import HTTPException | ||||||
|  | from pydantic import ValidationError | ||||||
|  |  | ||||||
| from ..structs.landmark import Landmark | from ..structs.landmark import Landmark | ||||||
|  | from ..persistence import client as cache_client | ||||||
|  |  | ||||||
|  |  | ||||||
| def landmarks_to_osmid(landmarks: List[Landmark]) -> List[int] : | def landmarks_to_osmid(landmarks: List[Landmark]) -> List[int] : | ||||||
| @@ -42,18 +44,58 @@ def fetch_landmark(client, landmark_uuid: str): | |||||||
|     try: |     try: | ||||||
|         json_data = response.json() |         json_data = response.json() | ||||||
|         logger.info(f"API Response: {json_data}") |         logger.info(f"API Response: {json_data}") | ||||||
|         print(f"API Response of type {type(json_data)} in json format: {json_data}") |  | ||||||
|     except ValueError as e: |     except ValueError as e: | ||||||
|         logger.error(f"Failed to parse response as JSON: {response.text}") |         logger.error(f"Failed to parse response as JSON: {response.text}") | ||||||
|         raise HTTPException(status_code=500, detail="Invalid response format from API") |         raise HTTPException(status_code=500, detail="Invalid response format from API") | ||||||
|      |      | ||||||
|  |     # Try validating against the Landmark model here to ensure consistency | ||||||
|  |     try: | ||||||
|  |         landmark = Landmark(**json_data) | ||||||
|  |     except ValidationError as ve: | ||||||
|  |         logging.error(f"Validation error: {ve}") | ||||||
|  |         raise HTTPException(status_code=500, detail="Invalid data format received from API") | ||||||
|  |      | ||||||
|  |  | ||||||
|     if "detail" in json_data: |     if "detail" in json_data: | ||||||
|         raise HTTPException(status_code=500, detail=json_data["detail"]) |         raise HTTPException(status_code=500, detail=json_data["detail"]) | ||||||
|  |  | ||||||
|     return json_data |     return Landmark(**json_data) | ||||||
|  |  | ||||||
|  |  | ||||||
| def load_trip_landmarks(client, first_uuid: str) -> List[Landmark]: | def fetch_landmark_cache(landmark_uuid: str): | ||||||
|  |     """ | ||||||
|  |     Fetch landmark data from the cache based on the landmark UUID. | ||||||
|  |  | ||||||
|  |     Args: | ||||||
|  |         landmark_uuid (str): The UUID of the landmark. | ||||||
|  |  | ||||||
|  |     Returns: | ||||||
|  |         dict: Landmark data fetched from the cache or raises an HTTP exception. | ||||||
|  |     """ | ||||||
|  |     logger = logging.getLogger(__name__) | ||||||
|  |  | ||||||
|  |     # Try to fetch the landmark data from the cache | ||||||
|  |     try: | ||||||
|  |         landmark = cache_client.get(f"landmark_{landmark_uuid}") | ||||||
|  |         if not landmark : | ||||||
|  |             logger.warning(f"Cache miss for landmark UUID: {landmark_uuid}") | ||||||
|  |             raise HTTPException(status_code=404, detail=f"Landmark with UUID {landmark_uuid} not found in cache.") | ||||||
|  |          | ||||||
|  |         # Validate that the fetched data is a dictionary | ||||||
|  |         if not isinstance(landmark, Landmark): | ||||||
|  |             logger.error(f"Invalid cache data format for landmark UUID: {landmark_uuid}. Expected dict, got {type(landmark).__name__}.") | ||||||
|  |             raise HTTPException(status_code=500, detail="Invalid cache data format.") | ||||||
|  |  | ||||||
|  |         return landmark | ||||||
|  |      | ||||||
|  |     except Exception as exc: | ||||||
|  |         logger.error(f"Unexpected error occurred while fetching landmark UUID {landmark_uuid}: {exc}") | ||||||
|  |         raise HTTPException(status_code=500, detail="An unexpected error occurred while fetching the landmark from the cache") from exc | ||||||
|  |      | ||||||
|  |      | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def load_trip_landmarks(client, first_uuid: str, from_cache=None) -> List[Landmark]: | ||||||
|     """ |     """ | ||||||
|     Load all landmarks for a trip using the response from the API. |     Load all landmarks for a trip using the response from the API. | ||||||
|  |  | ||||||
| @@ -67,14 +109,13 @@ def load_trip_landmarks(client, first_uuid: str) -> List[Landmark]: | |||||||
|     next_uuid = first_uuid |     next_uuid = first_uuid | ||||||
|  |  | ||||||
|     while next_uuid is not None: |     while next_uuid is not None: | ||||||
|         landmark_data = fetch_landmark(client, next_uuid) |         if from_cache : | ||||||
|         # # Convert UUIDs to strings explicitly |             landmark = fetch_landmark_cache(next_uuid) | ||||||
|         # landmark_data = { |         else : | ||||||
|         #     key: str(value) if isinstance(value, UUID) else value |             landmark = fetch_landmark(client, next_uuid) | ||||||
|         #     for key, value in landmark_data.items() |  | ||||||
|         # } |         landmarks.append(landmark) | ||||||
|         landmarks.append(Landmark(**landmark_data)) # Create Landmark objects |         next_uuid = landmark.next_uuid  # Prepare for the next iteration | ||||||
|         next_uuid = landmark_data.get('next_uuid')  # Prepare for the next iteration |  | ||||||
|  |  | ||||||
|     return landmarks |     return landmarks | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user