@@ -133,3 +133,192 @@ def test_improper_function():
133133
134134 with pytest .raises (EtlApiException ):
135135 TestClient (wrap_in_fastapi (func = test_fn , plugin_id = "mock_plugin" ))
136+
137+
138+ @pytest .mark .parametrize (
139+ "file_data" , mock_file_data , ids = [type (fd ).__name__ for fd in mock_file_data ]
140+ )
141+ def test_exception_with_none_status_code (file_data ):
142+ """Test that exceptions with status_code=None are handled correctly."""
143+ from test .assets .exception_status_code import (
144+ function_raises_exception_with_none_status_code as test_fn ,
145+ )
146+
147+ client = TestClient (wrap_in_fastapi (func = test_fn , plugin_id = "mock_plugin" ))
148+
149+ post_body = {"file_data" : file_data .model_dump ()}
150+ resp = client .post ("/invoke" , json = post_body )
151+ resp_content = resp .json ()
152+ invoke_response = InvokeResponse .model_validate (resp_content )
153+
154+ # Should default to 500 when status_code is None
155+ assert invoke_response .status_code == 500
156+ assert "ExceptionWithNoneStatusCode" in invoke_response .status_code_text
157+ assert "Test exception with None status_code" in invoke_response .status_code_text
158+
159+
160+ @pytest .mark .parametrize (
161+ "file_data" , mock_file_data , ids = [type (fd ).__name__ for fd in mock_file_data ]
162+ )
163+ def test_exception_with_valid_status_code (file_data ):
164+ """Test that exceptions with valid status_code are handled correctly."""
165+ from test .assets .exception_status_code import (
166+ function_raises_exception_with_valid_status_code as test_fn ,
167+ )
168+
169+ client = TestClient (wrap_in_fastapi (func = test_fn , plugin_id = "mock_plugin" ))
170+
171+ post_body = {"file_data" : file_data .model_dump ()}
172+ resp = client .post ("/invoke" , json = post_body )
173+ resp_content = resp .json ()
174+ invoke_response = InvokeResponse .model_validate (resp_content )
175+
176+ # Should use the exception's status_code
177+ assert invoke_response .status_code == 422
178+ assert "ExceptionWithValidStatusCode" in invoke_response .status_code_text
179+ assert "Test exception with valid status_code" in invoke_response .status_code_text
180+
181+
182+ @pytest .mark .parametrize (
183+ "file_data" , mock_file_data , ids = [type (fd ).__name__ for fd in mock_file_data ]
184+ )
185+ def test_exception_without_status_code (file_data ):
186+ """Test that exceptions without status_code attribute are handled correctly."""
187+ from test .assets .exception_status_code import (
188+ function_raises_exception_without_status_code as test_fn ,
189+ )
190+
191+ client = TestClient (wrap_in_fastapi (func = test_fn , plugin_id = "mock_plugin" ))
192+
193+ post_body = {"file_data" : file_data .model_dump ()}
194+ resp = client .post ("/invoke" , json = post_body )
195+ resp_content = resp .json ()
196+ invoke_response = InvokeResponse .model_validate (resp_content )
197+
198+ # Should default to 500 when no status_code attribute
199+ assert invoke_response .status_code == 500
200+ assert "ExceptionWithoutStatusCode" in invoke_response .status_code_text
201+ assert "Test exception without status_code" in invoke_response .status_code_text
202+
203+
204+ @pytest .mark .parametrize (
205+ "file_data" , mock_file_data , ids = [type (fd ).__name__ for fd in mock_file_data ]
206+ )
207+ def test_http_exception_handling (file_data ):
208+ """Test that HTTPException is handled correctly (should use HTTPException path)."""
209+ from test .assets .exception_status_code import function_raises_http_exception as test_fn
210+
211+ client = TestClient (wrap_in_fastapi (func = test_fn , plugin_id = "mock_plugin" ))
212+
213+ post_body = {"file_data" : file_data .model_dump ()}
214+ resp = client .post ("/invoke" , json = post_body )
215+ resp_content = resp .json ()
216+ invoke_response = InvokeResponse .model_validate (resp_content )
217+
218+ # HTTPException should be handled by the HTTPException handler
219+ assert invoke_response .status_code == 404
220+ assert invoke_response .status_code_text == "Not found"
221+
222+
223+ @pytest .mark .parametrize (
224+ "file_data" , mock_file_data , ids = [type (fd ).__name__ for fd in mock_file_data ]
225+ )
226+ def test_generic_exception_handling (file_data ):
227+ """Test that generic exceptions are handled correctly."""
228+ from test .assets .exception_status_code import function_raises_generic_exception as test_fn
229+
230+ client = TestClient (wrap_in_fastapi (func = test_fn , plugin_id = "mock_plugin" ))
231+
232+ post_body = {"file_data" : file_data .model_dump ()}
233+ resp = client .post ("/invoke" , json = post_body )
234+ resp_content = resp .json ()
235+ invoke_response = InvokeResponse .model_validate (resp_content )
236+
237+ # Should default to 500 for generic exceptions
238+ assert invoke_response .status_code == 500
239+ assert "ValueError" in invoke_response .status_code_text
240+ assert "Generic error" in invoke_response .status_code_text
241+
242+
243+ @pytest .mark .parametrize (
244+ "file_data" , mock_file_data , ids = [type (fd ).__name__ for fd in mock_file_data ]
245+ )
246+ def test_async_exception_with_none_status_code (file_data ):
247+ """Test that async functions with status_code=None exceptions are handled correctly."""
248+ from test .assets .exception_status_code import (
249+ async_function_raises_exception_with_none_status_code as test_fn ,
250+ )
251+
252+ client = TestClient (wrap_in_fastapi (func = test_fn , plugin_id = "mock_plugin" ))
253+
254+ post_body = {"file_data" : file_data .model_dump ()}
255+ resp = client .post ("/invoke" , json = post_body )
256+ resp_content = resp .json ()
257+ invoke_response = InvokeResponse .model_validate (resp_content )
258+
259+ # Should default to 500 when status_code is None
260+ assert invoke_response .status_code == 500
261+ assert "ExceptionWithNoneStatusCode" in invoke_response .status_code_text
262+ assert "Async test exception with None status_code" in invoke_response .status_code_text
263+
264+
265+ def test_streaming_exception_with_none_status_code ():
266+ """Test that async generator functions with
267+ status_code=None exceptions are handled correctly."""
268+ from test .assets .exception_status_code import (
269+ async_gen_function_raises_exception_with_none_status_code as test_fn ,
270+ )
271+
272+ client = TestClient (wrap_in_fastapi (func = test_fn , plugin_id = "mock_plugin" ))
273+
274+ post_body = {"file_data" : mock_file_data [0 ].model_dump ()}
275+ resp = client .post ("/invoke" , json = post_body )
276+
277+ # For streaming responses, we get NDJSON
278+ assert resp .status_code == 200
279+ assert resp .headers ["content-type" ] == "application/x-ndjson"
280+
281+ # Parse the streaming response - should be a single error response
282+ lines = resp .content .decode ().strip ().split ("\n " )
283+ assert len (lines ) == 1 # Only error response since no items were yielded
284+
285+ # Parse the error response
286+ import json
287+
288+ error_response = json .loads (lines [0 ])
289+ invoke_response = InvokeResponse .model_validate (error_response )
290+
291+ # Should default to 500 when status_code is None
292+ assert invoke_response .status_code == 500
293+ assert "ExceptionWithNoneStatusCode" in invoke_response .status_code_text
294+
295+
296+ def test_streaming_exception_with_valid_status_code ():
297+ """Test that async generator functions with
298+ valid status_code exceptions are handled correctly."""
299+ from test .assets .exception_status_code import (
300+ async_gen_function_raises_exception_with_valid_status_code as test_fn ,
301+ )
302+
303+ client = TestClient (wrap_in_fastapi (func = test_fn , plugin_id = "mock_plugin" ))
304+
305+ post_body = {"file_data" : mock_file_data [0 ].model_dump ()}
306+ resp = client .post ("/invoke" , json = post_body )
307+
308+ # For streaming responses, we get NDJSON
309+ assert resp .status_code == 200
310+ assert resp .headers ["content-type" ] == "application/x-ndjson"
311+
312+ # Parse the streaming response - should be a single error response
313+ lines = resp .content .decode ().strip ().split ("\n " )
314+ assert len (lines ) == 1 # Only error response since no items were yielded
315+
316+ # Parse the error response
317+ import json
318+
319+ error_response = json .loads (lines [0 ])
320+ invoke_response = InvokeResponse .model_validate (error_response )
321+
322+ # Should use the exception's status_code
323+ assert invoke_response .status_code == 422
324+ assert "ExceptionWithValidStatusCode" in invoke_response .status_code_text
0 commit comments