Skip to content

Commit 562012f

Browse files
committed
improve coverage
1 parent 390334f commit 562012f

File tree

3 files changed

+82
-15
lines changed

3 files changed

+82
-15
lines changed

delta_backend/.coverage

0 Bytes
Binary file not shown.

delta_backend/tests/test_convert_to_flat_json.py

Lines changed: 80 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,11 @@
1212
from tests.utils_for_converter_tests import ValuesForTests, ErrorValuesForTests
1313
from botocore.config import Config
1414
from pathlib import Path
15+
from zoneinfo import ZoneInfo
1516
from SchemaParser import SchemaParser
1617
from Converter import Converter
17-
from ConversionChecker import ConversionChecker
18-
18+
from ConversionChecker import ConversionChecker, RecordError
19+
import ExceptionMessages
1920

2021
MOCK_ENV_VARS = {
2122
"AWS_SQS_QUEUE_URL": "https://sqs.eu-west-2.amazonaws.com/123456789012/test-queue",
@@ -27,6 +28,33 @@
2728
from delta import handler, Converter
2829
from Converter import imms
2930

31+
class TestRecordError(unittest.TestCase):
32+
def test_fields_and_str(self):
33+
err = RecordError(
34+
code=5,
35+
message="Test failed",
36+
details="Something went wrong"
37+
)
38+
39+
# The attributes should round‑trip
40+
self.assertEqual(err.code, 5)
41+
self.assertEqual(err.message, "Test failed")
42+
self.assertEqual(err.details, "Something went wrong")
43+
44+
# __repr__ and __str__ both produce the tuple repr
45+
expected = "(5, 'Test failed', 'Something went wrong')"
46+
self.assertEqual(str(err), expected)
47+
self.assertEqual(repr(err), expected)
48+
49+
def test_default_args(self):
50+
# If you omit arguments they default to None
51+
err = RecordError()
52+
self.assertIsNone(err.code)
53+
self.assertIsNone(err.message)
54+
self.assertIsNone(err.details)
55+
56+
# repr shows three Nones
57+
self.assertEqual(str(err), "(None, None, None)")
3058

3159
@patch.dict("os.environ", MOCK_ENV_VARS, clear=True)
3260
@mock_dynamodb
@@ -66,12 +94,12 @@ def setUp(self):
6694
},
6795
],
6896
)
69-
97+
7098
@staticmethod
7199
def get_event(event_name="INSERT", operation="operation", supplier="EMIS"):
72100
"""Returns test event data."""
73101
return ValuesForTests.get_event(event_name, operation, supplier)
74-
102+
75103
def assert_dynamodb_record(self, operation_flag, items, expected_values, expected_imms, response):
76104
"""
77105
Asserts that a record with the expected structure exists in DynamoDB.
@@ -99,7 +127,7 @@ def assert_dynamodb_record(self, operation_flag, items, expected_values, expecte
99127
for key, expected_value in expected_values.items():
100128
self.assertIn(key, filtered_items[0], f"{key} is missing")
101129
self.assertEqual(filtered_items[0][key], expected_value, f"{key} mismatch")
102-
130+
103131
def test_fhir_converter_json_direct_data(self):
104132
"""it should convert fhir json data to flat json"""
105133
imms.clear()
@@ -125,7 +153,7 @@ def test_fhir_converter_json_direct_data(self):
125153

126154
end = time.time()
127155
print(end - start)
128-
156+
129157
def test_fhir_converter_json_error_scenario(self):
130158
"""it should convert fhir json data to flat json - error scenarios"""
131159
error_test_cases = [ErrorValuesForTests.missing_json, ErrorValuesForTests.json_dob_error]
@@ -157,7 +185,7 @@ def test_fhir_converter_json_error_scenario(self):
157185

158186
end = time.time()
159187
print(end - start)
160-
188+
161189
def test_handler_imms_convert_to_flat_json(self):
162190
"""Test that the Imms field contains the correct flat JSON data for CREATE, UPDATE, and DELETE operations."""
163191
expected_action_flags = [
@@ -188,13 +216,13 @@ def test_handler_imms_convert_to_flat_json(self):
188216
result = self.table.scan()
189217
items = result.get("Items", [])
190218
self.clear_table()
191-
219+
192220
def test_conversionCount(self):
193221
parser = SchemaParser()
194222
schema_data = {"conversions": [{"conversion": "type1"}, {"conversion": "type2"}, {"conversion": "type3"}]}
195223
parser.parseSchema(schema_data)
196224
self.assertEqual(parser.conversionCount(), 3)
197-
225+
198226
def test_getConversion(self):
199227
parser = SchemaParser()
200228
schema_data = {"conversions": [{"conversion": "type1"}, {"conversion": "type2"}, {"conversion": "type3"}]}
@@ -297,7 +325,31 @@ def test_conversion_exceptions(self, mock_get_key_value, mock_get_conversions):
297325
error_records[0]["message"],
298326
)
299327
self.assertEqual(error_records[0]["code"], 0)
328+
329+
@patch("ConversionChecker.LookUpData")
330+
def test_log_error(self, MockLookUpData):
331+
# Instantiate ConversionChecker
332+
checker = ConversionChecker(dataParser=None, summarise=False, report_unexpected_exception=True)
333+
334+
# Simulate an exception
335+
exception = ValueError("Invalid value")
336+
337+
# Call the _log_error method twice to also check deduplication
338+
checker._log_error("test_field", "test_value", exception)
339+
checker._log_error("test_field", "test_value", exception)
340+
341+
# Assert that only one error record is added due to deduplication
342+
self.assertEqual(len(checker.errorRecords), 1)
300343

344+
# Assert that one error record is added
345+
self.assertEqual(len(checker.errorRecords), 1)
346+
error = checker.errorRecords[0]
347+
348+
# Assert that the error record contains correct details
349+
self.assertEqual(error["field"], "test_field")
350+
self.assertEqual(error["value"], "test_value")
351+
self.assertIn("Invalid value", error["message"])
352+
self.assertEqual(error["code"], ExceptionMessages.RECORD_CHECK_FAILED)
301353

302354
@patch("ConversionChecker.LookUpData")
303355
def test_convert_to_not_empty(self, MockLookUpData):
@@ -334,7 +386,7 @@ def test_convert_to_nhs_number(self, MockLookUpData):
334386
invalid_nhs_number = "1234567890243"
335387
result = checker._convertToNHSNumber("NHSNUMBER","fieldName", invalid_nhs_number, False, True)
336388
self.assertEqual(result, "", "Invalid NHS number should return empty string")
337-
389+
338390
@patch("ConversionChecker.LookUpData")
339391
def test_convert_to_date(self, MockLookUpData):
340392
dataParser = Mock()
@@ -377,18 +429,33 @@ def test_convert_to_date(self, MockLookUpData):
377429
result = checker._convertToDate("%Y%m%d", "fieldName", "", False, True)
378430
self.assertEqual(result, "")
379431

380-
#9 Validate all error logs of various responses
432+
# 9. Valid recorded date with timezone
433+
valid_recorded = datetime.now(ZoneInfo("UTC")).replace(microsecond=0).isoformat()
434+
result = checker._convertToDate("format:%Y-%m-%d", "recorded", valid_recorded, False, True)
435+
self.assertTrue(result.startswith(datetime.now(ZoneInfo("UTC")).strftime("%Y%m%dT%H")))
436+
437+
# 10. Recorded field: unsupported timezone offset (+02:00)
438+
result = checker._convertToDate("%Y%m%d", "recorded", "2022-01-01T12:00:00+02:00", False, True)
439+
self.assertEqual(result, "")
440+
441+
# 11. Recorded date with invalid format
442+
result = checker._convertToDate("format:%Y-%m-%d", "recorded", "invalid_date", False, True)
443+
self.assertEqual(result, "")
444+
445+
# 12 Validate all error logs of various responses
381446
messages = [err["message"] for err in checker.errorRecords]
382447
print(f"Error Test Case, {messages}")
383448

384449
self.assertIn("Date must be in YYYYMMDD format", messages)
385450
self.assertIn("Value is not a string", messages)
386451
self.assertIn("Partial date not accepted", messages)
387452
self.assertIn("Date cannot be in the future", messages)
453+
self.assertTrue(any(m.startswith("Unsupported offset") for m in messages))
454+
self.assertIn("Invalid date format", messages)
388455

389456
# Confirm Total Errors Per conversion
390-
self.assertEqual(len(checker.errorRecords), 4)
391-
457+
self.assertEqual(len(checker.errorRecords), 6)
458+
392459
@patch("ConversionChecker.LookUpData")
393460
def test_convert_to_date_time(self, MockLookUpData):
394461
dataParser = Mock()

delta_backend/tests/test_delta.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ def test_handler_exception_intrusion_check_false(self, mock_boto_resource, mock_
203203
with self.assertRaises(Exception):
204204
handler(event, context)
205205

206-
@patch("delta.firehose_logger.send_log", return_value=None) # Mock Firehose logger
206+
@patch("delta.firehose_logger.send_log") # Mock Firehose logger
207207
@patch("delta.logger.info") # Mock logging
208208
def test_dps_record_skipped(self, mock_logger_info, mock_firehose_send_log):
209209
event = self.get_event(supplier="DPSFULL")
@@ -219,7 +219,7 @@ def test_dps_record_skipped(self, mock_logger_info, mock_firehose_send_log):
219219
mock_logger_info.assert_called_with("Record from DPS skipped for 12345")
220220

221221
# TODO - amend test once error handling implemented
222-
@patch("delta.firehose_logger.send_log", return_value=None)
222+
@patch("delta.firehose_logger.send_log")
223223
@patch("delta.logger.info")
224224
@patch("Converter.Converter")
225225
@patch("delta.boto3.resource")

0 commit comments

Comments
 (0)