from unittest.mock import patch, MagicMock from src.utils import s3_backoff_utils as s3u def test_upload_file_backoff_calls_bucket_upload(): bucket = MagicMock() with patch.object( s3u, 's3_resource', MagicMock(Bucket=lambda name: bucket) ): s3u.upload_file_backoff('local.txt', 's3/path/local.txt', 'bucket') bucket.upload_file.assert_called_once_with( 'local.txt', 's3/path/local.txt' ) def test_upload_files_constructs_keys_and_calls_upload(tmp_path): bucket = MagicMock() with patch.object( s3u, 's3_resource', MagicMock(Bucket=lambda name: bucket) ): files = ['a.txt', 'b.txt'] local = str(tmp_path) s3u.upload_files(files, local, 'prefix', 'bucket') # Ensure both files attempted assert bucket.upload_file.call_count == 2 # Keys include prefix + finished file name calls = [c.args for c in bucket.upload_file.call_args_list] assert calls[0][1].startswith('prefix') assert calls[1][1].startswith('prefix') def test_delete_all_files_in_folder_uses_filter_and_delete(): class Obj: def __init__(self, key): self.key = key fake = [Obj('dir/file.txt'), Obj('dir/file2.txt')] with patch.object(s3u, 'filter_backoff', return_value=fake): with patch.object(s3u, 'delete_backoff') as del_b: s3u.delete_all_files_in_folder('dir', 'bucket', file_ext='.txt') # delete called for each resolved source key expected = { ('dir/file.txt', 'bucket'), ('dir/file2.txt', 'bucket'), } got = {(c.args[0], c.args[1]) for c in del_b.call_args_list} assert got == expected def test_move_all_files_in_folder_copies_then_deletes(): class Obj: def __init__(self, key): self.key = key fake = [Obj('dir/file.txt'), Obj('dir/file2.txt')] with patch.object(s3u, 'filter_backoff', return_value=fake): with patch.object(s3u, 'copy_from_backoff') as cp_b, \ patch.object(s3u, 'delete_backoff') as del_b: s3u.move_all_files_in_folder( 'dir', 'out', 'bucket', file_ext='.txt' ) # copy called for each assert cp_b.call_count == 2 # delete called for each assert del_b.call_count == 2