178 lines
5.8 KiB
Python
178 lines
5.8 KiB
Python
"""Tests for the JSON chat API (/api/chat, /api/upload, /api/chat/history)."""
|
|
|
|
import io
|
|
from unittest.mock import patch
|
|
|
|
|
|
# ── POST /api/chat ────────────────────────────────────────────────────────────
|
|
|
|
|
|
def test_api_chat_success(client):
|
|
with patch("dashboard.routes.chat_api.agent_chat", return_value="Hello."):
|
|
response = client.post(
|
|
"/api/chat",
|
|
json={"messages": [{"role": "user", "content": "hello"}]},
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["reply"] == "Hello."
|
|
assert "timestamp" in data
|
|
|
|
|
|
def test_api_chat_multimodal_content(client):
|
|
"""Multimodal content arrays should extract text parts."""
|
|
with patch("dashboard.routes.chat_api.agent_chat", return_value="I see an image."):
|
|
response = client.post(
|
|
"/api/chat",
|
|
json={
|
|
"messages": [
|
|
{
|
|
"role": "user",
|
|
"content": [
|
|
{"type": "text", "text": "What is this?"},
|
|
{"type": "image_url", "image_url": {"url": "/uploads/test.jpg"}},
|
|
],
|
|
}
|
|
]
|
|
},
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
assert response.json()["reply"] == "I see an image."
|
|
|
|
|
|
def test_api_chat_empty_messages(client):
|
|
response = client.post("/api/chat", json={"messages": []})
|
|
assert response.status_code == 400
|
|
assert "error" in response.json()
|
|
|
|
|
|
def test_api_chat_missing_messages(client):
|
|
response = client.post("/api/chat", json={"foo": "bar"})
|
|
assert response.status_code == 400
|
|
assert "messages" in response.json()["error"]
|
|
|
|
|
|
def test_api_chat_no_user_message(client):
|
|
response = client.post(
|
|
"/api/chat",
|
|
json={"messages": [{"role": "assistant", "content": "hi"}]},
|
|
)
|
|
assert response.status_code == 400
|
|
assert "No user message" in response.json()["error"]
|
|
|
|
|
|
def test_api_chat_ollama_offline(client):
|
|
with patch(
|
|
"dashboard.routes.chat_api.agent_chat",
|
|
side_effect=ConnectionError("Ollama unreachable"),
|
|
):
|
|
response = client.post(
|
|
"/api/chat",
|
|
json={"messages": [{"role": "user", "content": "hello"}]},
|
|
)
|
|
|
|
assert response.status_code == 503
|
|
data = response.json()
|
|
assert "offline" in data["error"].lower() or "unreachable" in data["error"].lower()
|
|
|
|
|
|
def test_api_chat_logs_to_message_log(client):
|
|
from dashboard.store import message_log
|
|
|
|
with patch("dashboard.routes.chat_api.agent_chat", return_value="Reply."):
|
|
client.post(
|
|
"/api/chat",
|
|
json={"messages": [{"role": "user", "content": "test msg"}]},
|
|
)
|
|
|
|
entries = message_log.all()
|
|
assert len(entries) == 2
|
|
assert entries[0].role == "user"
|
|
assert entries[0].content == "test msg"
|
|
assert entries[1].role == "agent"
|
|
assert entries[1].content == "Reply."
|
|
|
|
|
|
def test_api_chat_invalid_json(client):
|
|
response = client.post(
|
|
"/api/chat",
|
|
content=b"not json",
|
|
headers={"content-type": "application/json"},
|
|
)
|
|
assert response.status_code == 400
|
|
|
|
|
|
# ── POST /api/upload ──────────────────────────────────────────────────────────
|
|
|
|
|
|
def test_api_upload_file(client, tmp_path):
|
|
with patch("dashboard.routes.chat_api._UPLOAD_DIR", str(tmp_path)):
|
|
response = client.post(
|
|
"/api/upload",
|
|
files={"file": ("test.txt", io.BytesIO(b"hello world"), "text/plain")},
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["fileName"] == "test.txt"
|
|
assert data["mimeType"] == "text/plain"
|
|
assert "/uploads/" in data["url"]
|
|
|
|
|
|
def test_api_upload_image(client, tmp_path):
|
|
# 1x1 red PNG
|
|
png = (
|
|
b"\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x01"
|
|
b"\x00\x00\x00\x01\x08\x02\x00\x00\x00\x90wS\xde\x00"
|
|
)
|
|
with patch("dashboard.routes.chat_api._UPLOAD_DIR", str(tmp_path)):
|
|
response = client.post(
|
|
"/api/upload",
|
|
files={"file": ("photo.png", io.BytesIO(png), "image/png")},
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["fileName"] == "photo.png"
|
|
assert data["mimeType"] == "image/png"
|
|
|
|
|
|
# ── GET /api/chat/history ────────────────────────────────────────────────────
|
|
|
|
|
|
def test_api_chat_history_empty(client):
|
|
response = client.get("/api/chat/history")
|
|
assert response.status_code == 200
|
|
assert response.json()["messages"] == []
|
|
|
|
|
|
def test_api_chat_history_after_chat(client):
|
|
with patch("dashboard.routes.chat_api.agent_chat", return_value="Hi!"):
|
|
client.post(
|
|
"/api/chat",
|
|
json={"messages": [{"role": "user", "content": "hello"}]},
|
|
)
|
|
|
|
response = client.get("/api/chat/history")
|
|
assert response.status_code == 200
|
|
msgs = response.json()["messages"]
|
|
assert len(msgs) == 2
|
|
assert msgs[0]["role"] == "user"
|
|
assert msgs[1]["role"] == "agent"
|
|
|
|
|
|
# ── DELETE /api/chat/history ──────────────────────────────────────────────────
|
|
|
|
|
|
def test_api_clear_history(client):
|
|
from dashboard.store import message_log
|
|
|
|
message_log.append(role="user", content="old", timestamp="00:00:00")
|
|
|
|
response = client.delete("/api/chat/history")
|
|
assert response.status_code == 200
|
|
assert response.json()["success"] is True
|
|
assert len(message_log) == 0
|