Skip to content

Commit 5c4b1f0

Browse files
committed
additional test cases
1 parent 4daaa28 commit 5c4b1f0

File tree

1 file changed

+179
-0
lines changed

1 file changed

+179
-0
lines changed

tests/functional/event_handler/_pydantic/test_openapi_params.py

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -913,3 +913,182 @@ def upload_with_public_types(
913913

914914
assert "name" in properties
915915
assert properties["name"].type == "string"
916+
917+
918+
def test_openapi_file_parameter_with_custom_schema_extra():
919+
"""Test File parameter with custom json_schema_extra that gets merged with format: binary."""
920+
from aws_lambda_powertools.event_handler.openapi.params import _File
921+
922+
app = APIGatewayRestResolver(enable_validation=True)
923+
924+
@app.post("/upload-custom")
925+
def upload_with_custom_schema(
926+
file: Annotated[
927+
bytes,
928+
_File(
929+
description="Custom file upload", json_schema_extra={"example": "file_content", "title": "Custom File"}
930+
),
931+
],
932+
):
933+
return {"status": "uploaded"}
934+
935+
schema = app.get_openapi_schema()
936+
937+
# Check that the endpoint is present
938+
assert "/upload-custom" in schema.paths
939+
940+
post_op = schema.paths["/upload-custom"].post
941+
request_body = post_op.requestBody
942+
943+
# Should use multipart/form-data for file uploads
944+
assert "multipart/form-data" in request_body.content
945+
946+
# Get the component schema
947+
multipart_content = request_body.content["multipart/form-data"]
948+
schema_ref = multipart_content.schema_.ref
949+
component_name = schema_ref.split("/")[-1]
950+
component_schema = schema.components.schemas[component_name]
951+
952+
properties = component_schema.properties
953+
954+
# Check file parameter has both binary format and custom schema extras
955+
assert "file" in properties
956+
file_prop = properties["file"]
957+
assert file_prop.format == "binary" # This should be preserved
958+
assert file_prop.description == "Custom file upload"
959+
960+
961+
def test_openapi_body_param_with_conflicting_field_info():
962+
"""Test error condition when both FieldInfo annotation and value are provided."""
963+
from aws_lambda_powertools.event_handler.openapi.params import _File
964+
import pytest
965+
966+
app = APIGatewayRestResolver(enable_validation=True)
967+
968+
# This should work fine - using FieldInfo as annotation
969+
@app.post("/upload-normal")
970+
def upload_normal(file: Annotated[bytes, _File(description="File to upload")]):
971+
return {"status": "uploaded"}
972+
973+
# Test that the normal case works
974+
schema = app.get_openapi_schema()
975+
assert "/upload-normal" in schema.paths
976+
977+
978+
def test_openapi_mixed_body_media_types():
979+
"""Test mixed Body parameters with different media types."""
980+
from aws_lambda_powertools.event_handler.openapi.params import Body
981+
from pydantic import BaseModel
982+
983+
class UserData(BaseModel):
984+
name: str
985+
email: str
986+
987+
app = APIGatewayRestResolver(enable_validation=True)
988+
989+
@app.post("/mixed-body")
990+
def mixed_body_endpoint(user_data: Annotated[UserData, Body(media_type="application/json")]):
991+
return {"status": "created"}
992+
993+
schema = app.get_openapi_schema()
994+
995+
# Check that the endpoint uses the specified media type
996+
assert "/mixed-body" in schema.paths
997+
998+
post_op = schema.paths["/mixed-body"].post
999+
request_body = post_op.requestBody
1000+
1001+
# Should use the specified media type
1002+
assert "application/json" in request_body.content
1003+
1004+
1005+
def test_openapi_form_parameter_edge_cases():
1006+
"""Test Form parameters with various edge cases."""
1007+
from aws_lambda_powertools.event_handler.openapi.params import _Form
1008+
from typing import Optional
1009+
1010+
app = APIGatewayRestResolver(enable_validation=True)
1011+
1012+
@app.post("/form-edge-cases")
1013+
def form_edge_cases(
1014+
required_field: Annotated[str, _Form(description="Required field")],
1015+
optional_field: Annotated[Optional[str], _Form(description="Optional field")] = None,
1016+
field_with_default: Annotated[str, _Form(description="Field with default")] = "default_value",
1017+
):
1018+
return {"required": required_field, "optional": optional_field, "default": field_with_default}
1019+
1020+
schema = app.get_openapi_schema()
1021+
1022+
# Check that the endpoint is present
1023+
assert "/form-edge-cases" in schema.paths
1024+
1025+
post_op = schema.paths["/form-edge-cases"].post
1026+
request_body = post_op.requestBody
1027+
1028+
# Should use application/x-www-form-urlencoded for form-only parameters
1029+
assert "application/x-www-form-urlencoded" in request_body.content
1030+
1031+
# Get the component schema
1032+
form_content = request_body.content["application/x-www-form-urlencoded"]
1033+
schema_ref = form_content.schema_.ref
1034+
component_name = schema_ref.split("/")[-1]
1035+
component_schema = schema.components.schemas[component_name]
1036+
1037+
properties = component_schema.properties
1038+
1039+
# Check all fields are present
1040+
assert "required_field" in properties
1041+
assert "optional_field" in properties
1042+
assert "field_with_default" in properties
1043+
1044+
# Check required vs optional handling
1045+
assert "required_field" in component_schema.required
1046+
assert "optional_field" not in component_schema.required # Optional
1047+
assert "field_with_default" not in component_schema.required # Has default
1048+
1049+
1050+
def test_openapi_file_with_list_type_edge_case():
1051+
"""Test File parameter with nested List types for edge case coverage."""
1052+
from aws_lambda_powertools.event_handler.openapi.params import _File, _Form
1053+
from typing import List, Optional
1054+
1055+
app = APIGatewayRestResolver(enable_validation=True)
1056+
1057+
@app.post("/upload-complex")
1058+
def upload_complex_types(
1059+
files: Annotated[List[bytes], _File(description="Multiple files")],
1060+
metadata: Annotated[Optional[str], _Form(description="Optional metadata")] = None,
1061+
):
1062+
total_size = sum(len(file) for file in files) if files else 0
1063+
return {"file_count": len(files) if files else 0, "total_size": total_size, "metadata": metadata}
1064+
1065+
schema = app.get_openapi_schema()
1066+
1067+
# Check that the endpoint is present
1068+
assert "/upload-complex" in schema.paths
1069+
1070+
post_op = schema.paths["/upload-complex"].post
1071+
request_body = post_op.requestBody
1072+
1073+
# Should use multipart/form-data when files are present
1074+
assert "multipart/form-data" in request_body.content
1075+
1076+
# Get the component schema
1077+
multipart_content = request_body.content["multipart/form-data"]
1078+
schema_ref = multipart_content.schema_.ref
1079+
component_name = schema_ref.split("/")[-1]
1080+
component_schema = schema.components.schemas[component_name]
1081+
1082+
properties = component_schema.properties
1083+
1084+
# Check files parameter is array with binary format items
1085+
assert "files" in properties
1086+
files_prop = properties["files"]
1087+
assert files_prop.type == "array"
1088+
assert files_prop.items.type == "string"
1089+
assert files_prop.items.format == "binary"
1090+
1091+
# Check metadata is optional
1092+
assert "metadata" in properties
1093+
assert "files" in component_schema.required
1094+
assert "metadata" not in component_schema.required

0 commit comments

Comments
 (0)