Merge modifications for more separate backend functions #69
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @@ -1,324 +0,0 @@ | ||||
| """Collection of tests to ensure correct implementation and track progress.""" | ||||
| import time | ||||
| from fastapi.testclient import TestClient | ||||
| import pytest | ||||
|  | ||||
| from .test_utils import load_trip_landmarks, log_trip_details | ||||
| from ..main import app | ||||
|  | ||||
|  | ||||
| @pytest.fixture(scope="module") | ||||
| def client(): | ||||
|     """Client used to call the app.""" | ||||
|     return TestClient(app) | ||||
|  | ||||
|  | ||||
| def test_turckheim(client, request):    # pylint: disable=redefined-outer-name | ||||
|     """ | ||||
|     Test n°1 : Custom test in Turckheim to ensure small villages are also supported. | ||||
|  | ||||
|     Args: | ||||
|         client: | ||||
|         request: | ||||
|     """ | ||||
|     start_time = time.time()  # Start timer | ||||
|     duration_minutes = 20 | ||||
|  | ||||
|     response = client.post( | ||||
|         "/trip/new", | ||||
|         json={ | ||||
|             "preferences": {"sightseeing": {"type": "sightseeing", "score": 5}, | ||||
|             "nature": {"type": "nature", "score": 0}, | ||||
|             "shopping": {"type": "shopping", "score": 0}, | ||||
|             "max_time_minute": duration_minutes, | ||||
|             "detour_tolerance_minute": 0}, | ||||
|             "start": [48.084588, 7.280405] | ||||
|             # "start": [45.74445023349939, 4.8222687890538865] | ||||
|             # "start": [45.75156398104873, 4.827154464827647] | ||||
|             } | ||||
|         ) | ||||
|     result = response.json() | ||||
|     landmarks = load_trip_landmarks(client, result['first_landmark_uuid']) | ||||
|  | ||||
|  | ||||
|     # Get computation time | ||||
|     comp_time = time.time() - start_time | ||||
|  | ||||
|     # Add details to report | ||||
|     log_trip_details(request, landmarks, result['total_time'], duration_minutes) | ||||
|  | ||||
|  | ||||
|     # checks : | ||||
|     assert response.status_code == 200  # check for successful planning | ||||
|     assert isinstance(landmarks, list)  # check that the return type is a list | ||||
|     assert len(landmarks) > 2           # check that there is something to visit | ||||
|     assert comp_time < 30, f"Computation time exceeded 30 seconds: {comp_time:.2f} seconds" | ||||
|     assert duration_minutes*0.8 < result['total_time'], f"Trip too short: {result['total_time']} instead of {duration_minutes}" | ||||
|     assert duration_minutes*1.2 > result['total_time'], f"Trip too long: {result['total_time']} instead of {duration_minutes}" | ||||
|     # assert 2!= 3 | ||||
|  | ||||
| def test_bellecour(client, request) :   # pylint: disable=redefined-outer-name | ||||
|     """ | ||||
|     Test n°2 : Custom test in Lyon centre to ensure proper decision making in crowded area. | ||||
|      | ||||
|     Args: | ||||
|         client: | ||||
|         request: | ||||
|     """ | ||||
|     start_time = time.time()  # Start timer | ||||
|     duration_minutes = 120 | ||||
|  | ||||
|  | ||||
|     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": [45.7576485, 4.8330241] | ||||
|             } | ||||
|         ) | ||||
|     result = response.json() | ||||
|     landmarks = load_trip_landmarks(client, result['first_landmark_uuid']) | ||||
|  | ||||
|     # Get computation time | ||||
|     comp_time = time.time() - start_time | ||||
|  | ||||
|     # Add details to report | ||||
|     log_trip_details(request, landmarks, result['total_time'], duration_minutes) | ||||
|  | ||||
|     # checks : | ||||
|     assert response.status_code == 200  # check for successful planning | ||||
|     assert comp_time < 30, f"Computation time exceeded 30 seconds: {comp_time:.2f} seconds" | ||||
|     assert duration_minutes*0.8 < result['total_time'], f"Trip too short: {result['total_time']} instead of {duration_minutes}" | ||||
|     assert duration_minutes*1.2 > result['total_time'], f"Trip too long: {result['total_time']} instead of {duration_minutes}" | ||||
|  | ||||
|  | ||||
| def test_cologne(client, request) :   # pylint: disable=redefined-outer-name | ||||
|     """ | ||||
|     Test n°3 : Custom test in Cologne to ensure proper decision making in crowded area. | ||||
|      | ||||
|     Args: | ||||
|         client: | ||||
|         request: | ||||
|     """ | ||||
|     start_time = time.time()  # Start timer | ||||
|     duration_minutes = 240 | ||||
|  | ||||
|     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": [50.942352665, 6.957777972392] | ||||
|             } | ||||
|         ) | ||||
|     result = response.json() | ||||
|     landmarks = load_trip_landmarks(client, result['first_landmark_uuid']) | ||||
|  | ||||
|     # Get computation time | ||||
|     comp_time = time.time() - start_time | ||||
|  | ||||
|     # Add details to report | ||||
|     log_trip_details(request, landmarks, result['total_time'], duration_minutes) | ||||
|  | ||||
|     # checks : | ||||
|     assert response.status_code == 200  # check for successful planning | ||||
|     assert comp_time < 30, f"Computation time exceeded 30 seconds: {comp_time:.2f} seconds" | ||||
|     assert duration_minutes*0.8 < result['total_time'], f"Trip too short: {result['total_time']} instead of {duration_minutes}" | ||||
|     assert duration_minutes*1.2 > result['total_time'], f"Trip too long: {result['total_time']} instead of {duration_minutes}" | ||||
|  | ||||
|  | ||||
| def test_strasbourg(client, request) :   # pylint: disable=redefined-outer-name | ||||
|     """ | ||||
|     Test n°4 : Custom test in Strasbourg to ensure proper decision making in crowded area. | ||||
|      | ||||
|     Args: | ||||
|         client: | ||||
|         request: | ||||
|     """ | ||||
|     start_time = time.time()  # Start timer | ||||
|     duration_minutes = 180 | ||||
|  | ||||
|     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.5846589226, 7.74078715721] | ||||
|             } | ||||
|         ) | ||||
|     result = response.json() | ||||
|     landmarks = load_trip_landmarks(client, result['first_landmark_uuid']) | ||||
|  | ||||
|     # Get computation time | ||||
|     comp_time = time.time() - start_time | ||||
|  | ||||
|     # Add details to report | ||||
|     log_trip_details(request, landmarks, result['total_time'], duration_minutes) | ||||
|  | ||||
|     # checks : | ||||
|     assert response.status_code == 200  # check for successful planning | ||||
|     assert comp_time < 30, f"Computation time exceeded 30 seconds: {comp_time:.2f} seconds" | ||||
|     assert duration_minutes*0.8 < result['total_time'], f"Trip too short: {result['total_time']} instead of {duration_minutes}" | ||||
|     assert duration_minutes*1.2 > result['total_time'], f"Trip too long: {result['total_time']} instead of {duration_minutes}" | ||||
|  | ||||
|  | ||||
| def test_zurich(client, request) :   # pylint: disable=redefined-outer-name | ||||
|     """ | ||||
|     Test n°5 : Custom test in Zurich to ensure proper decision making in crowded area. | ||||
|      | ||||
|     Args: | ||||
|         client: | ||||
|         request: | ||||
|     """ | ||||
|     start_time = time.time()  # Start timer | ||||
|     duration_minutes = 180 | ||||
|  | ||||
|     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": [47.377884227, 8.5395114066] | ||||
|             } | ||||
|         ) | ||||
|     result = response.json() | ||||
|     landmarks = load_trip_landmarks(client, result['first_landmark_uuid']) | ||||
|  | ||||
|     # Get computation time | ||||
|     comp_time = time.time() - start_time | ||||
|  | ||||
|     # Add details to report | ||||
|     log_trip_details(request, landmarks, result['total_time'], duration_minutes) | ||||
|  | ||||
|     # checks : | ||||
|     assert response.status_code == 200  # check for successful planning | ||||
|     assert comp_time < 30, f"Computation time exceeded 30 seconds: {comp_time:.2f} seconds" | ||||
|     assert duration_minutes*0.8 < result['total_time'], f"Trip too short: {result['total_time']} instead of {duration_minutes}" | ||||
|     assert duration_minutes*1.2 > result['total_time'], f"Trip too long: {result['total_time']} instead of {duration_minutes}" | ||||
|  | ||||
|  | ||||
| def test_paris(client, request) :   # pylint: disable=redefined-outer-name | ||||
|     """ | ||||
|     Test n°6 : Custom test in Paris (les Halles) centre to ensure proper decision making in crowded area. | ||||
|      | ||||
|     Args: | ||||
|         client: | ||||
|         request: | ||||
|     """ | ||||
|     start_time = time.time()  # Start timer | ||||
|     duration_minutes = 200 | ||||
|  | ||||
|     response = client.post( | ||||
|         "/trip/new", | ||||
|         json={ | ||||
|             "preferences": {"sightseeing": {"type": "sightseeing", "score": 5}, | ||||
|                             "nature": {"type": "nature", "score": 0}, | ||||
|                             "shopping": {"type": "shopping", "score": 5}, | ||||
|                             "max_time_minute": duration_minutes, | ||||
|                             "detour_tolerance_minute": 0}, | ||||
|             "start": [48.85468881798671, 2.3423925755998374] | ||||
|             } | ||||
|         ) | ||||
|     result = response.json() | ||||
|     landmarks = load_trip_landmarks(client, result['first_landmark_uuid']) | ||||
|  | ||||
|     # Get computation time | ||||
|     comp_time = time.time() - start_time | ||||
|  | ||||
|     # Add details to report | ||||
|     log_trip_details(request, landmarks, result['total_time'], duration_minutes) | ||||
|  | ||||
|     # checks : | ||||
|     assert response.status_code == 200  # check for successful planning | ||||
|     assert comp_time < 30, f"Computation time exceeded 30 seconds: {comp_time:.2f} seconds" | ||||
|     assert duration_minutes*0.8 < result['total_time'], f"Trip too short: {result['total_time']} instead of {duration_minutes}" | ||||
|     assert duration_minutes*1.2 > result['total_time'], f"Trip too long: {result['total_time']} instead of {duration_minutes}" | ||||
|  | ||||
|  | ||||
| def test_new_york(client, request) :   # pylint: disable=redefined-outer-name | ||||
|     """ | ||||
|     Test n°7 : Custom test in New York to ensure proper decision making in crowded area. | ||||
|      | ||||
|     Args: | ||||
|         client: | ||||
|         request: | ||||
|     """ | ||||
|     start_time = time.time()  # Start timer | ||||
|     duration_minutes = 600 | ||||
|  | ||||
|     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": [40.72592726802, -73.9920434795] | ||||
|             } | ||||
|         ) | ||||
|     result = response.json() | ||||
|     landmarks = load_trip_landmarks(client, result['first_landmark_uuid']) | ||||
|  | ||||
|     # Get computation time | ||||
|     comp_time = time.time() - start_time | ||||
|  | ||||
|     # Add details to report | ||||
|     log_trip_details(request, landmarks, result['total_time'], duration_minutes) | ||||
|  | ||||
|     # checks : | ||||
|     assert response.status_code == 200  # check for successful planning | ||||
|     assert comp_time < 30, f"Computation time exceeded 30 seconds: {comp_time:.2f} seconds" | ||||
|     assert duration_minutes*0.8 < result['total_time'], f"Trip too short: {result['total_time']} instead of {duration_minutes}" | ||||
|     assert duration_minutes*1.2 > result['total_time'], f"Trip too long: {result['total_time']} instead of {duration_minutes}" | ||||
|  | ||||
|  | ||||
| def test_shopping(client, request) :   # pylint: disable=redefined-outer-name | ||||
|     """ | ||||
|     Test n°8 : Custom test in Lyon centre to ensure shopping clusters are found. | ||||
|      | ||||
|     Args: | ||||
|         client: | ||||
|         request: | ||||
|     """ | ||||
|     start_time = time.time()  # Start timer | ||||
|     duration_minutes = 240 | ||||
|  | ||||
|     response = client.post( | ||||
|         "/trip/new", | ||||
|         json={ | ||||
|             "preferences": {"sightseeing": {"type": "sightseeing", "score": 0}, | ||||
|                             "nature": {"type": "nature", "score": 0}, | ||||
|                             "shopping": {"type": "shopping", "score": 5}, | ||||
|                             "max_time_minute": duration_minutes, | ||||
|                             "detour_tolerance_minute": 0}, | ||||
|             "start": [45.7576485, 4.8330241] | ||||
|             } | ||||
|         ) | ||||
|     result = response.json() | ||||
|     landmarks = load_trip_landmarks(client, result['first_landmark_uuid']) | ||||
|  | ||||
|     # Get computation time | ||||
|     comp_time = time.time() - start_time | ||||
|  | ||||
|     # Add details to report | ||||
|     log_trip_details(request, landmarks, result['total_time'], duration_minutes) | ||||
|  | ||||
|     # checks : | ||||
|     assert response.status_code == 200  # check for successful planning | ||||
|     assert comp_time < 30, f"Computation time exceeded 30 seconds: {comp_time:.2f} seconds" | ||||
|     assert duration_minutes*0.8 < result['total_time'], f"Trip too short: {result['total_time']} instead of {duration_minutes}" | ||||
|     assert duration_minutes*1.2 > result['total_time'], f"Trip too long: {result['total_time']} instead of {duration_minutes}" | ||||
| @@ -14,43 +14,43 @@ def client(): | ||||
|     return TestClient(app) | ||||
|  | ||||
|  | ||||
| def test_bellecour(client, request) :   # pylint: disable=redefined-outer-name | ||||
|     """ | ||||
|     Test n°2 : Custom test in Lyon centre to ensure proper decision making in crowded area. | ||||
| @pytest.mark.parametrize( | ||||
|     "sightseeing, shopping, nature, max_time_minute, start_coords, end_coords", | ||||
|     [ | ||||
|         # Edge cases | ||||
|         (0, 0, 5, 240, [45.7576485, 4.8330241], None),                  # Lyon, Bellecour - test shopping only | ||||
|          | ||||
|         # Realistic | ||||
|         (5, 0, 0, 20, [48.0845881, 7.2804050], None),                   # Turckheim | ||||
|         (5, 5, 5, 120, [45.7576485, 4.8330241], None),                  # Lyon, Bellecour | ||||
|         (5, 5, 5, 240, [50.9423526, 6.9577780], None),                  # Cologne, centre | ||||
|         (5, 5, 5, 180, [48.5846589226, 7.74078715721], None),           # Strasbourg, centre | ||||
|         (5, 5, 5, 180, [47.377884227, 8.5395114066], None),             # Zurich, centre | ||||
|         (5, 0, 5, 200, [48.85468881798671, 2.3423925755998374], None),  # Paris, centre | ||||
|         (5, 5, 5, 600, [40.72592726802, -73.9920434795], None),         # New York, Lower Manhattan | ||||
|     ] | ||||
| ) | ||||
| def test_trip(client, request, sightseeing, shopping, nature, max_time_minute, start_coords, end_coords): | ||||
|  | ||||
|     Args: | ||||
|         client: | ||||
|         request: | ||||
|     """ | ||||
|     start_time = time.time()  # Start timer | ||||
|  | ||||
|     # Step 0: Define the trip preferences | ||||
|     prefs = Preferences( | ||||
|         sightseeing = Preference( | ||||
|             type='sightseeing', | ||||
|             score=5 | ||||
|         ), | ||||
|         shopping = Preference( | ||||
|             type='shopping', | ||||
|             score=5 | ||||
|         ), | ||||
|         nature = Preference( | ||||
|             type='nature', | ||||
|             score=5 | ||||
|         ), | ||||
|         max_time_minute=120, | ||||
|         sightseeing=Preference(type='sightseeing', score=sightseeing), | ||||
|         shopping=Preference(type='shopping', score=shopping), | ||||
|         nature=Preference(type='nature', score=nature), | ||||
|         max_time_minute=max_time_minute, | ||||
|         detour_tolerance_minute=0, | ||||
|     ) | ||||
|      | ||||
|     # Define the starting coordinates | ||||
|     start = [45.7576485, 4.8330241] | ||||
|     start = start_coords | ||||
|     end = end_coords | ||||
|  | ||||
|     # Step 1: request the list of landmarks in the vicinty of the starting point | ||||
|     response = client.post( | ||||
|         "/get/landmarks", | ||||
|         json={ | ||||
|             "preferences": prefs.model_dump(), | ||||
|             "start": start | ||||
|             "start": start_coords, | ||||
|             "end": end_coords, | ||||
|             } | ||||
|         ) | ||||
|     landmarks = response.json() | ||||
| @@ -61,7 +61,8 @@ def test_bellecour(client, request) :   # pylint: disable=redefined-outer-name | ||||
|         json={ | ||||
|             "preferences": prefs.model_dump(), | ||||
|             "landmarks": landmarks, | ||||
|             "start": start | ||||
|             "start": start, | ||||
|             "end": end, | ||||
|             } | ||||
|         ) | ||||
|     result = response.json() | ||||
|   | ||||
| @@ -1,9 +1,12 @@ | ||||
| """Helper methods for testing.""" | ||||
| import time | ||||
| import logging | ||||
| from functools import wraps | ||||
| from fastapi import HTTPException | ||||
|  | ||||
| from ..structs.landmark import Landmark | ||||
| from ..cache import client as cache_client | ||||
| from ..structs.landmark import Landmark | ||||
| from ..structs.preferences import Preferences, Preference | ||||
|  | ||||
|  | ||||
| def landmarks_to_osmid(landmarks: list[Landmark]) -> list[int] : | ||||
| @@ -91,3 +94,34 @@ def log_trip_details(request, landmarks: list[Landmark], duration: int, target_d | ||||
|     request.node.trip_details = trip_string | ||||
|     request.node.trip_duration = str(duration)              # result['total_time'] | ||||
|     request.node.target_duration = str(target_duration) | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| def trip_params( | ||||
|     sightseeing: int, | ||||
|     shopping: int, | ||||
|     nature: int, | ||||
|     max_time_minute: int, | ||||
|     start_coords: tuple[float, float] = None, | ||||
|     end_coords: tuple[float, float] = None, | ||||
| ): | ||||
|     def decorator(test_func): | ||||
|         @wraps(test_func) | ||||
|         def wrapper(client, request): | ||||
|             prefs = Preferences( | ||||
|                 sightseeing=Preference(type='sightseeing', score=sightseeing), | ||||
|                 shopping=Preference(type='shopping', score=shopping), | ||||
|                 nature=Preference(type='nature', score=nature), | ||||
|                 max_time_minute=max_time_minute, | ||||
|                 detour_tolerance_minute=0, | ||||
|             ) | ||||
|  | ||||
|             start = start_coords | ||||
|             end = end_coords | ||||
|  | ||||
|             # Inject into test function | ||||
|             return test_func(client, request, prefs, start, end) | ||||
|  | ||||
|         return wrapper | ||||
|     return decorator | ||||
		Reference in New Issue
	
	Block a user