Formatting
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
"""Edge case tests for FastAPI endpoints."""
|
||||
import pytest
|
||||
import json
|
||||
from unittest.mock import Mock, patch, MagicMock
|
||||
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
|
||||
@@ -10,43 +10,46 @@ class TestChatCompletionsEdgeCases:
|
||||
|
||||
def test_very_long_message(self, memory):
|
||||
"""Should handle very long user message."""
|
||||
from app import app, agent
|
||||
|
||||
from app import agent, app
|
||||
|
||||
# Patch the agent's LLM directly
|
||||
mock_llm = Mock()
|
||||
mock_llm.complete.return_value = {
|
||||
"role": "assistant",
|
||||
"content": "Response"
|
||||
}
|
||||
mock_llm.complete.return_value = {"role": "assistant", "content": "Response"}
|
||||
agent.llm = mock_llm
|
||||
|
||||
|
||||
client = TestClient(app)
|
||||
|
||||
long_message = "x" * 100000
|
||||
response = client.post("/v1/chat/completions", json={
|
||||
"model": "agent-media",
|
||||
"messages": [{"role": "user", "content": long_message}],
|
||||
})
|
||||
response = client.post(
|
||||
"/v1/chat/completions",
|
||||
json={
|
||||
"model": "agent-media",
|
||||
"messages": [{"role": "user", "content": long_message}],
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
def test_unicode_message(self, memory):
|
||||
"""Should handle unicode in message."""
|
||||
from app import app, agent
|
||||
|
||||
from app import agent, app
|
||||
|
||||
mock_llm = Mock()
|
||||
mock_llm.complete.return_value = {
|
||||
"role": "assistant",
|
||||
"content": "日本語の応答"
|
||||
"content": "日本語の応答",
|
||||
}
|
||||
agent.llm = mock_llm
|
||||
|
||||
|
||||
client = TestClient(app)
|
||||
|
||||
response = client.post("/v1/chat/completions", json={
|
||||
"model": "agent-media",
|
||||
"messages": [{"role": "user", "content": "日本語のメッセージ 🎬"}],
|
||||
})
|
||||
response = client.post(
|
||||
"/v1/chat/completions",
|
||||
json={
|
||||
"model": "agent-media",
|
||||
"messages": [{"role": "user", "content": "日本語のメッセージ 🎬"}],
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
content = response.json()["choices"][0]["message"]["content"]
|
||||
@@ -54,22 +57,22 @@ class TestChatCompletionsEdgeCases:
|
||||
|
||||
def test_special_characters_in_message(self, memory):
|
||||
"""Should handle special characters."""
|
||||
from app import app, agent
|
||||
|
||||
from app import agent, app
|
||||
|
||||
mock_llm = Mock()
|
||||
mock_llm.complete.return_value = {
|
||||
"role": "assistant",
|
||||
"content": "Response"
|
||||
}
|
||||
mock_llm.complete.return_value = {"role": "assistant", "content": "Response"}
|
||||
agent.llm = mock_llm
|
||||
|
||||
|
||||
client = TestClient(app)
|
||||
|
||||
special_message = 'Test with "quotes" and \\backslash and \n newline'
|
||||
response = client.post("/v1/chat/completions", json={
|
||||
"model": "agent-media",
|
||||
"messages": [{"role": "user", "content": special_message}],
|
||||
})
|
||||
response = client.post(
|
||||
"/v1/chat/completions",
|
||||
json={
|
||||
"model": "agent-media",
|
||||
"messages": [{"role": "user", "content": special_message}],
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
@@ -81,12 +84,16 @@ class TestChatCompletionsEdgeCases:
|
||||
mock_llm_class.return_value = mock_llm
|
||||
|
||||
from app import app
|
||||
|
||||
client = TestClient(app)
|
||||
|
||||
response = client.post("/v1/chat/completions", json={
|
||||
"model": "agent-media",
|
||||
"messages": [{"role": "user", "content": ""}],
|
||||
})
|
||||
response = client.post(
|
||||
"/v1/chat/completions",
|
||||
json={
|
||||
"model": "agent-media",
|
||||
"messages": [{"role": "user", "content": ""}],
|
||||
},
|
||||
)
|
||||
|
||||
# Empty content should be rejected
|
||||
assert response.status_code == 422
|
||||
@@ -98,12 +105,16 @@ class TestChatCompletionsEdgeCases:
|
||||
mock_llm_class.return_value = mock_llm
|
||||
|
||||
from app import app
|
||||
|
||||
client = TestClient(app)
|
||||
|
||||
response = client.post("/v1/chat/completions", json={
|
||||
"model": "agent-media",
|
||||
"messages": [{"role": "user", "content": None}],
|
||||
})
|
||||
response = client.post(
|
||||
"/v1/chat/completions",
|
||||
json={
|
||||
"model": "agent-media",
|
||||
"messages": [{"role": "user", "content": None}],
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 422
|
||||
|
||||
@@ -114,12 +125,16 @@ class TestChatCompletionsEdgeCases:
|
||||
mock_llm_class.return_value = mock_llm
|
||||
|
||||
from app import app
|
||||
|
||||
client = TestClient(app)
|
||||
|
||||
response = client.post("/v1/chat/completions", json={
|
||||
"model": "agent-media",
|
||||
"messages": [{"role": "user"}], # No content
|
||||
})
|
||||
response = client.post(
|
||||
"/v1/chat/completions",
|
||||
json={
|
||||
"model": "agent-media",
|
||||
"messages": [{"role": "user"}], # No content
|
||||
},
|
||||
)
|
||||
|
||||
# May accept or reject depending on validation
|
||||
assert response.status_code in [200, 400, 422]
|
||||
@@ -131,12 +146,16 @@ class TestChatCompletionsEdgeCases:
|
||||
mock_llm_class.return_value = mock_llm
|
||||
|
||||
from app import app
|
||||
|
||||
client = TestClient(app)
|
||||
|
||||
response = client.post("/v1/chat/completions", json={
|
||||
"model": "agent-media",
|
||||
"messages": [{"content": "Hello"}], # No role
|
||||
})
|
||||
response = client.post(
|
||||
"/v1/chat/completions",
|
||||
json={
|
||||
"model": "agent-media",
|
||||
"messages": [{"content": "Hello"}], # No role
|
||||
},
|
||||
)
|
||||
|
||||
# Should reject or accept depending on validation
|
||||
assert response.status_code in [200, 400, 422]
|
||||
@@ -149,27 +168,28 @@ class TestChatCompletionsEdgeCases:
|
||||
mock_llm_class.return_value = mock_llm
|
||||
|
||||
from app import app
|
||||
|
||||
client = TestClient(app)
|
||||
|
||||
response = client.post("/v1/chat/completions", json={
|
||||
"model": "agent-media",
|
||||
"messages": [{"role": "invalid_role", "content": "Hello"}],
|
||||
})
|
||||
response = client.post(
|
||||
"/v1/chat/completions",
|
||||
json={
|
||||
"model": "agent-media",
|
||||
"messages": [{"role": "invalid_role", "content": "Hello"}],
|
||||
},
|
||||
)
|
||||
|
||||
# Should reject or ignore invalid role
|
||||
assert response.status_code in [200, 400, 422]
|
||||
|
||||
def test_many_messages(self, memory):
|
||||
"""Should handle many messages in conversation."""
|
||||
from app import app, agent
|
||||
|
||||
from app import agent, app
|
||||
|
||||
mock_llm = Mock()
|
||||
mock_llm.complete.return_value = {
|
||||
"role": "assistant",
|
||||
"content": "Response"
|
||||
}
|
||||
mock_llm.complete.return_value = {"role": "assistant", "content": "Response"}
|
||||
agent.llm = mock_llm
|
||||
|
||||
|
||||
client = TestClient(app)
|
||||
|
||||
messages = []
|
||||
@@ -178,10 +198,13 @@ class TestChatCompletionsEdgeCases:
|
||||
messages.append({"role": "assistant", "content": f"Response {i}"})
|
||||
messages.append({"role": "user", "content": "Final message"})
|
||||
|
||||
response = client.post("/v1/chat/completions", json={
|
||||
"model": "agent-media",
|
||||
"messages": messages,
|
||||
})
|
||||
response = client.post(
|
||||
"/v1/chat/completions",
|
||||
json={
|
||||
"model": "agent-media",
|
||||
"messages": messages,
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
@@ -192,15 +215,19 @@ class TestChatCompletionsEdgeCases:
|
||||
mock_llm_class.return_value = mock_llm
|
||||
|
||||
from app import app
|
||||
|
||||
client = TestClient(app)
|
||||
|
||||
response = client.post("/v1/chat/completions", json={
|
||||
"model": "agent-media",
|
||||
"messages": [
|
||||
{"role": "system", "content": "You are helpful"},
|
||||
{"role": "system", "content": "Be concise"},
|
||||
],
|
||||
})
|
||||
response = client.post(
|
||||
"/v1/chat/completions",
|
||||
json={
|
||||
"model": "agent-media",
|
||||
"messages": [
|
||||
{"role": "system", "content": "You are helpful"},
|
||||
{"role": "system", "content": "Be concise"},
|
||||
],
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 422
|
||||
|
||||
@@ -211,14 +238,18 @@ class TestChatCompletionsEdgeCases:
|
||||
mock_llm_class.return_value = mock_llm
|
||||
|
||||
from app import app
|
||||
|
||||
client = TestClient(app)
|
||||
|
||||
response = client.post("/v1/chat/completions", json={
|
||||
"model": "agent-media",
|
||||
"messages": [
|
||||
{"role": "assistant", "content": "Hello"},
|
||||
],
|
||||
})
|
||||
response = client.post(
|
||||
"/v1/chat/completions",
|
||||
json={
|
||||
"model": "agent-media",
|
||||
"messages": [
|
||||
{"role": "assistant", "content": "Hello"},
|
||||
],
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 422
|
||||
|
||||
@@ -229,12 +260,16 @@ class TestChatCompletionsEdgeCases:
|
||||
mock_llm_class.return_value = mock_llm
|
||||
|
||||
from app import app
|
||||
|
||||
client = TestClient(app)
|
||||
|
||||
response = client.post("/v1/chat/completions", json={
|
||||
"model": "agent-media",
|
||||
"messages": "not an array",
|
||||
})
|
||||
response = client.post(
|
||||
"/v1/chat/completions",
|
||||
json={
|
||||
"model": "agent-media",
|
||||
"messages": "not an array",
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 422
|
||||
# Pydantic validation error
|
||||
@@ -246,118 +281,128 @@ class TestChatCompletionsEdgeCases:
|
||||
mock_llm_class.return_value = mock_llm
|
||||
|
||||
from app import app
|
||||
|
||||
client = TestClient(app)
|
||||
|
||||
response = client.post("/v1/chat/completions", json={
|
||||
"model": "agent-media",
|
||||
"messages": ["not an object", 123, None],
|
||||
})
|
||||
response = client.post(
|
||||
"/v1/chat/completions",
|
||||
json={
|
||||
"model": "agent-media",
|
||||
"messages": ["not an object", 123, None],
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 422
|
||||
# Pydantic validation error
|
||||
|
||||
def test_extra_fields_in_request(self, memory):
|
||||
"""Should ignore extra fields in request."""
|
||||
from app import app, agent
|
||||
|
||||
from app import agent, app
|
||||
|
||||
mock_llm = Mock()
|
||||
mock_llm.complete.return_value = {
|
||||
"role": "assistant",
|
||||
"content": "Response"
|
||||
}
|
||||
mock_llm.complete.return_value = {"role": "assistant", "content": "Response"}
|
||||
agent.llm = mock_llm
|
||||
|
||||
|
||||
client = TestClient(app)
|
||||
|
||||
response = client.post("/v1/chat/completions", json={
|
||||
"model": "agent-media",
|
||||
"messages": [{"role": "user", "content": "Hello"}],
|
||||
"extra_field": "should be ignored",
|
||||
"temperature": 0.7,
|
||||
"max_tokens": 100,
|
||||
})
|
||||
response = client.post(
|
||||
"/v1/chat/completions",
|
||||
json={
|
||||
"model": "agent-media",
|
||||
"messages": [{"role": "user", "content": "Hello"}],
|
||||
"extra_field": "should be ignored",
|
||||
"temperature": 0.7,
|
||||
"max_tokens": 100,
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
def test_streaming_with_tool_call(self, memory, real_folder):
|
||||
"""Should handle streaming with tool execution."""
|
||||
from app import app, agent
|
||||
from app import agent, app
|
||||
from infrastructure.persistence import get_memory
|
||||
|
||||
|
||||
mem = get_memory()
|
||||
mem.ltm.set_config("download_folder", str(real_folder["downloads"]))
|
||||
|
||||
|
||||
call_count = [0]
|
||||
|
||||
def mock_complete(messages, tools=None):
|
||||
call_count[0] += 1
|
||||
if call_count[0] == 1:
|
||||
return {
|
||||
"role": "assistant",
|
||||
"content": None,
|
||||
"tool_calls": [{
|
||||
"id": "call_1",
|
||||
"function": {
|
||||
"name": "list_folder",
|
||||
"arguments": '{"folder_type": "download"}'
|
||||
"tool_calls": [
|
||||
{
|
||||
"id": "call_1",
|
||||
"function": {
|
||||
"name": "list_folder",
|
||||
"arguments": '{"folder_type": "download"}',
|
||||
},
|
||||
}
|
||||
}]
|
||||
],
|
||||
}
|
||||
return {
|
||||
"role": "assistant",
|
||||
"content": "Listed the folder."
|
||||
}
|
||||
|
||||
return {"role": "assistant", "content": "Listed the folder."}
|
||||
|
||||
mock_llm = Mock()
|
||||
mock_llm.complete = Mock(side_effect=mock_complete)
|
||||
agent.llm = mock_llm
|
||||
|
||||
|
||||
client = TestClient(app)
|
||||
|
||||
response = client.post("/v1/chat/completions", json={
|
||||
"model": "agent-media",
|
||||
"messages": [{"role": "user", "content": "List downloads"}],
|
||||
"stream": True,
|
||||
})
|
||||
response = client.post(
|
||||
"/v1/chat/completions",
|
||||
json={
|
||||
"model": "agent-media",
|
||||
"messages": [{"role": "user", "content": "List downloads"}],
|
||||
"stream": True,
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
def test_concurrent_requests_simulation(self, memory):
|
||||
"""Should handle rapid sequential requests."""
|
||||
from app import app, agent
|
||||
|
||||
from app import agent, app
|
||||
|
||||
mock_llm = Mock()
|
||||
mock_llm.complete.return_value = {
|
||||
"role": "assistant",
|
||||
"content": "Response"
|
||||
}
|
||||
mock_llm.complete.return_value = {"role": "assistant", "content": "Response"}
|
||||
agent.llm = mock_llm
|
||||
|
||||
|
||||
client = TestClient(app)
|
||||
|
||||
for i in range(10):
|
||||
response = client.post("/v1/chat/completions", json={
|
||||
"model": "agent-media",
|
||||
"messages": [{"role": "user", "content": f"Request {i}"}],
|
||||
})
|
||||
response = client.post(
|
||||
"/v1/chat/completions",
|
||||
json={
|
||||
"model": "agent-media",
|
||||
"messages": [{"role": "user", "content": f"Request {i}"}],
|
||||
},
|
||||
)
|
||||
assert response.status_code == 200
|
||||
|
||||
def test_llm_returns_json_in_response(self, memory):
|
||||
"""Should handle LLM returning JSON in text response."""
|
||||
from app import app, agent
|
||||
|
||||
from app import agent, app
|
||||
|
||||
mock_llm = Mock()
|
||||
mock_llm.complete.return_value = {
|
||||
"role": "assistant",
|
||||
"content": '{"result": "some data", "count": 5}'
|
||||
"content": '{"result": "some data", "count": 5}',
|
||||
}
|
||||
agent.llm = mock_llm
|
||||
|
||||
|
||||
client = TestClient(app)
|
||||
|
||||
response = client.post("/v1/chat/completions", json={
|
||||
"model": "agent-media",
|
||||
"messages": [{"role": "user", "content": "Give me JSON"}],
|
||||
})
|
||||
response = client.post(
|
||||
"/v1/chat/completions",
|
||||
json={
|
||||
"model": "agent-media",
|
||||
"messages": [{"role": "user", "content": "Give me JSON"}],
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
content = response.json()["choices"][0]["message"]["content"]
|
||||
@@ -425,6 +470,7 @@ class TestMemoryEndpointsEdgeCases:
|
||||
with patch("app.DeepSeekClient") as mock_llm:
|
||||
mock_llm.return_value = Mock()
|
||||
from app import app
|
||||
|
||||
client = TestClient(app)
|
||||
|
||||
# Clear multiple times
|
||||
@@ -459,6 +505,7 @@ class TestHealthEndpointEdgeCases:
|
||||
with patch("app.DeepSeekClient") as mock_llm:
|
||||
mock_llm.return_value = Mock()
|
||||
from app import app
|
||||
|
||||
client = TestClient(app)
|
||||
|
||||
response = client.get("/health")
|
||||
@@ -471,6 +518,7 @@ class TestHealthEndpointEdgeCases:
|
||||
with patch("app.DeepSeekClient") as mock_llm:
|
||||
mock_llm.return_value = Mock()
|
||||
from app import app
|
||||
|
||||
client = TestClient(app)
|
||||
|
||||
response = client.get("/health?extra=param&another=value")
|
||||
@@ -486,6 +534,7 @@ class TestModelsEndpointEdgeCases:
|
||||
with patch("app.DeepSeekClient") as mock_llm:
|
||||
mock_llm.return_value = Mock()
|
||||
from app import app
|
||||
|
||||
client = TestClient(app)
|
||||
|
||||
response = client.get("/v1/models")
|
||||
|
||||
Reference in New Issue
Block a user