]> git-server-git.apps.pok.os.sepia.ceph.com Git - s3-tests.git/commitdiff
rgw/multipart: test idempotent complete-multipart cksum and etag 739/head
authorMatt Benjamin <mbenjamin@redhat.com>
Tue, 21 Apr 2026 17:29:23 +0000 (13:29 -0400)
committerMatt Benjamin <mbenjamin@redhat.com>
Tue, 21 Apr 2026 17:29:23 +0000 (13:29 -0400)
Verify that correct etag and checksum (if any) are returned from
a complete-multipart operation that is retried.

Signed-off-by: Matt Benjamin <mbenjamin@redhat.com>
s3tests/functional/test_s3.py

index 5fee6a75fbf754040b78691c540c36dfbc70f85a..a1ffe55fb9ff0d706c35af7140f33870b041fc32 100644 (file)
@@ -14676,6 +14676,54 @@ def test_multipart_checksum_sha256():
     response = client.head_object(Bucket=bucket, Key=key, ChecksumMode='ENABLED')
     assert composite_sha256sum == response['ChecksumSHA256']
 
+@pytest.mark.checksum
+@pytest.mark.fails_on_dbstore
+def test_multipart_reupload_checksum_and_etag():
+    bucket = get_new_bucket()
+    client = get_client()
+
+    key = "mymultipart"
+    response = client.create_multipart_upload(Bucket=bucket, Key=key, ChecksumAlgorithm='SHA256')
+    assert 'SHA256' == response['ChecksumAlgorithm']
+    upload_id = response['UploadId']
+
+    size = 5 * 1024 * 1024 # each part but the last must be at least 5M
+
+    # code to compute checksums for these is in unittest_rgw_cksum
+    body1 = FakeWriteFile(size, 'A')
+    body2 = FakeWriteFile(size, 'B')
+    body3 = FakeWriteFile(size, 'C')
+
+    # known MD5/etag and sha256 checksum values
+    part1_sha256sum = '275VF5loJr1YYawit0XSHREhkFXYkkPKGuoK0x9VKxI='
+    part2_sha256sum = 'mrHwOfjTL5Zwfj74F05HOQGLdUb7E5szdCbxgUSq6NM='
+    part3_sha256sum = 'Vw7oB/nKQ5xWb3hNgbyfkvDiivl+U+/Dft48nfJfDow='
+
+    composite_etag = 'b2add96cc9702bbf4efb0ccdfc6b7747-3'
+    composite_sha256sum = 'uWBwpe1dxI4Vw8Gf0X9ynOdw/SS6VBzfWm9giiv1sf4=-3'
+
+    response1 = client.upload_part(UploadId=upload_id, Bucket=bucket, Key=key, PartNumber=1, Body=body1, ChecksumAlgorithm='SHA256', ChecksumSHA256=part1_sha256sum)
+    response2 = client.upload_part(UploadId=upload_id, Bucket=bucket, Key=key, PartNumber=2, Body=body2, ChecksumAlgorithm='SHA256', ChecksumSHA256=part2_sha256sum)
+    response3 = client.upload_part(UploadId=upload_id, Bucket=bucket, Key=key, PartNumber=3, Body=body3, ChecksumAlgorithm='SHA256', ChecksumSHA256=part3_sha256sum)
+
+    res1 = client.complete_multipart_upload(Bucket=bucket, Key=key, UploadId=upload_id, ChecksumSHA256=composite_sha256sum, MultipartUpload={'Parts': [
+        {'ETag': response1['ETag'].strip('"'), 'ChecksumSHA256': response1['ChecksumSHA256'], 'PartNumber': 1},
+        {'ETag': response2['ETag'].strip('"'), 'ChecksumSHA256': response2['ChecksumSHA256'], 'PartNumber': 2},
+        {'ETag': response3['ETag'].strip('"'), 'ChecksumSHA256': response3['ChecksumSHA256'], 'PartNumber': 3}]})
+
+    assert composite_etag == res1['ETag'].strip('"')
+    assert composite_sha256sum == res1['ChecksumSHA256']
+
+    # validate the headers on the (idempotent) attempt to retry completion--they should match for ETag and Checksum (if any)
+    res2 = client.complete_multipart_upload(Bucket=bucket, Key=key, UploadId=upload_id, ChecksumSHA256=composite_sha256sum, MultipartUpload={'Parts': [
+        {'ETag': response1['ETag'].strip('"'), 'ChecksumSHA256': response1['ChecksumSHA256'], 'PartNumber': 1},
+        {'ETag': response2['ETag'].strip('"'), 'ChecksumSHA256': response2['ChecksumSHA256'], 'PartNumber': 2},
+        {'ETag': response3['ETag'].strip('"'), 'ChecksumSHA256': response3['ChecksumSHA256'], 'PartNumber': 3}]})
+
+    # assert just validated final etag and checksum values match
+    assert res1['ETag'] == res2['ETag']
+    assert res1['ChecksumSHA256'] == res2['ChecksumSHA256']
+
 def multipart_checksum_3parts_helper(key=None, checksum_algo=None, checksum_type=None, **kwargs):
 
     bucket = get_new_bucket()