@@ -268,7 +268,7 @@ def test_lambda_handler_extended_attributes_success(self):
268268
269269 # TODO: rewrite the bucket patches to use moto
270270
271- # Patch uuid4 (message id), the identifier extraction, and prevent external copy issues by simulating move
271+ # Patch uuid4 (message id), and prevent external copy issues by simulating move
272272 with (
273273 patch ("file_name_processor.uuid4" , return_value = test_cases [0 ].message_id ),
274274 patch (
@@ -339,7 +339,7 @@ def test_lambda_handler_extended_attributes_failure(self):
339339
340340 # TODO: rewrite the bucket patches to use moto
341341
342- # Patch uuid4 (message id), the identifier extraction, and don't move the file
342+ # Patch uuid4 (message id), and don't move the file
343343 with (
344344 patch ("file_name_processor.uuid4" , return_value = test_cases [0 ].message_id ),
345345 patch (
@@ -379,6 +379,68 @@ def test_lambda_handler_extended_attributes_failure(self):
379379 self .assert_no_sqs_message ()
380380 self .assert_no_ack_file (test_cases [0 ])
381381
382+ def test_lambda_handler_extended_attributes_invalid_key (self ):
383+ """
384+ Tests that for an extended attributes file (prefix starts with 'Vaccination_Extended_Attributes'):
385+ Where the filename is otherwise invalid:
386+ * The file is added to the audit table with a status of 'Failed'
387+ * The queue_name stored is 'unknown'
388+ * The file is moved to the archive/ folder in the source bucket
389+ * No SQS message is sent
390+ * No ack file is created
391+ """
392+
393+ # Build an extended attributes file.
394+ # FileDetails supports this when vaccine_type starts with 'Vaccination_Extended_Attributes'.
395+ test_cases = [MockFileDetails .extended_attributes_file ]
396+ invalid_file_key = "Vaccination_Extended_Attributes_invalid_20000101T00000001.csv"
397+ # Put file in source bucket
398+ s3_client .put_object (
399+ Bucket = BucketNames .SOURCE ,
400+ Key = invalid_file_key ,
401+ Body = MOCK_EXTENDED_ATTRIBUTES_FILE_CONTENT ,
402+ )
403+
404+ # TODO: rewrite the bucket patches to use moto
405+
406+ # Patch uuid4 (message id), and don't move the file
407+ with (
408+ patch ("file_name_processor.uuid4" , return_value = test_cases [0 ].message_id ),
409+ patch (
410+ "file_name_processor.copy_file_to_external_bucket" ,
411+ side_effect = lambda src_bucket , key , dst_bucket , dst_key , exp_owner , exp_src_owner : (
412+ # effectively do nothing
413+ None ,
414+ ),
415+ ),
416+ ):
417+ lambda_handler (self .make_event ([self .make_record (invalid_file_key )]), None )
418+
419+ # Assert audit table entry captured with Failed and queue_name set to the identifier.
420+ # Assert that the ClientError message is an InvalidFileKeyError.
421+ table_items = self .get_audit_table_items ()
422+ self .assertEqual (len (table_items ), 1 )
423+ item = table_items [0 ]
424+ self .assertEqual (item [AuditTableKeys .MESSAGE_ID ]["S" ], test_cases [0 ].message_id )
425+ self .assertEqual (item [AuditTableKeys .FILENAME ]["S" ], invalid_file_key )
426+ self .assertEqual (item [AuditTableKeys .QUEUE_NAME ]["S" ], "unknown" )
427+ self .assertEqual (item [AuditTableKeys .TIMESTAMP ]["S" ], test_cases [0 ].created_at_formatted_string )
428+ self .assertEqual (item [AuditTableKeys .STATUS ]["S" ], "Failed" )
429+ self .assertEqual (
430+ item [AuditTableKeys .ERROR_DETAILS ]["S" ],
431+ "Initial file validation failed: invalid extended attributes file key format" ,
432+ )
433+ self .assertEqual (item [AuditTableKeys .EXPIRES_AT ]["N" ], str (test_cases [0 ].expires_at ))
434+ # File should be moved to source under archive/
435+ dest_key = f"archive/{ invalid_file_key } "
436+ print (f" destination file is at { s3_client .list_objects (Bucket = BucketNames .SOURCE )} " )
437+ retrieved = s3_client .get_object (Bucket = BucketNames .SOURCE , Key = dest_key )
438+ self .assertIsNotNone (retrieved )
439+
440+ # No SQS and no ack file
441+ self .assert_no_sqs_message ()
442+ self .assert_no_ack_file (test_cases [0 ])
443+
382444 @patch ("elasticache.get_redis_client" )
383445 def test_lambda_invalid_file_key_no_other_files_in_queue (self , mock_get_redis_client ):
384446 """
0 commit comments