@@ -93,6 +93,208 @@ async def test_form_data_parsing():
9393 assert not hasattr (mock_request , "body" ) or not mock_request .body .called
9494
9595
96+ @pytest .mark .asyncio
97+ async def test_form_data_with_json_metadata ():
98+ """
99+ Test that form data with a JSON-encoded metadata field is correctly parsed.
100+
101+ When form data includes a 'metadata' field, it comes as a JSON string that needs
102+ to be parsed into a Python dictionary (lines 42-43 of http_parsing_utils.py).
103+ """
104+ # Create a mock request with form data containing JSON metadata
105+ mock_request = MagicMock ()
106+
107+ # Metadata is sent as a JSON string in form data
108+ metadata_json_string = json .dumps ({
109+ "user_id" : "12345" ,
110+ "request_type" : "audio_transcription" ,
111+ "tags" : ["urgent" , "production" ],
112+ "custom_field" : {"nested" : "value" }
113+ })
114+
115+ test_data = {
116+ "model" : "whisper-1" ,
117+ "file" : "audio.mp3" ,
118+ "metadata" : metadata_json_string # This is a JSON string, not a dict
119+ }
120+
121+ # Mock the form method to return the test data as an awaitable
122+ mock_request .form = AsyncMock (return_value = test_data )
123+ mock_request .headers = {"content-type" : "multipart/form-data" }
124+ mock_request .scope = {}
125+
126+ # Parse the form data
127+ result = await _read_request_body (mock_request )
128+
129+ # Verify the metadata was parsed from JSON string to dict
130+ assert "metadata" in result
131+ assert isinstance (result ["metadata" ], dict )
132+ assert result ["metadata" ]["user_id" ] == "12345"
133+ assert result ["metadata" ]["request_type" ] == "audio_transcription"
134+ assert result ["metadata" ]["tags" ] == ["urgent" , "production" ]
135+ assert result ["metadata" ]["custom_field" ] == {"nested" : "value" }
136+
137+ # Verify other fields remain unchanged
138+ assert result ["model" ] == "whisper-1"
139+ assert result ["file" ] == "audio.mp3"
140+
141+ # Verify form() was called
142+ mock_request .form .assert_called_once ()
143+
144+
145+ @pytest .mark .asyncio
146+ async def test_form_data_with_invalid_json_metadata ():
147+ """
148+ Test that form data with invalid JSON in metadata field raises an exception.
149+
150+ This tests error handling when the metadata field contains malformed JSON.
151+ """
152+ # Create a mock request with form data containing invalid JSON metadata
153+ mock_request = MagicMock ()
154+
155+ test_data = {
156+ "model" : "whisper-1" ,
157+ "file" : "audio.mp3" ,
158+ "metadata" : '{"invalid": json}' # Invalid JSON - unquoted value
159+ }
160+
161+ # Mock the form method to return the test data
162+ mock_request .form = AsyncMock (return_value = test_data )
163+ mock_request .headers = {"content-type" : "multipart/form-data" }
164+ mock_request .scope = {}
165+
166+ # Should raise JSONDecodeError when trying to parse invalid JSON metadata
167+ with pytest .raises (json .JSONDecodeError ):
168+ await _read_request_body (mock_request )
169+
170+
171+ @pytest .mark .asyncio
172+ async def test_form_data_without_metadata ():
173+ """
174+ Test that form data without metadata field works correctly.
175+
176+ Ensures the metadata parsing logic doesn't break when metadata is absent.
177+ """
178+ # Create a mock request with form data without metadata
179+ mock_request = MagicMock ()
180+
181+ test_data = {
182+ "model" : "whisper-1" ,
183+ "file" : "audio.mp3" ,
184+ "language" : "en"
185+ }
186+
187+ # Mock the form method to return the test data
188+ mock_request .form = AsyncMock (return_value = test_data )
189+ mock_request .headers = {"content-type" : "application/x-www-form-urlencoded" }
190+ mock_request .scope = {}
191+
192+ # Parse the form data
193+ result = await _read_request_body (mock_request )
194+
195+ # Verify all fields are preserved as-is
196+ assert result == test_data
197+ assert "metadata" not in result
198+ assert result ["model" ] == "whisper-1"
199+ assert result ["file" ] == "audio.mp3"
200+ assert result ["language" ] == "en"
201+
202+
203+ @pytest .mark .asyncio
204+ async def test_form_data_with_empty_metadata ():
205+ """
206+ Test that form data with empty JSON object in metadata field is parsed correctly.
207+ """
208+ # Create a mock request with form data containing empty metadata
209+ mock_request = MagicMock ()
210+
211+ test_data = {
212+ "model" : "whisper-1" ,
213+ "file" : "audio.mp3" ,
214+ "metadata" : "{}" # Empty JSON object as string
215+ }
216+
217+ # Mock the form method to return the test data
218+ mock_request .form = AsyncMock (return_value = test_data )
219+ mock_request .headers = {"content-type" : "multipart/form-data" }
220+ mock_request .scope = {}
221+
222+ # Parse the form data
223+ result = await _read_request_body (mock_request )
224+
225+ # Verify the metadata was parsed to an empty dict
226+ assert "metadata" in result
227+ assert isinstance (result ["metadata" ], dict )
228+ assert result ["metadata" ] == {}
229+ assert result ["model" ] == "whisper-1"
230+
231+
232+ @pytest .mark .asyncio
233+ async def test_form_data_with_dict_metadata ():
234+ """
235+ Test that form data with metadata already as a dict is not parsed again.
236+
237+ This handles edge cases where metadata might already be a dictionary
238+ (shouldn't happen in normal form data, but defensive coding).
239+ """
240+ # Create a mock request with form data where metadata is already a dict
241+ mock_request = MagicMock ()
242+
243+ metadata_dict = {
244+ "user_id" : "12345" ,
245+ "tags" : ["test" ]
246+ }
247+
248+ test_data = {
249+ "model" : "whisper-1" ,
250+ "file" : "audio.mp3" ,
251+ "metadata" : metadata_dict # Already a dict, not a string
252+ }
253+
254+ # Mock the form method to return the test data
255+ mock_request .form = AsyncMock (return_value = test_data )
256+ mock_request .headers = {"content-type" : "multipart/form-data" }
257+ mock_request .scope = {}
258+
259+ # Parse the form data
260+ result = await _read_request_body (mock_request )
261+
262+ # Verify the metadata remains as a dict and is not parsed
263+ assert "metadata" in result
264+ assert isinstance (result ["metadata" ], dict )
265+ assert result ["metadata" ] == metadata_dict
266+ assert result ["metadata" ]["user_id" ] == "12345"
267+ assert result ["model" ] == "whisper-1"
268+
269+
270+ @pytest .mark .asyncio
271+ async def test_form_data_with_none_metadata ():
272+ """
273+ Test that form data with None metadata value is handled gracefully.
274+ """
275+ # Create a mock request with form data where metadata is None
276+ mock_request = MagicMock ()
277+
278+ test_data = {
279+ "model" : "whisper-1" ,
280+ "file" : "audio.mp3" ,
281+ "metadata" : None # None value
282+ }
283+
284+ # Mock the form method to return the test data
285+ mock_request .form = AsyncMock (return_value = test_data )
286+ mock_request .headers = {"content-type" : "multipart/form-data" }
287+ mock_request .scope = {}
288+
289+ # Parse the form data
290+ result = await _read_request_body (mock_request )
291+
292+ # Verify the metadata remains None (not parsed)
293+ assert "metadata" in result
294+ assert result ["metadata" ] is None
295+ assert result ["model" ] == "whisper-1"
296+
297+
96298@pytest .mark .asyncio
97299async def test_empty_request_body ():
98300 """
0 commit comments