diff --git a/server/src/functions/return_historical_data/__init__.py b/server/src/functions/return_historical_data/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/server/src/functions/return_historical_data/lambda_function.py b/server/src/functions/return_historical_data/lambda_function.py new file mode 100644 index 0000000..193a5d3 --- /dev/null +++ b/server/src/functions/return_historical_data/lambda_function.py @@ -0,0 +1,51 @@ +import json +import os +import boto3 +from boto3.dynamodb.conditions import Key, Attr + +os.environ.setdefault('AWS_DEFAULT_REGION', 'us-east-1') +dynamodb = boto3.resource('dynamodb') + +def lambda_handler(event, context): + table = dynamodb.Table(os.environ['TABLE_NAME']) + + try: + if 'queryStringParameters' in event and event['queryStringParameters'] and 'objectType' in event[ + 'queryStringParameters']: + + objectType = event['queryStringParameters']['objectType'] + object_types = objectType.split(',') + + items = [] + response = table.scan( + FilterExpression=Attr('objectType').is_in(object_types) + ) + items.extend(response.get('Items', [])) + + # Handle pagination + while 'LastEvaluatedKey' in response: + response = table.scan( + FilterExpression=Attr('objectType').is_in(object_types), + ExclusiveStartKey=response['LastEvaluatedKey'] + ) + items.extend(response.get('Items', [])) + else: + # Fallback to scanning the entire table + items = [] + response = table.scan() + items.extend(response.get('Items', [])) + + while 'LastEvaluatedKey' in response: + response = table.scan(ExclusiveStartKey=response['LastEvaluatedKey']) + items.extend(response.get('Items', [])) + + return { + 'statusCode': 200, + 'body': json.dumps(items) + } + + except Exception as e: + return { + 'statusCode': 500, + 'body': json.dumps({'error': str(e)}) + } diff --git a/server/src/functions/return_permanent_data/lambda_function.py b/server/src/functions/return_permanent_data/lambda_function.py index 193a5d3..4583472 100644 --- a/server/src/functions/return_permanent_data/lambda_function.py +++ b/server/src/functions/return_permanent_data/lambda_function.py @@ -41,7 +41,7 @@ def lambda_handler(event, context): return { 'statusCode': 200, - 'body': json.dumps(items) + 'body': json.dumps(items, default=str) } except Exception as e: diff --git a/server/src/test/return_historical_data/return_historical_data.sh b/server/src/test/return_historical_data/return_historical_data.sh new file mode 100755 index 0000000..85616d1 --- /dev/null +++ b/server/src/test/return_historical_data/return_historical_data.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +API_URL="https://8g93x0lm0l.execute-api.us-east-1.amazonaws.com/return_historical_data" + +if [ "$1" ]; then + query_string="?objectType=$1" +fi + +curl "$API_URL$query_string" diff --git a/server/src/test/return_historical_data/test_return_historical_data.py b/server/src/test/return_historical_data/test_return_historical_data.py new file mode 100644 index 0000000..0bee80e --- /dev/null +++ b/server/src/test/return_historical_data/test_return_historical_data.py @@ -0,0 +1,127 @@ +import unittest +from unittest.mock import patch, MagicMock +import json +import os +from functions.return_historical_data.lambda_function import lambda_handler + + +class TestLambdaFunction(unittest.TestCase): + + # Mock environment variable before each test + def setUp(self): + patch.dict(os.environ, {'TABLE_NAME': 'test-table'}).start() + + # Clean up patches after each test + def tearDown(self): + patch.stopall() + + @patch('functions.return_historical_data.lambda_function.dynamodb.Table') + def test_lambda_handler_with_object_type(self, mock_table): + # Mock scan response for specific object types + mock_table.return_value.scan.return_value = { + 'Items': [ + {'objectID': '1', 'objectType': 'Bus'}, + {'objectID': '2', 'objectType': 'Train'} + ] + } + + # Mock event with objectType query parameter + event = { + 'queryStringParameters': { + 'objectType': 'Bus,Train' + } + } + + result = lambda_handler(event, {}) + self.assertEqual(result['statusCode'], 200) + + # Parse result body + body = json.loads(result['body']) + self.assertEqual(len(body), 2) + self.assertEqual(body[0]['objectType'], 'Bus') + self.assertEqual(body[1]['objectType'], 'Train') + + @patch('functions.return_historical_data.lambda_function.dynamodb.Table') + def test_lambda_handler_with_pagination(self, mock_table): + # Mock paginated scan responses + mock_table.return_value.scan.side_effect = [ + {'Items': [{'objectID': '1', 'objectType': 'Bus'}], 'LastEvaluatedKey': 'key1'}, + {'Items': [{'objectID': '2', 'objectType': 'Train'}], 'LastEvaluatedKey': 'key2'}, + {'Items': [{'objectID': '3', 'objectType': 'Luas'}]} + ] + + event = { + 'queryStringParameters': { + 'objectType': 'Bus,Train,Luas' + } + } + + result = lambda_handler(event, {}) + self.assertEqual(result['statusCode'], 200) + + body = json.loads(result['body']) + self.assertEqual(len(body), 3) + self.assertEqual(body[0]['objectType'], 'Bus') + self.assertEqual(body[1]['objectType'], 'Train') + self.assertEqual(body[2]['objectType'], 'Luas') + + @patch('functions.return_historical_data.lambda_function.dynamodb.Table') + def test_lambda_handler_without_object_type(self, mock_table): + # Mock scan response for full table scan + mock_table.return_value.scan.return_value = { + 'Items': [ + {'objectID': '1', 'objectType': 'Bus'}, + {'objectID': '2', 'objectType': 'Train'} + ] + } + + # Mock event without objectType query parameter + event = { + 'queryStringParameters': None + } + + result = lambda_handler(event, {}) + self.assertEqual(result['statusCode'], 200) + + body = json.loads(result['body']) + self.assertEqual(len(body), 2) + self.assertEqual(body[0]['objectType'], 'Bus') + self.assertEqual(body[1]['objectType'], 'Train') + + @patch('functions.return_historical_data.lambda_function.dynamodb.Table') + def test_lambda_handler_with_no_items(self, mock_table): + # Mock empty scan response + mock_table.return_value.scan.return_value = { + 'Items': [] + } + + # Mock event without objectType query parameter + event = { + 'queryStringParameters': None + } + + result = lambda_handler(event, {}) + self.assertEqual(result['statusCode'], 200) + + body = json.loads(result['body']) + self.assertEqual(len(body), 0) + + @patch('functions.return_historical_data.lambda_function.dynamodb.Table') + def test_lambda_handler_error(self, mock_table): + # Mock table scan to raise an exception + mock_table.return_value.scan.side_effect = Exception('DynamoDB error') + + event = { + 'queryStringParameters': None + } + + result = lambda_handler(event, {}) + self.assertEqual(result['statusCode'], 500) + + body = json.loads(result['body']) + self.assertIn('error', body) + self.assertEqual(body['error'], 'DynamoDB error') + + +if __name__ == "__main__": + unittest.main()