Skip to content

Commit 44994bb

Browse files
authored
VED-1072: Ack file extension fixes (#1231)
* VED-1072 ack file extension fixes * os.path & update_json_ack_file
1 parent 3461824 commit 44994bb

8 files changed

Lines changed: 97 additions & 15 deletions

File tree

lambdas/ack_backend/src/update_ack_file.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,8 @@ def complete_batch_file_process(
142142
start_time = time.time()
143143

144144
# finish CSV file
145-
ack_filename = f"{file_key.replace('.csv', f'_BusAck_{created_at_formatted_string}.csv')}"
145+
file_key_without_ext = os.path.splitext(file_key)[0]
146+
ack_filename = f"{file_key_without_ext}_BusAck_{created_at_formatted_string}.csv"
146147

147148
move_file(ACK_BUCKET_NAME, f"{TEMP_ACK_DIR}/{ack_filename}", f"{COMPLETED_ACK_DIR}/{ack_filename}")
148149
move_file(SOURCE_BUCKET_NAME, f"{BATCH_FILE_PROCESSING_DIR}/{file_key}", f"{BATCH_FILE_ARCHIVE_DIR}/{file_key}")
@@ -164,7 +165,7 @@ def complete_batch_file_process(
164165
)
165166

166167
# finish JSON file
167-
json_ack_filename = f"{file_key.replace('.csv', f'_BusAck_{created_at_formatted_string}.json')}"
168+
json_ack_filename = f"{file_key_without_ext}_BusAck_{created_at_formatted_string}.json"
168169
temp_ack_file_key = f"{TEMP_ACK_DIR}/{json_ack_filename}"
169170
ack_data_dict = obtain_current_json_ack_content(message_id, supplier, file_key, temp_ack_file_key)
170171

@@ -246,7 +247,7 @@ def obtain_current_json_ack_content(message_id: str, supplier: str, file_key: st
246247
logger.info("No existing JSON ack file found in S3 - creating new file")
247248

248249
ingestion_start_time = get_ingestion_start_time_by_message_id(message_id)
249-
raw_ack_filename = file_key.split(".")[0]
250+
raw_ack_filename = os.path.splitext(file_key)[0]
250251

251252
# Generate the initial fields
252253
return _make_ack_data_dict_identifier_information(
@@ -268,7 +269,8 @@ def update_csv_ack_file(
268269
ack_data_rows: list,
269270
) -> None:
270271
"""Updates the ack file with the new data row based on the given arguments"""
271-
ack_filename = f"{file_key.replace('.csv', f'_BusAck_{created_at_formatted_string}.csv')}"
272+
file_key_without_ext = os.path.splitext(file_key)[0]
273+
ack_filename = f"{file_key_without_ext}_BusAck_{created_at_formatted_string}.csv"
272274
temp_ack_file_key = f"{TEMP_ACK_DIR}/{ack_filename}"
273275
accumulated_csv_content = obtain_current_csv_ack_content(temp_ack_file_key)
274276

@@ -291,7 +293,8 @@ def update_json_ack_file(
291293
ack_data_rows: list,
292294
) -> None:
293295
"""Updates the ack file with the new data row based on the given arguments"""
294-
ack_filename = f"{file_key.replace('.csv', f'_BusAck_{created_at_formatted_string}.json')}"
296+
file_key_without_ext = os.path.splitext(file_key)[0]
297+
ack_filename = f"{file_key_without_ext}_BusAck_{created_at_formatted_string}.json"
295298
temp_ack_file_key = f"{TEMP_ACK_DIR}/{ack_filename}"
296299
ack_data_dict = obtain_current_json_ack_content(message_id, supplier, file_key, temp_ack_file_key)
297300

lambdas/ack_backend/tests/test_splunk_logging.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -167,13 +167,12 @@ def test_splunk_logging_successful_rows(self):
167167

168168
def test_splunk_logging_missing_data(self):
169169
"""Tests missing key values in the body of the event"""
170-
171170
with ( # noqa: E999
172171
patch("common.log_decorator.send_log_to_firehose") as mock_send_log_to_firehose, # noqa: E999
173172
patch("common.log_decorator.logger") as mock_logger, # noqa: E999
174173
patch("ack_processor.increment_records_failed_count"), # noqa: E999
175174
): # noqa: E999
176-
with self.assertRaises(AttributeError):
175+
with self.assertRaises(TypeError):
177176
lambda_handler(event={"Records": [{"body": json.dumps([{"": "456", "row_id": "test^1"}])}]}, context={})
178177

179178
expected_first_logger_info_data = {**InvalidValues.logging_with_no_values}
@@ -182,7 +181,7 @@ def test_splunk_logging_missing_data(self):
182181
success=False,
183182
number_of_rows=1,
184183
ingestion_complete=False,
185-
diagnostics="'NoneType' object has no attribute 'replace'",
184+
diagnostics="expected str, bytes or os.PathLike object, not NoneType",
186185
)
187186

188187
first_logger_info_call_args = json.loads(self.extract_all_call_args_for_logger_info(mock_logger)[0])

lambdas/ack_backend/tests/test_update_ack_file.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,63 @@ def test_complete_batch_file_process_json_ack_file(self):
433433
)
434434
self.assertEqual(result, ValidValues.json_ack_complete_content)
435435

436+
def test_complete_batch_file_process_with_dat_extension(self):
437+
"""Test that complete_batch_file_process correctly handles files with .dat extension."""
438+
file_key_with_dat = "flu_Vaccinations_v5_YGA_20210730T12000000.dat"
439+
created_at_formatted_string = "20211120T12000000"
440+
expected_csv_ack_file_key = (
441+
f"forwardedFile/flu_Vaccinations_v5_YGA_20210730T12000000_BusAck_{created_at_formatted_string}.csv"
442+
)
443+
expected_json_ack_file_key = (
444+
f"forwardedFile/flu_Vaccinations_v5_YGA_20210730T12000000_BusAck_{created_at_formatted_string}.json"
445+
)
446+
447+
generate_sample_existing_json_ack_content()
448+
self.s3_client.put_object(
449+
Bucket=BucketNames.SOURCE,
450+
Key=f"processing/{file_key_with_dat}",
451+
Body="dummy content",
452+
)
453+
454+
update_csv_ack_file(
455+
file_key=file_key_with_dat,
456+
created_at_formatted_string=created_at_formatted_string,
457+
ack_data_rows=[ValidValues.ack_data_failure_dict],
458+
)
459+
update_json_ack_file(
460+
message_id=MOCK_MESSAGE_DETAILS.message_id,
461+
supplier=MOCK_MESSAGE_DETAILS.supplier,
462+
file_key=file_key_with_dat,
463+
created_at_formatted_string=created_at_formatted_string,
464+
ack_data_rows=[ValidValues.ack_data_failure_dict],
465+
)
466+
467+
self.mock_get_record_and_failure_count.return_value = 10, 1
468+
469+
complete_batch_file_process(
470+
message_id=MOCK_MESSAGE_DETAILS.message_id,
471+
supplier=MOCK_MESSAGE_DETAILS.supplier,
472+
vaccine_type=MOCK_MESSAGE_DETAILS.vaccine_type,
473+
created_at_formatted_string=created_at_formatted_string,
474+
file_key=file_key_with_dat,
475+
)
476+
477+
# Verify CSV ACK file was created with .csv extension
478+
try:
479+
self.s3_client.head_object(Bucket=BucketNames.DESTINATION, Key=expected_csv_ack_file_key)
480+
csv_ack_exists = True
481+
except Exception:
482+
csv_ack_exists = False
483+
self.assertTrue(csv_ack_exists, f"Expected CSV ACK file at {expected_csv_ack_file_key}")
484+
485+
# Verify JSON ACK file was created with .json extension (not .dat.json)
486+
try:
487+
self.s3_client.head_object(Bucket=BucketNames.DESTINATION, Key=expected_json_ack_file_key)
488+
json_ack_exists = True
489+
except Exception:
490+
json_ack_exists = False
491+
self.assertTrue(json_ack_exists, f"Expected JSON ACK file at {expected_json_ack_file_key}")
492+
436493
def test_update_json_ack_file_with_empty_ack_data_rows(self):
437494
"""Test that update_json_ack_file correctly updates the ack file when given an empty list"""
438495
# Mock existing content in the ack file

lambdas/batch_processor_filter/src/batch_file_repository.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"""Module for the batch file repository"""
22

3+
import os
34
from csv import writer
45
from io import BytesIO, StringIO
56

@@ -48,10 +49,8 @@ def move_source_file_to_archive(self, file_key: str) -> None:
4849
def upload_failure_ack(self, batch_file_created_event: BatchFileCreatedEvent) -> None:
4950
ack_failure_data = self._create_ack_failure_data(batch_file_created_event)
5051

51-
ack_filename = "ack/" + batch_file_created_event["filename"].replace(
52-
".csv",
53-
f"_InfAck_{batch_file_created_event['created_at_formatted_string']}.csv",
54-
)
52+
filename_without_ext = os.path.splitext(batch_file_created_event["filename"])[0]
53+
ack_filename = f"ack/{filename_without_ext}_InfAck_{batch_file_created_event['created_at_formatted_string']}.csv"
5554

5655
# Create CSV file with | delimiter, filetype .csv
5756
csv_buffer = StringIO()

lambdas/filenameprocessor/tests/test_lambda_handler.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""Tests for lambda_handler"""
22

33
import json
4+
import os
45
from contextlib import ExitStack
56
from copy import deepcopy
67
from json import loads as json_loads
@@ -120,7 +121,8 @@ def get_ack_file_key(
120121
created_at_formatted_string: str = MOCK_CREATED_AT_FORMATTED_STRING,
121122
) -> str:
122123
"""Returns the ack file key for the given file key"""
123-
return f"ack/{file_key.replace('.csv', '_InfAck_' + created_at_formatted_string + '.csv')}"
124+
file_key_without_ext = os.path.splitext(file_key)[0]
125+
return f"ack/{file_key_without_ext}_InfAck_{created_at_formatted_string}.csv"
124126

125127
@staticmethod
126128
def generate_expected_failure_inf_ack_content(message_id: str, created_at_formatted_string: str) -> str:

lambdas/filenameprocessor/tests/utils_for_tests/values_for_tests.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"""File of values which can be used for testing"""
22

3+
import os
34
from datetime import datetime
45
from unittest.mock import patch
56

@@ -54,7 +55,8 @@ def __init__(
5455

5556
self.file_key = file_key
5657

57-
self.ack_file_key = f"ack/{self.file_key[:-4]}_InfAck_{self.created_at_formatted_string}.csv"
58+
file_key_without_ext = os.path.splitext(self.file_key)[0]
59+
self.ack_file_key = f"ack/{file_key_without_ext}_InfAck_{self.created_at_formatted_string}.csv"
5860

5961
self.permissions_list = [f"{self.vaccine_type}_FULL"]
6062
self.permissions_config = {self.supplier: self.permissions_list}

lambdas/shared/src/common/ack_file_utils.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"""Create ack file and upload to S3 bucket"""
22

3+
import os
34
from csv import writer
45
from io import BytesIO, StringIO
56

@@ -35,7 +36,8 @@ def make_ack_data(
3536

3637
def upload_ack_file(file_key: str, ack_data: dict, created_at_formatted_string: str) -> None:
3738
"""Formats the ack data into a csv file and uploads it to the ack bucket"""
38-
ack_filename = "ack/" + file_key.replace(".csv", f"_InfAck_{created_at_formatted_string}.csv")
39+
file_key_without_ext = os.path.splitext(file_key)[0]
40+
ack_filename = f"ack/{file_key_without_ext}_InfAck_{created_at_formatted_string}.csv"
3941

4042
# Create CSV file with | delimiter, filetype .csv
4143
csv_buffer = StringIO()

lambdas/shared/tests/test_common/test_ack_file_utils.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,24 @@ def test_upload_ack_file_failure(self):
145145
)
146146
self.assertEqual(list(csv_dict_reader), expected_result)
147147

148+
def test_upload_ack_file_with_dat_extension(self):
149+
"""Test that upload_ack_file generates correct filename when source file has .dat extension"""
150+
151+
# Create a file_key with .dat extension
152+
file_key_with_dat = "flu_Vaccinations_v5_YGA_20210730T12000000.dat"
153+
expected_ack_file_key = "ack/flu_Vaccinations_v5_YGA_20210730T12000000_InfAck_20211120T12000000.csv"
154+
upload_ack_file(
155+
file_key=file_key_with_dat,
156+
ack_data=deepcopy(self.ack_data_validation_passed_and_message_delivered),
157+
created_at_formatted_string=self.created_at_formatted_string,
158+
)
159+
160+
expected_result = [deepcopy(self.ack_data_validation_passed_and_message_delivered)]
161+
# Note that the data downloaded from the CSV will contain the bool as a string
162+
expected_result[0]["MESSAGE_DELIVERY"] = "True"
163+
csv_dict_reader = get_csv_file_dict_reader(self.s3_client, BucketNames.DESTINATION, expected_ack_file_key)
164+
self.assertEqual(list(csv_dict_reader), expected_result)
165+
148166
def test_make_and_upload_ack_file_success(self):
149167
"""Test that make_and_upload_ack_file uploads an ack file containing the correct values"""
150168
make_and_upload_ack_file(

0 commit comments

Comments
 (0)