@@ -63,7 +63,46 @@ async def test_health_check_api(client):
6363
6464@pytest .mark .asyncio
6565async def test_chat_missing_message (client ):
66- """Test chat endpoint with missing message still returns response (no validation)."""
66+ """Test chat endpoint rejects missing/empty message with 400."""
67+ response = await client .post (
68+ "/api/chat" ,
69+ json = {"conversation_id" : "test-conv" }
70+ )
71+
72+ assert response .status_code == 400
73+ data = await response .get_json ()
74+ assert data ["action_type" ] == "error"
75+ assert "empty" in data ["message" ].lower ()
76+
77+
78+ @pytest .mark .asyncio
79+ async def test_chat_empty_body (client ):
80+ """Test chat endpoint rejects empty request body with 400."""
81+ response = await client .post (
82+ "/api/chat" ,
83+ data = "" ,
84+ headers = {"Content-Type" : "application/json" }
85+ )
86+
87+ assert response .status_code == 400
88+
89+
90+ @pytest .mark .asyncio
91+ async def test_chat_whitespace_message (client ):
92+ """Test chat endpoint rejects whitespace-only message with 400."""
93+ response = await client .post (
94+ "/api/chat" ,
95+ json = {"conversation_id" : "test-conv" , "message" : " " }
96+ )
97+
98+ assert response .status_code == 400
99+ data = await response .get_json ()
100+ assert data ["action_type" ] == "error"
101+
102+
103+ @pytest .mark .asyncio
104+ async def test_chat_empty_message_with_action_allowed (client ):
105+ """Test chat endpoint allows empty message when action is specified."""
67106 with patch ("app.get_routing_service" ) as mock_routing , \
68107 patch ("app.get_cosmos_service" ) as mock_cosmos , \
69108 patch ("app.get_orchestrator" ) as mock_orch :
@@ -88,10 +127,10 @@ async def test_chat_missing_message(client):
88127
89128 response = await client .post (
90129 "/api/chat" ,
91- json = {"conversation_id" : "test-conv" }
130+ json = {"conversation_id" : "test-conv" , "action" : "confirm_brief" , "message" : "" }
92131 )
93132
94- # API doesn't validate missing message - routes to handler with empty message
133+ # Action-based requests bypass message validation
95134 assert response .status_code in [200 , 500 ]
96135
97136
@@ -187,36 +226,15 @@ async def test_chat_cosmos_failure(client):
187226
188227@pytest .mark .asyncio
189228async def test_parse_brief_missing_text (client ):
190- """Test chat endpoint with missing message still processes (no validation)."""
191- with patch ("app.get_routing_service" ) as mock_routing , \
192- patch ("app.get_cosmos_service" ) as mock_cosmos , \
193- patch ("app.get_orchestrator" ) as mock_orch :
194-
195- from services .routing_service import Intent , RoutingResult , ConversationState
196- mock_routing_service = MagicMock ()
197- mock_routing_service .classify_intent = MagicMock (return_value = RoutingResult (
198- intent = Intent .PARSE_BRIEF ,
199- confidence = 0.5
200- ))
201- mock_routing_service .derive_state_from_conversation = MagicMock (return_value = ConversationState ())
202- mock_routing .return_value = mock_routing_service
203-
204- mock_cosmos_service = AsyncMock ()
205- mock_cosmos_service .get_conversation = AsyncMock (return_value = None )
206- mock_cosmos_service .add_message_to_conversation = AsyncMock ()
207- mock_cosmos .return_value = mock_cosmos_service
208-
209- mock_orchestrator = AsyncMock ()
210- mock_orchestrator .parse_brief = AsyncMock (return_value = (MagicMock (model_dump = lambda : {}), None , False ))
211- mock_orch .return_value = mock_orchestrator
212-
213- response = await client .post (
214- "/api/chat" ,
215- json = {"conversation_id" : "test-conv" }
216- )
229+ """Test chat endpoint rejects missing message with 400."""
230+ response = await client .post (
231+ "/api/chat" ,
232+ json = {"conversation_id" : "test-conv" }
233+ )
217234
218- # API doesn't validate missing message - routes to handler with empty message
219- assert response .status_code in [200 , 500 ]
235+ assert response .status_code == 400
236+ data = await response .get_json ()
237+ assert data ["action_type" ] == "error"
220238
221239
222240@pytest .mark .asyncio
@@ -864,39 +882,17 @@ async def test_regenerate_content_success(client, sample_creative_brief_dict):
864882
865883@pytest .mark .asyncio
866884async def test_regenerate_content_missing_modification_request (client , sample_creative_brief_dict ):
867- """Test regeneration without message still routes (no validation)."""
868- with patch ("app.get_routing_service" ) as mock_routing , \
869- patch ("app.get_cosmos_service" ) as mock_cosmos , \
870- patch ("app.get_orchestrator" ) as mock_orch :
871-
872- from services .routing_service import Intent , RoutingResult , ConversationState
873- mock_routing_service = MagicMock ()
874- mock_routing_service .classify_intent = MagicMock (return_value = RoutingResult (
875- intent = Intent .PARSE_BRIEF ,
876- confidence = 0.5
877- ))
878- mock_routing_service .derive_state_from_conversation = MagicMock (return_value = ConversationState ())
879- mock_routing .return_value = mock_routing_service
880-
881- mock_cosmos_service = AsyncMock ()
882- mock_cosmos_service .get_conversation = AsyncMock (return_value = None )
883- mock_cosmos_service .add_message_to_conversation = AsyncMock ()
884- mock_cosmos .return_value = mock_cosmos_service
885-
886- mock_orchestrator = AsyncMock ()
887- mock_orchestrator .parse_brief = AsyncMock (return_value = (MagicMock (model_dump = lambda : {}), None , False ))
888- mock_orch .return_value = mock_orchestrator
889-
890- response = await client .post (
891- "/api/chat" ,
892- json = {
893- "conversation_id" : "test-conv"
894- # Missing message - no validation in backend
895- }
896- )
885+ """Test regeneration rejects missing message with 400."""
886+ response = await client .post (
887+ "/api/chat" ,
888+ json = {
889+ "conversation_id" : "test-conv"
890+ }
891+ )
897892
898- # Backend doesn't validate missing message
899- assert response .status_code in [200 , 500 ]
893+ assert response .status_code == 400
894+ data = await response .get_json ()
895+ assert data ["action_type" ] == "error"
900896
901897
902898@pytest .mark .asyncio
0 commit comments