more testing and better pylint score
	
		
			
	
		
	
	
		
	
		
			Some checks failed
		
		
	
	
		
			
				
	
				Build and deploy the backend to staging / Build and push image (pull_request) Successful in 1m48s
				
			
		
			
				
	
				Run linting on the backend code / Build (pull_request) Failing after 29s
				
			
		
			
				
	
				Run testing on the backend code / Build (pull_request) Failing after 1m13s
				
			
		
			
				
	
				Build and deploy the backend to staging / Deploy to staging (pull_request) Successful in 47s
				
			
		
		
	
	
				
					
				
			
		
			Some checks failed
		
		
	
	Build and deploy the backend to staging / Build and push image (pull_request) Successful in 1m48s
				
			Run linting on the backend code / Build (pull_request) Failing after 29s
				
			Run testing on the backend code / Build (pull_request) Failing after 1m13s
				
			Build and deploy the backend to staging / Deploy to staging (pull_request) Successful in 47s
				
			This commit is contained in:
		
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @@ -39,6 +39,8 @@ def new_trip(preferences: Preferences, start: tuple[float, float], end: tuple[fl | |||||||
|         raise HTTPException(status_code=406, detail="All preferences are 0.") |         raise HTTPException(status_code=406, detail="All preferences are 0.") | ||||||
|     if start is None: |     if start is None: | ||||||
|         raise HTTPException(status_code=406, detail="Start coordinates not provided") |         raise HTTPException(status_code=406, detail="Start coordinates not provided") | ||||||
|  |     if not (-90 <= start[0] <= 90 or -180 <= start[1] <= 180): | ||||||
|  |         raise HTTPException(status_code=423, detail="Start coordinates not in range") | ||||||
|     if end is None: |     if end is None: | ||||||
|         end = start |         end = start | ||||||
|         logger.info("No end coordinates provided. Using start=end.") |         logger.info("No end coordinates provided. Using start=end.") | ||||||
| @@ -59,10 +61,10 @@ def new_trip(preferences: Preferences, start: tuple[float, float], end: tuple[fl | |||||||
|     # First stage optimization |     # First stage optimization | ||||||
|     try: |     try: | ||||||
|         base_tour = optimizer.solve_optimization(preferences.max_time_minute, landmarks_short) |         base_tour = optimizer.solve_optimization(preferences.max_time_minute, landmarks_short) | ||||||
|     except ArithmeticError: |     except ArithmeticError as exc: | ||||||
|         raise HTTPException(status_code=500, detail="No solution found") |         raise HTTPException(status_code=500, detail="No solution found") from exc | ||||||
|     except TimeoutError: |     except TimeoutError as exc: | ||||||
|         raise HTTPException(status_code=500, detail="Optimzation took too long") |         raise HTTPException(status_code=500, detail="Optimzation took too long") from exc | ||||||
|  |  | ||||||
|     # Second stage optimization |     # Second stage optimization | ||||||
|     refined_tour = refiner.refine_optimization(landmarks, base_tour, preferences.max_time_minute, preferences.detour_tolerance_minute) |     refined_tour = refiner.refine_optimization(landmarks, base_tour, preferences.max_time_minute, preferences.detour_tolerance_minute) | ||||||
| @@ -88,8 +90,8 @@ def get_trip(trip_uuid: str) -> Trip: | |||||||
|     try: |     try: | ||||||
|         trip = cache_client.get(f"trip_{trip_uuid}") |         trip = cache_client.get(f"trip_{trip_uuid}") | ||||||
|         return trip |         return trip | ||||||
|     except KeyError: |     except KeyError as exc: | ||||||
|         raise HTTPException(status_code=404, detail="Trip not found") |         raise HTTPException(status_code=404, detail="Trip not found") from exc | ||||||
|  |  | ||||||
|  |  | ||||||
| @app.get("/landmark/{landmark_uuid}") | @app.get("/landmark/{landmark_uuid}") | ||||||
| @@ -106,5 +108,5 @@ def get_landmark(landmark_uuid: str) -> Landmark: | |||||||
|     try: |     try: | ||||||
|         landmark = cache_client.get(f"landmark_{landmark_uuid}") |         landmark = cache_client.get(f"landmark_{landmark_uuid}") | ||||||
|         return landmark |         return landmark | ||||||
|     except KeyError: |     except KeyError as exc: | ||||||
|         raise HTTPException(status_code=404, detail="Landmark not found") |         raise HTTPException(status_code=404, detail="Landmark not found") from exc | ||||||
|   | |||||||
| @@ -71,8 +71,10 @@ sightseeing: | |||||||
|     - castle |     - castle | ||||||
|     - museum |     - museum | ||||||
|  |  | ||||||
|  | museums: | ||||||
|  |   tourism: | ||||||
|  |     - museum | ||||||
|  |     - aquarium | ||||||
|  |  | ||||||
| # to be used later on | # to be used later on | ||||||
| restauration: | restauration: | ||||||
|   | |||||||
| @@ -28,7 +28,7 @@ class DummyClient: | |||||||
|             dictionary. |             dictionary. | ||||||
|     """ |     """ | ||||||
|     _data = {} |     _data = {} | ||||||
|     def set(self, key, value, **kwargs): |     def set(self, key, value, **kwargs):    # pylint: disable=unused-argument | ||||||
|         """ |         """ | ||||||
|         Store a key-value pair in the internal dictionary. |         Store a key-value pair in the internal dictionary. | ||||||
|  |  | ||||||
| @@ -39,7 +39,7 @@ class DummyClient: | |||||||
|         """ |         """ | ||||||
|         self._data[key] = value |         self._data[key] = value | ||||||
|  |  | ||||||
|     def set_many(self, data, **kwargs): |     def set_many(self, data, **kwargs): # pylint: disable=unused-argument | ||||||
|         """ |         """ | ||||||
|         Update the internal dictionary with multiple key-value pairs. |         Update the internal dictionary with multiple key-value pairs. | ||||||
|  |  | ||||||
| @@ -49,7 +49,7 @@ class DummyClient: | |||||||
|         """ |         """ | ||||||
|         self._data.update(data) |         self._data.update(data) | ||||||
|  |  | ||||||
|     def get(self, key, **kwargs): |     def get(self, key, **kwargs):   # pylint: disable=unused-argument | ||||||
|         """ |         """ | ||||||
|         Retrieve the value associated with the given key. |         Retrieve the value associated with the given key. | ||||||
|  |  | ||||||
|   | |||||||
| @@ -71,9 +71,11 @@ class Landmark(BaseModel) : | |||||||
|             time to the next landmark (if available), and whether the landmark is secondary. |             time to the next landmark (if available), and whether the landmark is secondary. | ||||||
|         """ |         """ | ||||||
|         time_to_next_str = f", time_to_next={self.time_to_reach_next}" if self.time_to_reach_next else "" |         time_to_next_str = f", time_to_next={self.time_to_reach_next}" if self.time_to_reach_next else "" | ||||||
|         is_secondary_str = f", secondary" if self.is_secondary else "" |         is_secondary_str = ", secondary" if self.is_secondary else "" | ||||||
|         type_str = '(' + self.type + ')' |         type_str = '(' + self.type + ')' | ||||||
|         if self.type in ["start", "finish", "nature", "shopping"] : type_str += '\t ' |         if self.type in ["start", "finish", "nature", "shopping"] : | ||||||
|  |             type_str += '\t ' | ||||||
|  |  | ||||||
|         return f'Landmark{type_str}: [{self.name} @{self.location}, score={self.attractiveness}{time_to_next_str}{is_secondary_str}]' |         return f'Landmark{type_str}: [{self.name} @{self.location}, score={self.attractiveness}{time_to_next_str}{is_secondary_str}]' | ||||||
|  |  | ||||||
|     def distance(self, value: 'Landmark') -> float: |     def distance(self, value: 'Landmark') -> float: | ||||||
|   | |||||||
| @@ -11,7 +11,7 @@ class LinkedLandmarks: | |||||||
|     to reference the next landmark in the list. This is not very efficient, but appropriate for the expected use case |     to reference the next landmark in the list. This is not very efficient, but appropriate for the expected use case | ||||||
|     ("short" trips with onyl few landmarks). |     ("short" trips with onyl few landmarks). | ||||||
|     """ |     """ | ||||||
|      |  | ||||||
|     _landmarks = list[Landmark] |     _landmarks = list[Landmark] | ||||||
|     total_time: int = 0 |     total_time: int = 0 | ||||||
|  |  | ||||||
|   | |||||||
| @@ -30,5 +30,5 @@ class Preferences(BaseModel) : | |||||||
|     # Shopping (diriger plutôt vers des zones / rues commerçantes) |     # Shopping (diriger plutôt vers des zones / rues commerçantes) | ||||||
|     shopping : Preference |     shopping : Preference | ||||||
|  |  | ||||||
|     max_time_minute: Optional[int] = 6*60 |     max_time_minute: Optional[int] = 3*60 | ||||||
|     detour_tolerance_minute: Optional[int] = 0 |     detour_tolerance_minute: Optional[int] = 0 | ||||||
|   | |||||||
| @@ -25,7 +25,7 @@ class Trip(BaseModel): | |||||||
|  |  | ||||||
|  |  | ||||||
|     @classmethod |     @classmethod | ||||||
|     def from_linked_landmarks(self, landmarks: LinkedLandmarks, cache_client: Client) -> "Trip": |     def from_linked_landmarks(cls, landmarks: LinkedLandmarks, cache_client: Client) -> "Trip": | ||||||
|         """ |         """ | ||||||
|         Initialize a new Trip object and ensure it is stored in the cache. |         Initialize a new Trip object and ensure it is stored in the cache. | ||||||
|         """ |         """ | ||||||
|   | |||||||
							
								
								
									
										62
									
								
								backend/src/tests/test_invalid_input.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								backend/src/tests/test_invalid_input.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | |||||||
|  | """Collection of tests to ensure correct handling of invalid input.""" | ||||||
|  |  | ||||||
|  | from fastapi.testclient import TestClient | ||||||
|  | import pytest | ||||||
|  |  | ||||||
|  | from ..main import app | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.fixture(scope="module") | ||||||
|  | def invalid_client(): | ||||||
|  |     """Client used to call the app.""" | ||||||
|  |     return TestClient(app) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize( | ||||||
|  |     "start,preferences,status_code", | ||||||
|  |     [ | ||||||
|  |         # Invalid case: no preferences at all. | ||||||
|  |         ([48.8566, 2.3522], {}, 422), | ||||||
|  |  | ||||||
|  |         # Invalid cases: incomplete preferences. | ||||||
|  |         ([48.084588, 7.280405], {"sightseeing": {"type": "nature", "score": 5}, # no shopping | ||||||
|  |                                  "nature": {"type": "nature", "score": 5}, | ||||||
|  |                                  }, 422), | ||||||
|  |         ([48.084588, 7.280405], {"sightseeing": {"type": "nature", "score": 5}, # no nature | ||||||
|  |                                  "shopping": {"type": "shopping", "score": 5}, | ||||||
|  |                                  }, 422), | ||||||
|  |         ([48.084588, 7.280405], {"nature": {"type": "nature", "score": 5},      # no sightseeing | ||||||
|  |                                  "shopping": {"type": "shopping", "score": 5}, | ||||||
|  |                                  }, 422), | ||||||
|  |  | ||||||
|  |         # Invalid cases: unexisting coords | ||||||
|  |         ([91, 181], {"sightseeing": {"type": "nature", "score": 5}, | ||||||
|  |                      "nature": {"type": "nature", "score": 5}, | ||||||
|  |                      "shopping": {"type": "shopping", "score": 5}, | ||||||
|  |                     }, 423), | ||||||
|  |         ([-91, 181], {"sightseeing": {"type": "nature", "score": 5}, | ||||||
|  |                      "nature": {"type": "nature", "score": 5}, | ||||||
|  |                      "shopping": {"type": "shopping", "score": 5}, | ||||||
|  |                     }, 423), | ||||||
|  |         ([91, -181], {"sightseeing": {"type": "nature", "score": 5}, | ||||||
|  |                      "nature": {"type": "nature", "score": 5}, | ||||||
|  |                      "shopping": {"type": "shopping", "score": 5}, | ||||||
|  |                     }, 423), | ||||||
|  |         ([-91, -181], {"sightseeing": {"type": "nature", "score": 5}, | ||||||
|  |                      "nature": {"type": "nature", "score": 5}, | ||||||
|  |                      "shopping": {"type": "shopping", "score": 5}, | ||||||
|  |                     }, 423), | ||||||
|  |     ] | ||||||
|  | ) | ||||||
|  | def test_input(invalid_client, start, preferences, status_code):   # pylint: disable=redefined-outer-name | ||||||
|  |     """ | ||||||
|  |     Test new trip creation with different sets of preferences and locations. | ||||||
|  |     """ | ||||||
|  |     response = invalid_client.post( | ||||||
|  |         "/trip/new", | ||||||
|  |         json={ | ||||||
|  |             "preferences": preferences, | ||||||
|  |             "start": start | ||||||
|  |         } | ||||||
|  |     ) | ||||||
|  |     assert response.status_code == status_code | ||||||
| @@ -1,38 +1,20 @@ | |||||||
| """Collection of tests to ensure correct implementation and track progress. """ | """Collection of tests to ensure correct implementation and track progress. """ | ||||||
|  |  | ||||||
| from typing import List |  | ||||||
| from fastapi.testclient import TestClient | from fastapi.testclient import TestClient | ||||||
| import pytest | import pytest | ||||||
|  |  | ||||||
|  | from .test_utils import landmarks_to_osmid, load_trip_landmarks, log_trip_details | ||||||
| from ..main import app | from ..main import app | ||||||
| from ..structs.landmark import Landmark |  | ||||||
|  |  | ||||||
|  | @pytest.fixture(scope="module") | ||||||
| @pytest.fixture() |  | ||||||
| def client(): | def client(): | ||||||
|  |     """Client used to call the app.""" | ||||||
|     return TestClient(app) |     return TestClient(app) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_new_trip_invalid_prefs(client): | def test_turckheim(client, request):    # pylint: disable=redefined-outer-name | ||||||
|     """ |     """ | ||||||
|     Test n°1 : base test for checking if the API returns correct error code when no preferences are specified. |     Test n°1 : Custom test in Turckheim to ensure small villages are also supported. | ||||||
|  |  | ||||||
|     Args: |  | ||||||
|         client: |  | ||||||
|     """ |  | ||||||
|     response = client.post( |  | ||||||
|         "/trip/new", |  | ||||||
|         json={ |  | ||||||
|             "preferences": {}, |  | ||||||
|             "start": [48.8566, 2.3522] |  | ||||||
|             } |  | ||||||
|         ) |  | ||||||
|     assert response.status_code == 422 |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_turckheim(client, request): |  | ||||||
|     """ |  | ||||||
|     Test n°2 : Custom test in Turckheim to ensure small villages are also supported. |  | ||||||
|  |  | ||||||
|     Args: |     Args: | ||||||
|         client: |         client: | ||||||
| @@ -42,7 +24,11 @@ def test_turckheim(client, request): | |||||||
|     response = client.post( |     response = client.post( | ||||||
|         "/trip/new", |         "/trip/new", | ||||||
|         json={ |         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}, |             "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] |             "start": [48.084588, 7.280405] | ||||||
|             } |             } | ||||||
|         ) |         ) | ||||||
| @@ -59,16 +45,15 @@ def test_turckheim(client, request): | |||||||
|     assert len(landmarks) > 2           # check that there is something to visit |     assert len(landmarks) > 2           # check that there is something to visit | ||||||
|  |  | ||||||
|  |  | ||||||
| # Test no. 3 | def test_bellecour(client, request) :   # pylint: disable=redefined-outer-name | ||||||
| def test_bellecour(client, request) : |  | ||||||
|     """ |     """ | ||||||
|     Test n°3 : Custom test in Lyon centre to ensure proper decision making in crowded area. |     Test n°2 : Custom test in Lyon centre to ensure proper decision making in crowded area. | ||||||
|      |      | ||||||
|     Args: |     Args: | ||||||
|         client: |         client: | ||||||
|         request: |         request: | ||||||
|     """ |     """ | ||||||
|     duration_minutes = 60 |     duration_minutes = 30 | ||||||
|     response = client.post( |     response = client.post( | ||||||
|         "/trip/new", |         "/trip/new", | ||||||
|         json={ |         json={ | ||||||
| @@ -90,89 +75,6 @@ def test_bellecour(client, request) : | |||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def landmarks_to_osmid(landmarks: List[Landmark]) -> List[int] : |  | ||||||
|     """ |  | ||||||
|     Convert the list of landmarks into a list containing their osm ids for quick landmark checking. |  | ||||||
|      |  | ||||||
|     Args : |  | ||||||
|         landmarks (list): the list of landmarks |  | ||||||
|      |  | ||||||
|     Returns : |  | ||||||
|         ids (list)      : the list of corresponding OSM ids |  | ||||||
|     """ |  | ||||||
|     ids = [] |  | ||||||
|     for landmark in landmarks : |  | ||||||
|         ids.append(landmark.osm_id) |  | ||||||
|  |  | ||||||
|     return ids |  | ||||||
|  |  | ||||||
| def fetch_landmark(client, landmark_uuid: str): |  | ||||||
|     """ |  | ||||||
|     Fetch landmark data from the API based on the landmark UUID. |  | ||||||
|  |  | ||||||
|     Args: |  | ||||||
|         landmark_uuid (str): The UUID of the landmark. |  | ||||||
|  |  | ||||||
|     Returns: |  | ||||||
|         dict: Landmark data fetched from the API. |  | ||||||
|     """ |  | ||||||
|     response = client.get(f"/landmark/{landmark_uuid}") |  | ||||||
|  |  | ||||||
|     if response.status_code != 200: |  | ||||||
|         raise Exception(f"Failed to fetch landmark with UUID {landmark_uuid}: {response.status_code}") |  | ||||||
|  |  | ||||||
|     json_data = response.json() |  | ||||||
|  |  | ||||||
|     if "detail" in json_data: |  | ||||||
|         raise Exception(json_data["detail"]) |  | ||||||
|  |  | ||||||
|     return json_data |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def load_trip_landmarks(client, first_uuid: str) -> List[Landmark]: |  | ||||||
|     """ |  | ||||||
|     Load all landmarks for a trip using the response from the API. |  | ||||||
|  |  | ||||||
|     Args: |  | ||||||
|         first_uuid (str) : The first UUID of the landmark. |  | ||||||
|  |  | ||||||
|     Returns: |  | ||||||
|         landmarks (list) : An list containing all landmarks for the trip. |  | ||||||
|     """ |  | ||||||
|     landmarks = [] |  | ||||||
|     next_uuid = first_uuid |  | ||||||
|  |  | ||||||
|     while next_uuid is not None: |  | ||||||
|         landmark_data = fetch_landmark(client, next_uuid) |  | ||||||
|         # # Convert UUIDs to strings explicitly |  | ||||||
|         # landmark_data = { |  | ||||||
|         #     key: str(value) if isinstance(value, UUID) else value |  | ||||||
|         #     for key, value in landmark_data.items() |  | ||||||
|         # } |  | ||||||
|         landmarks.append(Landmark(**landmark_data)) # Create Landmark objects |  | ||||||
|         next_uuid = landmark_data.get('next_uuid')  # Prepare for the next iteration |  | ||||||
|  |  | ||||||
|     return landmarks |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def log_trip_details(request, landmarks: List[Landmark], duration: int, target_duration: int) : |  | ||||||
|     """ |  | ||||||
|     Allows to show the detailed trip in the html test report. |  | ||||||
|      |  | ||||||
|     Args: |  | ||||||
|         request: |  | ||||||
|         landmarks (list): the ordered list of visited landmarks  |  | ||||||
|         duration (int): the total duration of this trip |  | ||||||
|         target_duration(int): the target duration of this trip |  | ||||||
|     """ |  | ||||||
|     trip_string = [f"{landmark.name} ({landmark.attractiveness} | {landmark.duration}) - {landmark.time_to_reach_next}" for landmark in landmarks] |  | ||||||
|  |  | ||||||
|     # Pass additional info to pytest for reporting |  | ||||||
|     request.node.trip_details = trip_string |  | ||||||
|     request.node.trip_duration = str(duration)              # result['total_time'] |  | ||||||
|     request.node.target_duration = str(target_duration) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| # def test_new_trip_single_prefs(client): | # def test_new_trip_single_prefs(client): | ||||||
| #     response = client.post( | #     response = client.post( | ||||||
| #         "/trip/new", | #         "/trip/new", | ||||||
| @@ -185,5 +87,4 @@ def log_trip_details(request, landmarks: List[Landmark], duration: int, target_d | |||||||
|  |  | ||||||
|  |  | ||||||
| # def test_new_trip_matches_prefs(client): | # def test_new_trip_matches_prefs(client): | ||||||
| #     # todo |  | ||||||
| #     pass | #     pass | ||||||
|   | |||||||
							
								
								
									
										89
									
								
								backend/src/tests/test_utils.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								backend/src/tests/test_utils.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,89 @@ | |||||||
|  | """Helper methods for testing.""" | ||||||
|  | from typing import List | ||||||
|  | from fastapi import HTTPException | ||||||
|  |  | ||||||
|  | from ..structs.landmark import Landmark | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def landmarks_to_osmid(landmarks: List[Landmark]) -> List[int] : | ||||||
|  |     """ | ||||||
|  |     Convert the list of landmarks into a list containing their osm ids for quick landmark checking. | ||||||
|  |      | ||||||
|  |     Args : | ||||||
|  |         landmarks (list): the list of landmarks | ||||||
|  |      | ||||||
|  |     Returns : | ||||||
|  |         ids (list)      : the list of corresponding OSM ids | ||||||
|  |     """ | ||||||
|  |     ids = [] | ||||||
|  |     for landmark in landmarks : | ||||||
|  |         ids.append(landmark.osm_id) | ||||||
|  |  | ||||||
|  |     return ids | ||||||
|  |  | ||||||
|  | def fetch_landmark(client, landmark_uuid: str): | ||||||
|  |     """ | ||||||
|  |     Fetch landmark data from the API based on the landmark UUID. | ||||||
|  |  | ||||||
|  |     Args: | ||||||
|  |         landmark_uuid (str): The UUID of the landmark. | ||||||
|  |  | ||||||
|  |     Returns: | ||||||
|  |         dict: Landmark data fetched from the API. | ||||||
|  |     """ | ||||||
|  |     response = client.get(f"/landmark/{landmark_uuid}") | ||||||
|  |  | ||||||
|  |     if response.status_code != 200: | ||||||
|  |         raise HTTPException(status_code=999, detail=f"Failed to fetch landmark with UUID {landmark_uuid}: {response.status_code}") | ||||||
|  |  | ||||||
|  |     json_data = response.json() | ||||||
|  |  | ||||||
|  |     if "detail" in json_data: | ||||||
|  |         raise HTTPException(status_code=999, detail=json_data["detail"]) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     return json_data | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def load_trip_landmarks(client, first_uuid: str) -> List[Landmark]: | ||||||
|  |     """ | ||||||
|  |     Load all landmarks for a trip using the response from the API. | ||||||
|  |  | ||||||
|  |     Args: | ||||||
|  |         first_uuid (str) : The first UUID of the landmark. | ||||||
|  |  | ||||||
|  |     Returns: | ||||||
|  |         landmarks (list) : An list containing all landmarks for the trip. | ||||||
|  |     """ | ||||||
|  |     landmarks = [] | ||||||
|  |     next_uuid = first_uuid | ||||||
|  |  | ||||||
|  |     while next_uuid is not None: | ||||||
|  |         landmark_data = fetch_landmark(client, next_uuid) | ||||||
|  |         # # Convert UUIDs to strings explicitly | ||||||
|  |         # landmark_data = { | ||||||
|  |         #     key: str(value) if isinstance(value, UUID) else value | ||||||
|  |         #     for key, value in landmark_data.items() | ||||||
|  |         # } | ||||||
|  |         landmarks.append(Landmark(**landmark_data)) # Create Landmark objects | ||||||
|  |         next_uuid = landmark_data.get('next_uuid')  # Prepare for the next iteration | ||||||
|  |  | ||||||
|  |     return landmarks | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def log_trip_details(request, landmarks: List[Landmark], duration: int, target_duration: int) : | ||||||
|  |     """ | ||||||
|  |     Allows to show the detailed trip in the html test report. | ||||||
|  |      | ||||||
|  |     Args: | ||||||
|  |         request: | ||||||
|  |         landmarks (list): the ordered list of visited landmarks  | ||||||
|  |         duration (int): the total duration of this trip | ||||||
|  |         target_duration(int): the target duration of this trip | ||||||
|  |     """ | ||||||
|  |     trip_string = [f"{landmark.name} ({landmark.attractiveness} | {landmark.duration}) - {landmark.time_to_reach_next}" for landmark in landmarks] | ||||||
|  |  | ||||||
|  |     # Pass additional info to pytest for reporting | ||||||
|  |     request.node.trip_details = trip_string | ||||||
|  |     request.node.trip_duration = str(duration)              # result['total_time'] | ||||||
|  |     request.node.target_duration = str(target_duration) | ||||||
		Reference in New Issue
	
	Block a user