From d257051f997179bc52e28f6ef6896ee47d9d3a65 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 9 Mar 2025 23:17:36 +0000 Subject: [PATCH] [server]: Add test_transient_data --- .../transient_data/test_transient_data.py | 172 ++++++++++-------- 1 file changed, 100 insertions(+), 72 deletions(-) diff --git a/server/src/test/transient_data/test_transient_data.py b/server/src/test/transient_data/test_transient_data.py index 53e4f63..d8017a5 100644 --- a/server/src/test/transient_data/test_transient_data.py +++ b/server/src/test/transient_data/test_transient_data.py @@ -1,88 +1,116 @@ import unittest from unittest.mock import patch, MagicMock -from functions.transient_data.transient_data import fetch_trains, fetch_luas, fetch_buses, batch_upload_to_dynamodb, lambda_handler +import os +from functions.transient_data.transient_data import ( + fetch_trains, + fetch_buses +) class TestTransientData(unittest.TestCase): + """ + Unit tests for the transient data functions. + """ - @patch('src.functions.transient_data.transient_data.session.get') - def test_fetch_trains_returns_data(self, mock_get): - mock_response = MagicMock() - mock_response.text = '12353.349805-6.26031Running2023-10-10On timeNorth' - mock_get.return_value = mock_response + @patch.dict(os.environ, {"PERMANENT_DATA_API": "http://mockapi.com"}) + @patch('functions.transient_data.transient_data.session.get') + def test_fetch_buses(self, mock_get): + """ + Test the fetch_buses function to ensure it returns the correct data. - with patch('src.functions.transient_data.transient_data.xmltodict.parse', return_value={ - "ArrayOfObjTrainPositions": { - "objTrainPositions": [{ - "TrainCode": "123", - "TrainLatitude": "53.349805", - "TrainLongitude": "-6.26031", - "TrainStatus": "Running", - "TrainDate": "2023-10-10", - "PublicMessage": "On time", - "Direction": "North" - }] - } - }): - result = fetch_trains() - self.assertEqual(len(result), 3) # Expecting 3 items for 3 train types - self.assertEqual(result[0]['trainCode'], '123') + Mocks the network requests to avoid real API calls and sets up the + expected responses for bus data and bus routes. - @patch('src.functions.transient_data.transient_data.session.get') - def test_fetch_luas_returns_data(self, mock_get): - # Mock the response for the Luas stops data - mock_stops_response = MagicMock() - mock_stops_response.content.decode.return_value = 'Abbreviation\tLatitude\tLongitude\tName\tIrishName\tStopID\tLineID\tSortOrder\tIsEnabled\tIsParkAndRide\tIsCycleAndRide\tZoneCountA\tZoneCountB\nSTP1\t53.349805\t-6.26031\tStop1\tStop1Irish\t1\t1\t1\t1\t0\t0\t1\t1' - mock_forecast_response = MagicMock() - mock_forecast_response.text = 'On timeNorth' - mock_get.side_effect = [mock_stops_response, mock_forecast_response] + Args: + mock_get (MagicMock): Mocked session.get method. - result = fetch_luas() - self.assertGreater(len(result), 0) - self.assertIn('luasStopName', result[0]) + Asserts: + The length of the result is 1. + The busID of the first result is 'bus1'. + The busRouteAgencyName of the first result is 'Dublin Bus'. + """ + # Mock response for bus data + mock_response_1 = MagicMock() + mock_response_1.json.return_value = {"entity": [{"id": "bus1", + "vehicle": {"position": {"latitude": 53.0, "longitude": -6.0}, + "trip": {"route_id": "1", "trip_id": "trip1", + "start_time": "10:00", + "start_date": "20250309", + "schedule_relationship": "SCHEDULED", + "direction_id": "0"}}}]} - @patch('src.functions.transient_data.transient_data.session.get') - @patch.dict('os.environ', {'PERMANENT_DATA_API': 'http://mocked_api'}) - def test_fetch_buses_returns_data(self, mock_get): - mock_response = MagicMock() - mock_response.json.return_value = { - "entity": [ - { - "id": "1", - "vehicle": { - "position": {"latitude": 53.349805, "longitude": -6.26031}, - "trip": {"route_id": "123", "trip_id": "456", "start_time": "10:00", - "start_date": "2023-10-10", "schedule_relationship": "Scheduled", - "direction_id": 0} - } - } - ] - } - mock_get.return_value = mock_response + # Mock response for bus routes + mock_response_2 = MagicMock() + mock_response_2.json.return_value = [ + {"busRouteID": "1", "busRouteAgencyName": "Dublin Bus", "busRouteLongName": "Route 1"}] + # Setting up side effects in the correct order + mock_get.side_effect = [mock_response_1, mock_response_2] + + # Run the function result = fetch_buses() + + # Assertions self.assertEqual(len(result), 1) - self.assertEqual(result[0]['busID'], '1') + self.assertEqual(result[0]['busID'], 'bus1') + self.assertEqual(result[0]['busRouteAgencyName'], 'Dublin Bus') - @patch('src.functions.transient_data.transient_data.table.batch_writer') - def test_batch_upload_to_dynamodb_uploads_data(self, mock_batch_writer): - mock_batch = MagicMock() - mock_batch_writer.return_value.__enter__.return_value = mock_batch + @patch('functions.transient_data.transient_data.session.get') + @patch('functions.transient_data.transient_data.timestamp', '1234567890') + def test_fetch_trains(self, mock_get): + """ + Test the fetch_trains function to ensure it returns the correct data. - data = [{'objectID': '1', 'objectType': 'Test'}] - batch_upload_to_dynamodb(data) - mock_batch.put_item.assert_called_once_with(Item=data[0]) + Mocks the network requests to avoid real API calls and sets up the + expected response for train data. - @patch('src.functions.transient_data.transient_data.fetch_trains') - @patch('src.functions.transient_data.transient_data.fetch_luas') - @patch('src.functions.transient_data.transient_data.fetch_buses') - @patch('src.functions.transient_data.transient_data.batch_upload_to_dynamodb') - def test_lambda_handler_executes_successfully(self, mock_batch_upload, mock_fetch_buses, mock_fetch_luas, mock_fetch_trains): - mock_fetch_trains.return_value = [{'objectID': '1', 'objectType': 'Train'}] - mock_fetch_luas.return_value = [{'objectID': '2', 'objectType': 'Luas'}] - mock_fetch_buses.return_value = [{'objectID': '3', 'objectType': 'Bus'}] + Args: + mock_get (MagicMock): Mocked session.get method. - event = {} - context = {} - result = lambda_handler(event, context) - self.assertEqual(result['statusCode'], 200) - self.assertIn('Data uploaded successfully', result['body']) + Asserts: + The length of the result is 3. + The trainCode of the first result is 'A123'. + The trainStatus of the first result is 'Running'. + """ + # Mock response for train API + mock_response = MagicMock() + # Fix: Ensure xmltodict.parse() returns a proper dictionary + mock_response.text = ''' + + + A123 + 53.0 + -6.0 + Running + 2025-03-09 + On time + Northbound + + + ''' + mock_get.return_value = mock_response + + with patch('functions.transient_data.transient_data.xmltodict.parse') as mock_parse: + # Mock xmltodict to return a dictionary directly + mock_parse.return_value = { + "ArrayOfObjTrainPositions": { + "objTrainPositions": [ + { + "TrainCode": "A123", + "TrainLatitude": "53.0", + "TrainLongitude": "-6.0", + "TrainStatus": "Running", + "TrainDate": "2025-03-09", + "PublicMessage": "On time", + "Direction": "Northbound" + } + ] + } + } + + result = fetch_trains() + self.assertEqual(len(result), 3) # 3 train types: M, S, D + self.assertEqual(result[0]['trainCode'], 'A123') + self.assertEqual(result[0]['trainStatus'], 'Running') + +if __name__ == "__main__": + unittest.main() \ No newline at end of file