@@ -129,10 +129,10 @@ def _assert_expected_crt_http_request(
129129 )
130130 if expected_missing_headers is not None :
131131 header_names = [
132- header [0 ] for header in crt_http_request .headers
132+ header [0 ]. lower () for header in crt_http_request .headers
133133 ]
134134 for expected_missing_header in expected_missing_headers :
135- self .assertNotIn (expected_missing_header , header_names )
135+ self .assertNotIn (expected_missing_header . lower () , header_names )
136136
137137 def _assert_subscribers_called (self , expected_future = None ):
138138 self .assertTrue (self .record_subscriber .on_queued_called )
@@ -145,6 +145,21 @@ def _assert_subscribers_called(self, expected_future=None):
145145 self .record_subscriber .on_done_future , expected_future
146146 )
147147
148+ def _get_expected_upload_checksum_config (self , ** overrides ):
149+ checksum_config_kwargs = {
150+ 'algorithm' : awscrt .s3 .S3ChecksumAlgorithm .CRC32 ,
151+ 'location' : awscrt .s3 .S3ChecksumLocation .TRAILER ,
152+ }
153+ checksum_config_kwargs .update (overrides )
154+ return awscrt .s3 .S3ChecksumConfig (** checksum_config_kwargs )
155+
156+ def _get_expected_download_checksum_config (self , ** overrides ):
157+ checksum_config_kwargs = {
158+ 'validate_response' : True ,
159+ }
160+ checksum_config_kwargs .update (overrides )
161+ return awscrt .s3 .S3ChecksumConfig (** checksum_config_kwargs )
162+
148163 def _invoke_done_callbacks (self , ** kwargs ):
149164 callargs = self .s3_crt_client .make_request .call_args
150165 callargs_kwargs = callargs [1 ]
@@ -182,6 +197,7 @@ def test_upload(self):
182197 'send_filepath' : self .filename ,
183198 'on_progress' : mock .ANY ,
184199 'on_done' : mock .ANY ,
200+ 'checksum_config' : self ._get_expected_upload_checksum_config (),
185201 },
186202 )
187203 self ._assert_expected_crt_http_request (
@@ -208,6 +224,7 @@ def test_upload_from_seekable_stream(self):
208224 'send_filepath' : None ,
209225 'on_progress' : mock .ANY ,
210226 'on_done' : mock .ANY ,
227+ 'checksum_config' : self ._get_expected_upload_checksum_config (),
211228 },
212229 )
213230 self ._assert_expected_crt_http_request (
@@ -239,6 +256,7 @@ def test_upload_from_nonseekable_stream(self):
239256 'send_filepath' : None ,
240257 'on_progress' : mock .ANY ,
241258 'on_done' : mock .ANY ,
259+ 'checksum_config' : self ._get_expected_upload_checksum_config (),
242260 },
243261 )
244262 self ._assert_expected_crt_http_request (
@@ -253,6 +271,54 @@ def test_upload_from_nonseekable_stream(self):
253271 )
254272 self ._assert_subscribers_called (future )
255273
274+ def test_upload_override_checksum_algorithm (self ):
275+ future = self .transfer_manager .upload (
276+ self .filename ,
277+ self .bucket ,
278+ self .key ,
279+ {'ChecksumAlgorithm' : 'CRC32C' },
280+ [self .record_subscriber ],
281+ )
282+ future .result ()
283+
284+ callargs_kwargs = self .s3_crt_client .make_request .call_args [1 ]
285+ self .assertEqual (
286+ callargs_kwargs ,
287+ {
288+ 'request' : mock .ANY ,
289+ 'type' : awscrt .s3 .S3RequestType .PUT_OBJECT ,
290+ 'send_filepath' : self .filename ,
291+ 'on_progress' : mock .ANY ,
292+ 'on_done' : mock .ANY ,
293+ 'checksum_config' : self ._get_expected_upload_checksum_config (
294+ algorithm = awscrt .s3 .S3ChecksumAlgorithm .CRC32C
295+ ),
296+ },
297+ )
298+ self ._assert_expected_crt_http_request (
299+ callargs_kwargs ["request" ],
300+ expected_http_method = 'PUT' ,
301+ expected_content_length = len (self .expected_content ),
302+ expected_missing_headers = [
303+ 'Content-MD5' ,
304+ 'x-amz-sdk-checksum-algorithm' ,
305+ 'X-Amz-Trailer' ,
306+ ],
307+ )
308+ self ._assert_subscribers_called (future )
309+
310+ def test_upload_throws_error_for_unsupported_checksum (self ):
311+ with self .assertRaisesRegex (
312+ ValueError , 'ChecksumAlgorithm: UNSUPPORTED not supported'
313+ ):
314+ self .transfer_manager .upload (
315+ self .filename ,
316+ self .bucket ,
317+ self .key ,
318+ {'ChecksumAlgorithm' : 'UNSUPPORTED' },
319+ [self .record_subscriber ],
320+ )
321+
256322 def test_download (self ):
257323 future = self .transfer_manager .download (
258324 self .bucket , self .key , self .filename , {}, [self .record_subscriber ]
@@ -269,6 +335,7 @@ def test_download(self):
269335 'on_progress' : mock .ANY ,
270336 'on_done' : mock .ANY ,
271337 'on_body' : None ,
338+ 'checksum_config' : self ._get_expected_download_checksum_config (),
272339 },
273340 )
274341 # the recv_filepath will be set to a temporary file path with some
@@ -306,6 +373,7 @@ def test_download_to_seekable_stream(self):
306373 'on_progress' : mock .ANY ,
307374 'on_done' : mock .ANY ,
308375 'on_body' : mock .ANY ,
376+ 'checksum_config' : self ._get_expected_download_checksum_config (),
309377 },
310378 )
311379 self ._assert_expected_crt_http_request (
@@ -340,6 +408,7 @@ def test_download_to_nonseekable_stream(self):
340408 'on_progress' : mock .ANY ,
341409 'on_done' : mock .ANY ,
342410 'on_body' : mock .ANY ,
411+ 'checksum_config' : self ._get_expected_download_checksum_config (),
343412 },
344413 )
345414 self ._assert_expected_crt_http_request (
0 commit comments