Skip to content

Commit 153f66b

Browse files
committed
Test post object with plain HTTP and large payload
S3Mock must be re-configured to accept large payloads. Python requests lib sends payloads in full even if it does not know how large the payload is going to be. From my POV, this is a bug and other libaries handle this correctly (e.g., Java's HttpClient).
1 parent 3d7978c commit 153f66b

File tree

4 files changed

+86
-2
lines changed

4 files changed

+86
-2
lines changed

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ classifiers = [
2626
# Runtime dependencies (for running tests/examples)
2727
dependencies = [
2828
"boto3>=1.40.35",
29+
"requests>=2.32.3",
2930
]
3031

3132
[dependency-groups]

s3mock_test.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,18 @@
3333
REGION = os.getenv("AWS_REGION", "us-east-1")
3434
ONE_MB = 1024 * 1024
3535
PREFIX = "prefix"
36+
PAYLOAD_MAX_SIZE = "100MB"
3637

3738
container = (
38-
DockerContainer("adobe/s3mock:4.9.0")
39+
DockerContainer("adobe/s3mock:4.11.0")
3940
.with_exposed_ports(9090, 9191)
4041
.with_env("debug", "true")
42+
# Increase various limits to allow large payload testing, see test_presigned_urls.py
43+
.with_env("SERVER_TOMCAT_MAX_PART_COUNT", "-1")
44+
.with_env("SERVER_TOMCAT_MAX_SWALLOW_SIZE", PAYLOAD_MAX_SIZE)
45+
.with_env("SERVER_TOMCAT_MAX_HTTP_FORM_POST_SIZE", PAYLOAD_MAX_SIZE)
46+
.with_env("SPRING_SERVLET_MULTIPART_MAX_FILE_SIZE", PAYLOAD_MAX_SIZE)
47+
.with_env("SPRING_SERVLET_MULTIPART_MAX_REQUEST_SIZE", PAYLOAD_MAX_SIZE)
4148
.with_env("COM_ADOBE_TESTING_S3MOCK_DOMAIN_INITIAL_BUCKETS", "bucket-a, bucket-b")
4249
.with_env("COM_ADOBE_TESTING_S3MOCK_DOMAIN_VALID_KMS_KEYS",
4350
"arn:aws:kms:us-east-1:1234567890:key/valid-test-key-id")

tests/test_presigned_urls.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import os
2+
import tempfile
3+
4+
import requests
5+
6+
from s3mock_test import (
7+
UPLOAD_FILE_NAME,
8+
compute_md5_etag,
9+
given_bucket,
10+
random_name,
11+
)
12+
13+
# Reimplementation of https://github.com/adobe/S3Mock/blob/main/integration-tests/src/test/kotlin/com/adobe/testing/s3mock/its/PresignedUrlIT.kt
14+
15+
16+
def test_presigned_post_object(s3_client, bucket_name: str):
17+
given_bucket(s3_client, bucket_name)
18+
19+
key = f"{random_name()}-{UPLOAD_FILE_NAME}"
20+
payload = os.urandom(20 * 1024 * 1024)
21+
expected_etag = compute_md5_etag(payload)
22+
tagging_xml = (
23+
'<Tagging><TagSet><Tag><Key>Tag Name</Key>'
24+
'<Value>Tag Value</Value></Tag></TagSet></Tagging>'
25+
)
26+
tmp_file = tempfile.NamedTemporaryFile(delete=False)
27+
try:
28+
tmp_file.write(payload)
29+
tmp_file.flush()
30+
tmp_file_path = tmp_file.name
31+
finally:
32+
tmp_file.close()
33+
34+
presigned = s3_client.generate_presigned_post(
35+
Bucket=bucket_name,
36+
Key=key,
37+
Fields={
38+
'Content-Type': 'application/octet-stream',
39+
'x-amz-storage-class': 'INTELLIGENT_TIERING',
40+
'tagging': tagging_xml,
41+
},
42+
Conditions=[
43+
{'Content-Type': 'application/octet-stream'},
44+
{'x-amz-storage-class': 'INTELLIGENT_TIERING'},
45+
{'tagging': tagging_xml},
46+
],
47+
ExpiresIn=60,
48+
)
49+
50+
form_fields = presigned['fields'].copy()
51+
try:
52+
with open(tmp_file_path, 'rb') as upload_fp:
53+
files = {'file': (key, upload_fp, 'application/octet-stream')}
54+
resp = requests.post(
55+
presigned['url'], data=form_fields, files=files, timeout=30, verify=False
56+
)
57+
finally:
58+
os.unlink(tmp_file_path)
59+
60+
assert resp.status_code in (200, 201, 204)
61+
actual_etag = resp.headers.get('ETag')
62+
assert actual_etag == expected_etag
63+
64+
head = s3_client.head_object(Bucket=bucket_name, Key=key)
65+
assert head['ETag'] == expected_etag
66+
assert head.get('StorageClass') == 'INTELLIGENT_TIERING'
67+
68+
tagging = s3_client.get_object_tagging(Bucket=bucket_name, Key=key)
69+
tags = tagging.get('TagSet', [])
70+
assert len(tags) == 1
71+
assert tags[0]['Key'] == 'Tag Name'
72+
assert tags[0]['Value'] == 'Tag Value'

uv.lock

Lines changed: 5 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)