[server]: Add test_transient_data

This commit is contained in:
2025-03-09 23:17:36 +00:00
parent 98f26d9339
commit d257051f99

View File

@ -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):
@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.
Mocks the network requests to avoid real API calls and sets up the
expected responses for bus data and bus routes.
Args:
mock_get (MagicMock): Mocked session.get method.
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"}}}]}
# 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'], 'bus1')
self.assertEqual(result[0]['busRouteAgencyName'], 'Dublin Bus')
@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.
Mocks the network requests to avoid real API calls and sets up the
expected response for train data.
Args:
mock_get (MagicMock): Mocked session.get method.
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()
mock_response.text = '<ArrayOfObjTrainPositions><objTrainPositions><TrainCode>123</TrainCode><TrainLatitude>53.349805</TrainLatitude><TrainLongitude>-6.26031</TrainLongitude><TrainStatus>Running</TrainStatus><TrainDate>2023-10-10</TrainDate><PublicMessage>On time</PublicMessage><Direction>North</Direction></objTrainPositions></ArrayOfObjTrainPositions>'
# Fix: Ensure xmltodict.parse() returns a proper dictionary
mock_response.text = '''
<ArrayOfObjTrainPositions>
<objTrainPositions>
<TrainCode>A123</TrainCode>
<TrainLatitude>53.0</TrainLatitude>
<TrainLongitude>-6.0</TrainLongitude>
<TrainStatus>Running</TrainStatus>
<TrainDate>2025-03-09</TrainDate>
<PublicMessage>On time</PublicMessage>
<Direction>Northbound</Direction>
</objTrainPositions>
</ArrayOfObjTrainPositions>
'''
mock_get.return_value = mock_response
with patch('src.functions.transient_data.transient_data.xmltodict.parse', return_value={
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": "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')
@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 = '<stopInfo><message>On time</message><direction>North</direction></stopInfo>'
mock_get.side_effect = [mock_stops_response, mock_forecast_response]
result = fetch_luas()
self.assertGreater(len(result), 0)
self.assertIn('luasStopName', result[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": [
"objTrainPositions": [
{
"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}
}
"TrainCode": "A123",
"TrainLatitude": "53.0",
"TrainLongitude": "-6.0",
"TrainStatus": "Running",
"TrainDate": "2025-03-09",
"PublicMessage": "On time",
"Direction": "Northbound"
}
]
}
mock_get.return_value = mock_response
}
result = fetch_buses()
self.assertEqual(len(result), 1)
self.assertEqual(result[0]['busID'], '1')
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')
@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
data = [{'objectID': '1', 'objectType': 'Test'}]
batch_upload_to_dynamodb(data)
mock_batch.put_item.assert_called_once_with(Item=data[0])
@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'}]
event = {}
context = {}
result = lambda_handler(event, context)
self.assertEqual(result['statusCode'], 200)
self.assertIn('Data uploaded successfully', result['body'])
if __name__ == "__main__":
unittest.main()