Skip to content

Commit 46357d7

Browse files
committed
Good Tests
1 parent 59c06ec commit 46357d7

File tree

5 files changed

+102
-82
lines changed

5 files changed

+102
-82
lines changed

delta_backend/src/delta.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ def send_message(record):
2828
sqs_client.send_message(QueueUrl=failure_queue_url, MessageBody=json.dumps(message_body))
2929
logger.info("Record saved successfully to the DLQ")
3030
except ClientError as e:
31-
logger.info(f"Error sending record to DLQ: {e}")
31+
logger.error(f"Error sending record to DLQ: {e}")
3232

3333

3434
def get_vaccine_type(patientsk) -> str:
@@ -37,7 +37,7 @@ def get_vaccine_type(patientsk) -> str:
3737

3838

3939
def handler(event, context):
40-
40+
firehose_logger.send_log(event)
4141
logger.info("Starting Delta Handler")
4242
log_data = dict()
4343
firehose_log = dict()
@@ -145,6 +145,7 @@ def handler(event, context):
145145
return {"statusCode": 500, "body": "Records not processed successfully"}
146146

147147
except Exception as e:
148+
148149
operation_outcome["statusCode"] = "500"
149150
operation_outcome["statusDesc"] = "Exception"
150151
if intrusion_check:

delta_backend/src/log_firehose.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ def send_log(self, log_message):
2222
log_to_splunk = log_message
2323
logger.info(f"Log sent to Firehose for save: {log_to_splunk}")
2424
encoded_log_data = json.dumps(log_to_splunk).encode("utf-8")
25+
2526
try:
2627
response = self.firehose_client.put_record(
2728
DeliveryStreamName=self.delivery_stream_name,

delta_backend/tests/test_convert_to_flat_json.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1116,4 +1116,4 @@ def _run_test_practitioner_surname(self, expected_forename):
11161116
self.assertEqual(flat_json[0]["PERFORMING_PROFESSIONAL_SURNAME"], expected_forename)
11171117

11181118
if __name__ == "__main__":
1119-
unittest.main()
1119+
unittest.main()

delta_backend/tests/test_delta.py

Lines changed: 35 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,47 @@
11
import unittest
2-
import os
32
from unittest.mock import patch, MagicMock
43
from botocore.exceptions import ClientError
5-
from sample_data.test_resource_data import get_test_data_resource
4+
import os
5+
from tests.sample_data.test_resource_data import get_test_data_resource
66

77
# Set environment variables before importing the module
88
os.environ["AWS_SQS_QUEUE_URL"] = "https://sqs.us-east-1.amazonaws.com/123456789012/MyQueue"
99
os.environ["DELTA_TABLE_NAME"] = "my_delta_table"
1010
os.environ["SOURCE"] = "my_source"
11-
os.environ["SPLUNK_FIREHOSE_NAME"] = "my_firehose"
1211

1312
from src.delta import send_message, handler # Import after setting environment variables
1413
import json
1514

1615

16+
1717
class DeltaTestCase(unittest.TestCase):
1818

1919
def setUp(self):
2020
# Common setup if needed
2121
self.context = {}
22+
self.logger_exception_patcher = patch("logging.Logger.exception")
23+
self.mock_logger_exception = self.logger_exception_patcher.start()
24+
25+
self.firehose_logger_patcher = patch("src.delta.firehose_logger")
26+
self.mock_firehose_logger = self.firehose_logger_patcher.start()
27+
self.mock_firehose_logger.send_log = MagicMock()
28+
29+
30+
def tearDown(self):
31+
self.logger_exception_patcher.stop()
32+
self.mock_firehose_logger.stop()
2233

2334
@staticmethod
2435
def setup_mock_sqs(mock_boto_client, return_value={"ResponseMetadata": {"HTTPStatusCode": 200}}):
2536
mock_sqs = mock_boto_client.return_value
2637
mock_sqs.send_message.return_value = return_value
2738
return mock_sqs
2839

29-
@staticmethod
30-
def setup_mock_firehose(mock_boto_client, return_value={"ResponseMetadata": {"HTTPStatusCode": 200}}):
31-
mock_firehose = mock_boto_client.return_value
32-
mock_firehose.put_record.return_value = return_value
33-
return mock_firehose
34-
35-
@staticmethod
36-
def setup_mock_firehose(mock_boto_client, return_value={"ResponseMetadata": {"HTTPStatusCode": 200}}):
37-
mock_firehose = mock_boto_client.return_value
38-
mock_firehose.put_record.return_value = return_value
39-
return mock_firehose
40-
41-
4240
@staticmethod
4341
def setup_mock_dynamodb(mock_boto_resource, status_code=200):
44-
"""
45-
Sets up a mock for boto3.resource("dynamodb") and its Table method.
46-
"""
47-
# Mock the DynamoDB resource
4842
mock_dynamodb = mock_boto_resource.return_value
49-
50-
# Mock the Table method
51-
mock_table = MagicMock()
52-
mock_dynamodb.Table.return_value = mock_table
53-
54-
# Mock the put_item method of the table
43+
mock_table = mock_dynamodb.Table.return_value
5544
mock_table.put_item.return_value = {"ResponseMetadata": {"HTTPStatusCode": status_code}}
56-
5745
return mock_table
5846

5947
def setUp_mock_resources(self, mock_boto_resource, mock_boto_client):
@@ -123,8 +111,8 @@ def test_send_message_success(self, mock_boto_client):
123111
)
124112

125113
@patch("boto3.client")
126-
@patch("logging.Logger.info")
127-
def test_send_message_client_error(self, mock_logger_info, mock_boto_client):
114+
@patch("logging.Logger.error")
115+
def test_send_message_client_error(self, mock_logger_error, mock_boto_client):
128116
# Arrange
129117
mock_sqs = MagicMock()
130118
mock_boto_client.return_value = mock_sqs
@@ -138,33 +126,27 @@ def test_send_message_client_error(self, mock_logger_info, mock_boto_client):
138126
send_message(record)
139127

140128
# Assert
141-
mock_logger_info.assert_called_once_with(
129+
mock_logger_error.assert_called_once_with(
142130
f"Error sending record to DLQ: An error occurred (500) when calling the SendMessage operation: Internal Server Error"
143131
)
144132

145-
@patch("delta.FirehoseLogger.send_log")
146133
@patch("boto3.resource")
147-
def test_handler_success_insert(self, mock_boto_resource, mock_send_log):
134+
def test_handler_success_insert(self, mock_boto_resource):
148135
# Arrange
149-
mock_send_log.return_value = None
150136
self.setup_mock_dynamodb(mock_boto_resource)
151137
suppilers = ["DPS", "EMIS"]
152138
for supplier in suppilers:
153139
event = self.get_event(supplier=supplier)
154-
for record in event["Records"]:
155-
record["dynamodb"]["NewImage"]["Resource"]["S"] = json.dumps(get_test_data_resource())
156140

157141
# Act
158142
result = handler(event, self.context)
159143

160144
# Assert
161145
self.assertEqual(result["statusCode"], 200)
162146

163-
@patch("delta.FirehoseLogger.send_log")
164147
@patch("boto3.resource")
165-
def test_handler_failure(self, mock_boto_resource, mock_send_log):
148+
def test_handler_failure(self, mock_boto_resource):
166149
# Arrange
167-
mock_send_log.return_value = None
168150
self.setup_mock_dynamodb(mock_boto_resource, status_code=500)
169151
event = self.get_event()
170152

@@ -174,11 +156,9 @@ def test_handler_failure(self, mock_boto_resource, mock_send_log):
174156
# Assert
175157
self.assertEqual(result["statusCode"], 500)
176158

177-
@patch("delta.FirehoseLogger.send_log")
178159
@patch("boto3.resource")
179-
def test_handler_success_update(self, mock_boto_resource, mock_send_log):
160+
def test_handler_success_update(self, mock_boto_resource):
180161
# Arrange
181-
mock_send_log.return_value = None
182162
self.setup_mock_dynamodb(mock_boto_resource)
183163
event = self.get_event(event_name="UPDATE", operation="UPDATE")
184164

@@ -188,11 +168,9 @@ def test_handler_success_update(self, mock_boto_resource, mock_send_log):
188168
# Assert
189169
self.assertEqual(result["statusCode"], 200)
190170

191-
@patch("delta.FirehoseLogger.send_log")
192171
@patch("boto3.resource")
193-
def test_handler_success_remove(self, mock_boto_resource, mock_send_log):
172+
def test_handler_success_remove(self, mock_boto_resource):
194173
# Arrange
195-
mock_send_log.return_value = None
196174
self.setup_mock_dynamodb(mock_boto_resource)
197175
event = self.get_event(event_name="REMOVE", operation="DELETE")
198176

@@ -202,12 +180,10 @@ def test_handler_success_remove(self, mock_boto_resource, mock_send_log):
202180
# Assert
203181
self.assertEqual(result["statusCode"], 200)
204182

205-
@patch("delta.FirehoseLogger.send_log") # Patch the method directly
206183
@patch("boto3.resource")
207184
@patch("boto3.client")
208-
def test_handler_exception_intrusion_check(self, mock_boto_resource, mock_boto_client, mock_send_log):
185+
def test_handler_exception_intrusion_check(self, mock_boto_resource, mock_boto_client):
209186
# Arrange
210-
mock_send_log.return_value = None
211187
self.setup_mock_dynamodb(mock_boto_resource, status_code=500)
212188
mock_boto_client.return_value = MagicMock()
213189
event = self.get_event()
@@ -217,73 +193,53 @@ def test_handler_exception_intrusion_check(self, mock_boto_resource, mock_boto_c
217193
result = handler(event, self.context)
218194
self.assertEqual(result["statusCode"], 500)
219195

220-
@patch("delta.FirehoseLogger.send_log") # Patch the method directly
221196
@patch("boto3.resource")
222197
@patch("boto3.client")
223-
def test_handler_exception_intrusion(self, mock_boto_resource, mock_boto_client, mock_send_log):
198+
def test_handler_exception_intrusion(self, mock_boto_client, mock_boto_resource):
224199
# Arrange
225200
self.setUp_mock_resources(mock_boto_resource, mock_boto_client)
226-
mock_send_log.return_value = None
201+
227202
event = self.get_event()
228203
context = {}
229204

230205
# Act & Assert
231206
with self.assertRaises(Exception):
232207
handler(event, context)
233208

234-
@patch("delta.FirehoseLogger.send_log")
209+
self.mock_logger_exception.assert_called_once_with("Delta Lambda failure: Test Exception")
210+
235211
@patch("boto3.resource")
236212
@patch("delta.handler")
237-
def test_handler_exception_intrusion_check_false(self, mock_boto_resource, mock_boto_client, mock_send_log):
213+
def test_handler_exception_intrusion_check_false(self, mocked_intrusion, mock_boto_client):
238214
# Arrange
239-
mock_send_log.return_value = None
240-
self.setUp_mock_resources(mock_boto_resource, mock_boto_client)
215+
self.setUp_mock_resources(mocked_intrusion, mock_boto_client)
241216
event = self.get_event()
242217
context = {}
243218

244219
# Act & Assert
245220
with self.assertRaises(Exception):
246221
handler(event, context)
247222

248-
@patch("delta.FirehoseLogger.send_log") # Patch the method directly
249-
@patch("boto3.client")
250-
@patch("delta.logger.info")
251-
def test_dps_record_skipped(self, mock_logger_info, mock_boto_client, mock_send_log):
252-
"""
253-
Test that DPSFULL records are skipped and Firehose put_record is mocked.
254-
"""
255-
# Arrange
256-
mock_firehose_client = self.setup_mock_firehose(mock_boto_client)
257-
258-
mock_send_log.return_value = None
223+
@patch("delta.logger.info") # Mock logging
224+
def test_dps_record_skipped(self, mock_logger_info):
259225

260-
# Create a test event with supplier "DPSFULL"
261226
event = self.get_event(supplier="DPSFULL")
262227
context = {}
263228

264-
# Act
265229
response = handler(event, context)
230+
print(f"final response1: {response}")
266231

267-
# Assert
268-
# check send_log was called
269-
mock_send_log.assert_called_once()
270232
self.assertEqual(response["statusCode"], 200)
271233
self.assertEqual(response["body"], "Record from DPS skipped for 12345")
272234

273-
# Check logging was called
235+
# Check logging and Firehose were called
274236
mock_logger_info.assert_called_with("Record from DPS skipped for 12345")
275237

276-
# Ensure Firehose put_record was not called since DPSFULL records are skipped
277-
mock_firehose_client.put_record.assert_not_called()
278-
279-
# # TODO - amend test once error handling implemented
280-
@patch("delta.FirehoseLogger.send_log") # Patch the method directly
238+
# TODO - amend test once error handling implemented
281239
@patch("delta.logger.info")
282240
@patch("Converter.Converter")
283241
@patch("delta.boto3.resource")
284-
def test_partial_success_with_errors(self, mock_dynamodb, mock_converter, mock_logger_info, mock_send_log):
285-
286-
mock_send_log.return_value = None
242+
def test_partial_success_with_errors(self, mock_dynamodb, mock_converter, mock_logger_info):
287243
mock_converter_instance = MagicMock()
288244
mock_converter_instance.runConversion.return_value = [{}]
289245
mock_converter_instance.getErrorRecords.return_value = [{"error": "Invalid field"}]
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import unittest
2+
from unittest.mock import patch, MagicMock
3+
import json
4+
from src.log_firehose import FirehoseLogger
5+
6+
7+
class TestFirehoseLogger(unittest.TestCase):
8+
9+
@patch("boto3.client")
10+
def test_send_log(self, mock_boto_client):
11+
"""it should send log message to Firehose"""
12+
13+
# Arrange
14+
mock_response = {
15+
"RecordId": "shardId-000000000000000000000001",
16+
"ResponseMetadata": {
17+
"RequestId": "12345abcde67890fghijk",
18+
"HTTPStatusCode": 200,
19+
"RetryAttempts": 0
20+
}
21+
}
22+
mock_firehose_client = MagicMock()
23+
mock_boto_client.return_value = mock_firehose_client
24+
mock_firehose_client.put_record.return_value = mock_response
25+
26+
stream_name = "stream_name"
27+
firehose_logger = FirehoseLogger(boto_client=mock_firehose_client, stream_name=stream_name)
28+
log_message = {"text": "Test log message"}
29+
30+
# Act
31+
firehose_logger.send_log(log_message)
32+
33+
# Assert
34+
mock_firehose_client.put_record.assert_called_once()
35+
self.assertEqual(mock_firehose_client.put_record.return_value, mock_response)
36+
37+
@patch("boto3.client")
38+
def test_send_log_failure(self, mock_boto_client):
39+
"""Test that send_log logs an exception when put_record fails."""
40+
41+
# Arrange
42+
mock_firehose_client = MagicMock()
43+
mock_boto_client.return_value = mock_firehose_client
44+
mock_firehose_client.put_record.side_effect = Exception("Test exception")
45+
46+
stream_name = "test-stream"
47+
firehose_logger = FirehoseLogger(boto_client=mock_firehose_client, stream_name=stream_name)
48+
log_message = {"key": "value"}
49+
50+
with patch("src.log_firehose.logger.exception") as mock_logger_exception:
51+
# Act
52+
firehose_logger.send_log(log_message)
53+
54+
# Assert
55+
mock_firehose_client.put_record.assert_called_once_with(
56+
DeliveryStreamName="test-stream",
57+
Record={"Data": json.dumps(log_message).encode("utf-8")},
58+
)
59+
mock_logger_exception.assert_called_once_with("Error sending log to Firehose: Test exception")
60+
61+
if __name__ == "__main__":
62+
unittest.main()

0 commit comments

Comments
 (0)