Update backend schema
This commit is contained in:
1
api/tests/__init__.py
Normal file
1
api/tests/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
# Tests package
|
||||
102
api/tests/conftest.py
Normal file
102
api/tests/conftest.py
Normal file
@@ -0,0 +1,102 @@
|
||||
"""Pytest fixtures for API tests"""
|
||||
import os
|
||||
import sys
|
||||
import pytest
|
||||
|
||||
# Add api directory to path
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from fastapi.testclient import TestClient
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from sqlalchemy.pool import StaticPool
|
||||
|
||||
from app.db import Base, get_db
|
||||
from app.main import app
|
||||
|
||||
|
||||
# Use in-memory SQLite for testing
|
||||
DATABASE_URL = "sqlite:///:memory:"
|
||||
|
||||
engine = create_engine(
|
||||
DATABASE_URL,
|
||||
connect_args={"check_same_thread": False},
|
||||
poolclass=StaticPool,
|
||||
)
|
||||
TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def db_session():
|
||||
"""Create a fresh database session for each test"""
|
||||
# Create all tables
|
||||
Base.metadata.create_all(bind=engine)
|
||||
|
||||
session = TestingSessionLocal()
|
||||
try:
|
||||
yield session
|
||||
finally:
|
||||
session.close()
|
||||
# Drop all tables after test
|
||||
Base.metadata.drop_all(bind=engine)
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def client(db_session):
|
||||
"""Create a test client with database dependency override"""
|
||||
|
||||
def override_get_db():
|
||||
try:
|
||||
yield db_session
|
||||
finally:
|
||||
pass
|
||||
|
||||
app.dependency_overrides[get_db] = override_get_db
|
||||
|
||||
with TestClient(app) as test_client:
|
||||
yield test_client
|
||||
|
||||
app.dependency_overrides.clear()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_voice_data():
|
||||
"""Sample voice data for testing"""
|
||||
return {
|
||||
"name": "Test Voice",
|
||||
"vendor": "TestVendor",
|
||||
"gender": "Female",
|
||||
"language": "zh",
|
||||
"description": "A test voice for unit testing",
|
||||
"model": "test-model",
|
||||
"voice_key": "test-key",
|
||||
"speed": 1.0,
|
||||
"gain": 0,
|
||||
"pitch": 0,
|
||||
"enabled": True
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_assistant_data():
|
||||
"""Sample assistant data for testing"""
|
||||
return {
|
||||
"name": "Test Assistant",
|
||||
"opener": "Hello, welcome!",
|
||||
"prompt": "You are a helpful assistant.",
|
||||
"language": "zh",
|
||||
"speed": 1.0,
|
||||
"hotwords": ["test", "hello"],
|
||||
"tools": [],
|
||||
"configMode": "platform"
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_call_record_data():
|
||||
"""Sample call record data for testing"""
|
||||
return {
|
||||
"user_id": 1,
|
||||
"assistant_id": None,
|
||||
"source": "debug"
|
||||
}
|
||||
168
api/tests/test_assistants.py
Normal file
168
api/tests/test_assistants.py
Normal file
@@ -0,0 +1,168 @@
|
||||
"""Tests for Assistant API endpoints"""
|
||||
import pytest
|
||||
import uuid
|
||||
|
||||
|
||||
class TestAssistantAPI:
|
||||
"""Test cases for Assistant endpoints"""
|
||||
|
||||
def test_get_assistants_empty(self, client):
|
||||
"""Test getting assistants when database is empty"""
|
||||
response = client.get("/api/assistants")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert "total" in data
|
||||
assert "list" in data
|
||||
|
||||
def test_create_assistant(self, client, sample_assistant_data):
|
||||
"""Test creating a new assistant"""
|
||||
response = client.post("/api/assistants", json=sample_assistant_data)
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["name"] == sample_assistant_data["name"]
|
||||
assert data["opener"] == sample_assistant_data["opener"]
|
||||
assert data["prompt"] == sample_assistant_data["prompt"]
|
||||
assert data["language"] == sample_assistant_data["language"]
|
||||
assert "id" in data
|
||||
assert data["callCount"] == 0
|
||||
|
||||
def test_create_assistant_minimal(self, client):
|
||||
"""Test creating an assistant with minimal required data"""
|
||||
data = {"name": "Minimal Assistant"}
|
||||
response = client.post("/api/assistants", json=data)
|
||||
assert response.status_code == 200
|
||||
assert response.json()["name"] == "Minimal Assistant"
|
||||
|
||||
def test_get_assistant_by_id(self, client, sample_assistant_data):
|
||||
"""Test getting a specific assistant by ID"""
|
||||
# Create first
|
||||
create_response = client.post("/api/assistants", json=sample_assistant_data)
|
||||
assistant_id = create_response.json()["id"]
|
||||
|
||||
# Get by ID
|
||||
response = client.get(f"/api/assistants/{assistant_id}")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["id"] == assistant_id
|
||||
assert data["name"] == sample_assistant_data["name"]
|
||||
|
||||
def test_get_assistant_not_found(self, client):
|
||||
"""Test getting a non-existent assistant"""
|
||||
response = client.get("/api/assistants/non-existent-id")
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_update_assistant(self, client, sample_assistant_data):
|
||||
"""Test updating an assistant"""
|
||||
# Create first
|
||||
create_response = client.post("/api/assistants", json=sample_assistant_data)
|
||||
assistant_id = create_response.json()["id"]
|
||||
|
||||
# Update
|
||||
update_data = {
|
||||
"name": "Updated Assistant",
|
||||
"prompt": "You are an updated assistant.",
|
||||
"speed": 1.5
|
||||
}
|
||||
response = client.put(f"/api/assistants/{assistant_id}", json=update_data)
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["name"] == "Updated Assistant"
|
||||
assert data["prompt"] == "You are an updated assistant."
|
||||
assert data["speed"] == 1.5
|
||||
|
||||
def test_delete_assistant(self, client, sample_assistant_data):
|
||||
"""Test deleting an assistant"""
|
||||
# Create first
|
||||
create_response = client.post("/api/assistants", json=sample_assistant_data)
|
||||
assistant_id = create_response.json()["id"]
|
||||
|
||||
# Delete
|
||||
response = client.delete(f"/api/assistants/{assistant_id}")
|
||||
assert response.status_code == 200
|
||||
|
||||
# Verify deleted
|
||||
get_response = client.get(f"/api/assistants/{assistant_id}")
|
||||
assert get_response.status_code == 404
|
||||
|
||||
def test_list_assistants_with_pagination(self, client, sample_assistant_data):
|
||||
"""Test listing assistants with pagination"""
|
||||
# Create multiple assistants
|
||||
for i in range(3):
|
||||
data = sample_assistant_data.copy()
|
||||
data["name"] = f"Assistant {i}"
|
||||
client.post("/api/assistants", json=data)
|
||||
|
||||
# Test pagination
|
||||
response = client.get("/api/assistants?page=1&limit=2")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["total"] == 3
|
||||
assert len(data["list"]) == 2
|
||||
|
||||
def test_create_assistant_with_voice(self, client, sample_assistant_data, sample_voice_data):
|
||||
"""Test creating an assistant with a voice reference"""
|
||||
# Create a voice first
|
||||
voice_response = client.post("/api/voices", json=sample_voice_data)
|
||||
voice_id = voice_response.json()["id"]
|
||||
|
||||
# Create assistant with voice
|
||||
sample_assistant_data["voice"] = voice_id
|
||||
response = client.post("/api/assistants", json=sample_assistant_data)
|
||||
assert response.status_code == 200
|
||||
assert response.json()["voice"] == voice_id
|
||||
|
||||
def test_create_assistant_with_knowledge_base(self, client, sample_assistant_data):
|
||||
"""Test creating an assistant with knowledge base reference"""
|
||||
# Note: This test assumes knowledge base doesn't exist
|
||||
sample_assistant_data["knowledgeBaseId"] = "non-existent-kb"
|
||||
response = client.post("/api/assistants", json=sample_assistant_data)
|
||||
assert response.status_code == 200
|
||||
assert response.json()["knowledgeBaseId"] == "non-existent-kb"
|
||||
|
||||
def test_assistant_with_model_references(self, client, sample_assistant_data):
|
||||
"""Test creating assistant with model references"""
|
||||
sample_assistant_data.update({
|
||||
"llmModelId": "llm-001",
|
||||
"asrModelId": "asr-001",
|
||||
"embeddingModelId": "emb-001",
|
||||
"rerankModelId": "rerank-001"
|
||||
})
|
||||
response = client.post("/api/assistants", json=sample_assistant_data)
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["llmModelId"] == "llm-001"
|
||||
assert data["asrModelId"] == "asr-001"
|
||||
assert data["embeddingModelId"] == "emb-001"
|
||||
assert data["rerankModelId"] == "rerank-001"
|
||||
|
||||
def test_assistant_with_tools(self, client, sample_assistant_data):
|
||||
"""Test creating assistant with tools"""
|
||||
sample_assistant_data["tools"] = ["weather", "calculator", "search"]
|
||||
response = client.post("/api/assistants", json=sample_assistant_data)
|
||||
assert response.status_code == 200
|
||||
assert response.json()["tools"] == ["weather", "calculator", "search"]
|
||||
|
||||
def test_assistant_with_hotwords(self, client, sample_assistant_data):
|
||||
"""Test creating assistant with hotwords"""
|
||||
sample_assistant_data["hotwords"] = ["hello", "help", "stop"]
|
||||
response = client.post("/api/assistants", json=sample_assistant_data)
|
||||
assert response.status_code == 200
|
||||
assert response.json()["hotwords"] == ["hello", "help", "stop"]
|
||||
|
||||
def test_different_config_modes(self, client, sample_assistant_data):
|
||||
"""Test creating assistants with different config modes"""
|
||||
for mode in ["platform", "dify", "fastgpt", "none"]:
|
||||
sample_assistant_data["name"] = f"Assistant {mode}"
|
||||
sample_assistant_data["configMode"] = mode
|
||||
response = client.post("/api/assistants", json=sample_assistant_data)
|
||||
assert response.status_code == 200
|
||||
assert response.json()["configMode"] == mode
|
||||
|
||||
def test_different_languages(self, client, sample_assistant_data):
|
||||
"""Test creating assistants with different languages"""
|
||||
for lang in ["zh", "en", "ja", "ko"]:
|
||||
sample_assistant_data["name"] = f"Assistant {lang}"
|
||||
sample_assistant_data["language"] = lang
|
||||
response = client.post("/api/assistants", json=sample_assistant_data)
|
||||
assert response.status_code == 200
|
||||
assert response.json()["language"] == lang
|
||||
236
api/tests/test_history.py
Normal file
236
api/tests/test_history.py
Normal file
@@ -0,0 +1,236 @@
|
||||
"""Tests for History/Call Record API endpoints"""
|
||||
import pytest
|
||||
import time
|
||||
|
||||
|
||||
class TestHistoryAPI:
|
||||
"""Test cases for History/Call Record endpoints"""
|
||||
|
||||
def test_get_history_empty(self, client):
|
||||
"""Test getting history when database is empty"""
|
||||
response = client.get("/api/history")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert "total" in data
|
||||
assert "list" in data
|
||||
|
||||
def test_create_call_record(self, client, sample_call_record_data):
|
||||
"""Test creating a new call record"""
|
||||
response = client.post("/api/history", json=sample_call_record_data)
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["user_id"] == sample_call_record_data["user_id"]
|
||||
assert data["source"] == sample_call_record_data["source"]
|
||||
assert data["status"] == "connected"
|
||||
assert "id" in data
|
||||
assert "started_at" in data
|
||||
|
||||
def test_create_call_record_with_assistant(self, client, sample_assistant_data, sample_call_record_data):
|
||||
"""Test creating a call record associated with an assistant"""
|
||||
# Create assistant first
|
||||
assistant_response = client.post("/api/assistants", json=sample_assistant_data)
|
||||
assistant_id = assistant_response.json()["id"]
|
||||
|
||||
# Create call record with assistant
|
||||
sample_call_record_data["assistant_id"] = assistant_id
|
||||
response = client.post("/api/history", json=sample_call_record_data)
|
||||
assert response.status_code == 200
|
||||
assert response.json()["assistant_id"] == assistant_id
|
||||
|
||||
def test_get_call_record_by_id(self, client, sample_call_record_data):
|
||||
"""Test getting a specific call record by ID"""
|
||||
# Create first
|
||||
create_response = client.post("/api/history", json=sample_call_record_data)
|
||||
record_id = create_response.json()["id"]
|
||||
|
||||
# Get by ID
|
||||
response = client.get(f"/api/history/{record_id}")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["id"] == record_id
|
||||
|
||||
def test_get_call_record_not_found(self, client):
|
||||
"""Test getting a non-existent call record"""
|
||||
response = client.get("/api/history/non-existent-id")
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_update_call_record(self, client, sample_call_record_data):
|
||||
"""Test updating a call record"""
|
||||
# Create first
|
||||
create_response = client.post("/api/history", json=sample_call_record_data)
|
||||
record_id = create_response.json()["id"]
|
||||
|
||||
# Update
|
||||
update_data = {
|
||||
"status": "completed",
|
||||
"summary": "Test summary",
|
||||
"duration_seconds": 120
|
||||
}
|
||||
response = client.put(f"/api/history/{record_id}", json=update_data)
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["status"] == "completed"
|
||||
assert data["summary"] == "Test summary"
|
||||
assert data["duration_seconds"] == 120
|
||||
|
||||
def test_delete_call_record(self, client, sample_call_record_data):
|
||||
"""Test deleting a call record"""
|
||||
# Create first
|
||||
create_response = client.post("/api/history", json=sample_call_record_data)
|
||||
record_id = create_response.json()["id"]
|
||||
|
||||
# Delete
|
||||
response = client.delete(f"/api/history/{record_id}")
|
||||
assert response.status_code == 200
|
||||
|
||||
# Verify deleted
|
||||
get_response = client.get(f"/api/history/{record_id}")
|
||||
assert get_response.status_code == 404
|
||||
|
||||
def test_add_transcript(self, client, sample_call_record_data):
|
||||
"""Test adding a transcript to a call record"""
|
||||
# Create call record first
|
||||
create_response = client.post("/api/history", json=sample_call_record_data)
|
||||
record_id = create_response.json()["id"]
|
||||
|
||||
# Add transcript
|
||||
transcript_data = {
|
||||
"turn_index": 0,
|
||||
"speaker": "human",
|
||||
"content": "Hello, I need help",
|
||||
"start_ms": 0,
|
||||
"end_ms": 3000,
|
||||
"confidence": 0.95
|
||||
}
|
||||
response = client.post(
|
||||
f"/api/history/{record_id}/transcripts",
|
||||
json=transcript_data
|
||||
)
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["turn_index"] == 0
|
||||
assert data["speaker"] == "human"
|
||||
assert data["content"] == "Hello, I need help"
|
||||
|
||||
def test_add_multiple_transcripts(self, client, sample_call_record_data):
|
||||
"""Test adding multiple transcripts"""
|
||||
# Create call record first
|
||||
create_response = client.post("/api/history", json=sample_call_record_data)
|
||||
record_id = create_response.json()["id"]
|
||||
|
||||
# Add human transcript
|
||||
human_transcript = {
|
||||
"turn_index": 0,
|
||||
"speaker": "human",
|
||||
"content": "Hello",
|
||||
"start_ms": 0,
|
||||
"end_ms": 1000
|
||||
}
|
||||
client.post(f"/api/history/{record_id}/transcripts", json=human_transcript)
|
||||
|
||||
# Add AI transcript
|
||||
ai_transcript = {
|
||||
"turn_index": 1,
|
||||
"speaker": "ai",
|
||||
"content": "Hello! How can I help you?",
|
||||
"start_ms": 1500,
|
||||
"end_ms": 4000
|
||||
}
|
||||
client.post(f"/api/history/{record_id}/transcripts", json=ai_transcript)
|
||||
|
||||
# Verify both transcripts exist
|
||||
response = client.get(f"/api/history/{record_id}")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert len(data["transcripts"]) == 2
|
||||
|
||||
def test_filter_history_by_status(self, client, sample_call_record_data):
|
||||
"""Test filtering history by status"""
|
||||
# Create records with different statuses
|
||||
for i in range(2):
|
||||
data = sample_call_record_data.copy()
|
||||
data["status"] = "connected" if i % 2 == 0 else "missed"
|
||||
client.post("/api/history", json=data)
|
||||
|
||||
# Filter by status
|
||||
response = client.get("/api/history?status=connected")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
for record in data["list"]:
|
||||
assert record["status"] == "connected"
|
||||
|
||||
def test_filter_history_by_source(self, client, sample_call_record_data):
|
||||
"""Test filtering history by source"""
|
||||
sample_call_record_data["source"] = "external"
|
||||
client.post("/api/history", json=sample_call_record_data)
|
||||
|
||||
response = client.get("/api/history?source=external")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
for record in data["list"]:
|
||||
assert record["source"] == "external"
|
||||
|
||||
def test_history_pagination(self, client, sample_call_record_data):
|
||||
"""Test history pagination"""
|
||||
# Create multiple records
|
||||
for i in range(5):
|
||||
data = sample_call_record_data.copy()
|
||||
data["source"] = f"source-{i}"
|
||||
client.post("/api/history", json=data)
|
||||
|
||||
# Test pagination
|
||||
response = client.get("/api/history?page=1&limit=3")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["total"] == 5
|
||||
assert len(data["list"]) == 3
|
||||
|
||||
def test_transcript_with_emotion(self, client, sample_call_record_data):
|
||||
"""Test adding transcript with emotion"""
|
||||
# Create call record first
|
||||
create_response = client.post("/api/history", json=sample_call_record_data)
|
||||
record_id = create_response.json()["id"]
|
||||
|
||||
# Add transcript with emotion
|
||||
transcript_data = {
|
||||
"turn_index": 0,
|
||||
"speaker": "ai",
|
||||
"content": "Great news!",
|
||||
"start_ms": 0,
|
||||
"end_ms": 2000,
|
||||
"emotion": "happy"
|
||||
}
|
||||
response = client.post(
|
||||
f"/api/history/{record_id}/transcripts",
|
||||
json=transcript_data
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert response.json()["emotion"] == "happy"
|
||||
|
||||
def test_history_with_cost(self, client, sample_call_record_data):
|
||||
"""Test creating history with cost"""
|
||||
sample_call_record_data["cost"] = 0.05
|
||||
response = client.post("/api/history", json=sample_call_record_data)
|
||||
assert response.status_code == 200
|
||||
assert response.json()["cost"] == 0.05
|
||||
|
||||
def test_history_search(self, client, sample_call_record_data):
|
||||
"""Test searching history"""
|
||||
# Create record
|
||||
create_response = client.post("/api/history", json=sample_call_record_data)
|
||||
record_id = create_response.json()["id"]
|
||||
|
||||
# Add transcript with searchable content
|
||||
transcript_data = {
|
||||
"turn_index": 0,
|
||||
"speaker": "human",
|
||||
"content": "I want to buy a product",
|
||||
"start_ms": 0,
|
||||
"end_ms": 3000
|
||||
}
|
||||
client.post(f"/api/history/{record_id}/transcripts", json=transcript_data)
|
||||
|
||||
# Search (this endpoint may not exist yet)
|
||||
response = client.get("/api/history/search?q=product")
|
||||
# This might return 404 if endpoint doesn't exist
|
||||
assert response.status_code in [200, 404]
|
||||
255
api/tests/test_knowledge.py
Normal file
255
api/tests/test_knowledge.py
Normal file
@@ -0,0 +1,255 @@
|
||||
"""Tests for Knowledge Base API endpoints"""
|
||||
import pytest
|
||||
import uuid
|
||||
|
||||
|
||||
class TestKnowledgeAPI:
|
||||
"""Test cases for Knowledge Base endpoints"""
|
||||
|
||||
def test_get_knowledge_bases_empty(self, client):
|
||||
"""Test getting knowledge bases when database is empty"""
|
||||
response = client.get("/api/knowledge/bases")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert "total" in data
|
||||
assert "list" in data
|
||||
|
||||
def test_create_knowledge_base(self, client):
|
||||
"""Test creating a new knowledge base"""
|
||||
data = {
|
||||
"name": "Test Knowledge Base",
|
||||
"description": "A test knowledge base",
|
||||
"embeddingModel": "text-embedding-3-small",
|
||||
"chunkSize": 500,
|
||||
"chunkOverlap": 50
|
||||
}
|
||||
response = client.post("/api/knowledge/bases", json=data)
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["name"] == "Test Knowledge Base"
|
||||
assert data["description"] == "A test knowledge base"
|
||||
assert data["embeddingModel"] == "text-embedding-3-small"
|
||||
assert "id" in data
|
||||
assert data["docCount"] == 0
|
||||
assert data["chunkCount"] == 0
|
||||
assert data["status"] == "active"
|
||||
|
||||
def test_create_knowledge_base_minimal(self, client):
|
||||
"""Test creating a knowledge base with minimal data"""
|
||||
data = {"name": "Minimal KB"}
|
||||
response = client.post("/api/knowledge/bases", json=data)
|
||||
assert response.status_code == 200
|
||||
assert response.json()["name"] == "Minimal KB"
|
||||
|
||||
def test_get_knowledge_base_by_id(self, client):
|
||||
"""Test getting a specific knowledge base by ID"""
|
||||
# Create first
|
||||
create_data = {"name": "Test KB"}
|
||||
create_response = client.post("/api/knowledge/bases", json=create_data)
|
||||
kb_id = create_response.json()["id"]
|
||||
|
||||
# Get by ID
|
||||
response = client.get(f"/api/knowledge/bases/{kb_id}")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["id"] == kb_id
|
||||
assert data["name"] == "Test KB"
|
||||
|
||||
def test_get_knowledge_base_not_found(self, client):
|
||||
"""Test getting a non-existent knowledge base"""
|
||||
response = client.get("/api/knowledge/bases/non-existent-id")
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_update_knowledge_base(self, client):
|
||||
"""Test updating a knowledge base"""
|
||||
# Create first
|
||||
create_data = {"name": "Original Name"}
|
||||
create_response = client.post("/api/knowledge/bases", json=create_data)
|
||||
kb_id = create_response.json()["id"]
|
||||
|
||||
# Update
|
||||
update_data = {
|
||||
"name": "Updated Name",
|
||||
"description": "Updated description",
|
||||
"chunkSize": 800
|
||||
}
|
||||
response = client.put(f"/api/knowledge/bases/{kb_id}", json=update_data)
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["name"] == "Updated Name"
|
||||
assert data["description"] == "Updated description"
|
||||
assert data["chunkSize"] == 800
|
||||
|
||||
def test_delete_knowledge_base(self, client):
|
||||
"""Test deleting a knowledge base"""
|
||||
# Create first
|
||||
create_data = {"name": "To Delete"}
|
||||
create_response = client.post("/api/knowledge/bases", json=create_data)
|
||||
kb_id = create_response.json()["id"]
|
||||
|
||||
# Delete
|
||||
response = client.delete(f"/api/knowledge/bases/{kb_id}")
|
||||
assert response.status_code == 200
|
||||
|
||||
# Verify deleted
|
||||
get_response = client.get(f"/api/knowledge/bases/{kb_id}")
|
||||
assert get_response.status_code == 404
|
||||
|
||||
def test_upload_document(self, client):
|
||||
"""Test uploading a document to knowledge base"""
|
||||
# Create KB first
|
||||
create_data = {"name": "Test KB for Docs"}
|
||||
create_response = client.post("/api/knowledge/bases", json=create_data)
|
||||
kb_id = create_response.json()["id"]
|
||||
|
||||
# Upload document
|
||||
doc_data = {
|
||||
"name": "test-document.txt",
|
||||
"size": "1024",
|
||||
"fileType": "txt",
|
||||
"storageUrl": "https://storage.example.com/test-document.txt"
|
||||
}
|
||||
response = client.post(
|
||||
f"/api/knowledge/bases/{kb_id}/documents",
|
||||
json=doc_data
|
||||
)
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["name"] == "test-document.txt"
|
||||
assert "id" in data
|
||||
assert data["status"] == "pending"
|
||||
|
||||
def test_delete_document(self, client):
|
||||
"""Test deleting a document from knowledge base"""
|
||||
# Create KB first
|
||||
create_data = {"name": "Test KB for Delete"}
|
||||
create_response = client.post("/api/knowledge/bases", json=create_data)
|
||||
kb_id = create_response.json()["id"]
|
||||
|
||||
# Upload document
|
||||
doc_data = {"name": "to-delete.txt", "size": "100", "fileType": "txt"}
|
||||
upload_response = client.post(
|
||||
f"/api/knowledge/bases/{kb_id}/documents",
|
||||
json=doc_data
|
||||
)
|
||||
doc_id = upload_response.json()["id"]
|
||||
|
||||
# Delete document
|
||||
response = client.delete(
|
||||
f"/api/knowledge/bases/{kb_id}/documents/{doc_id}"
|
||||
)
|
||||
assert response.status_code == 200
|
||||
|
||||
def test_index_document(self, client):
|
||||
"""Test indexing a document"""
|
||||
# Create KB first
|
||||
create_data = {"name": "Test KB for Index"}
|
||||
create_response = client.post("/api/knowledge/bases", json=create_data)
|
||||
kb_id = create_response.json()["id"]
|
||||
|
||||
# Index document
|
||||
index_data = {
|
||||
"document_id": "doc-001",
|
||||
"content": "This is the content to index. It contains important information about the product."
|
||||
}
|
||||
response = client.post(
|
||||
f"/api/knowledge/bases/{kb_id}/documents/doc-001/index",
|
||||
json=index_data
|
||||
)
|
||||
# This might return 200 or error depending on vector store implementation
|
||||
assert response.status_code in [200, 500]
|
||||
|
||||
def test_search_knowledge(self, client):
|
||||
"""Test searching knowledge base"""
|
||||
# Create KB first
|
||||
create_data = {"name": "Test KB for Search"}
|
||||
create_response = client.post("/api/knowledge/bases", json=create_data)
|
||||
kb_id = create_response.json()["id"]
|
||||
|
||||
# Search (this may fail without indexed content)
|
||||
search_data = {
|
||||
"query": "test query",
|
||||
"kb_id": kb_id,
|
||||
"nResults": 5
|
||||
}
|
||||
response = client.post("/api/knowledge/search", json=search_data)
|
||||
# This might return 200 or error depending on implementation
|
||||
assert response.status_code in [200, 500]
|
||||
|
||||
def test_get_knowledge_stats(self, client):
|
||||
"""Test getting knowledge base statistics"""
|
||||
# Create KB first
|
||||
create_data = {"name": "Test KB for Stats"}
|
||||
create_response = client.post("/api/knowledge/bases", json=create_data)
|
||||
kb_id = create_response.json()["id"]
|
||||
|
||||
response = client.get(f"/api/knowledge/bases/{kb_id}/stats")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["kb_id"] == kb_id
|
||||
assert "docCount" in data
|
||||
assert "chunkCount" in data
|
||||
|
||||
def test_knowledge_bases_pagination(self, client):
|
||||
"""Test knowledge bases pagination"""
|
||||
# Create multiple KBs
|
||||
for i in range(5):
|
||||
data = {"name": f"Knowledge Base {i}"}
|
||||
client.post("/api/knowledge/bases", json=data)
|
||||
|
||||
# Test pagination
|
||||
response = client.get("/api/knowledge/bases?page=1&limit=3")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["total"] == 5
|
||||
assert len(data["list"]) == 3
|
||||
|
||||
def test_different_embedding_models(self, client):
|
||||
"""Test creating KB with different embedding models"""
|
||||
models = [
|
||||
"text-embedding-3-small",
|
||||
"text-embedding-3-large",
|
||||
"bge-small-zh"
|
||||
]
|
||||
for model in models:
|
||||
data = {"name": f"KB with {model}", "embeddingModel": model}
|
||||
response = client.post("/api/knowledge/bases", json=data)
|
||||
assert response.status_code == 200
|
||||
assert response.json()["embeddingModel"] == model
|
||||
|
||||
def test_different_chunk_sizes(self, client):
|
||||
"""Test creating KB with different chunk configurations"""
|
||||
configs = [
|
||||
{"chunkSize": 500, "chunkOverlap": 50},
|
||||
{"chunkSize": 1000, "chunkOverlap": 100},
|
||||
{"chunkSize": 256, "chunkOverlap": 25}
|
||||
]
|
||||
for config in configs:
|
||||
data = {"name": "Chunk Test KB", **config}
|
||||
response = client.post("/api/knowledge/bases", json=data)
|
||||
assert response.status_code == 200
|
||||
|
||||
def test_knowledge_base_with_documents(self, client):
|
||||
"""Test creating KB and adding multiple documents"""
|
||||
# Create KB
|
||||
create_data = {"name": "KB with Multiple Docs"}
|
||||
create_response = client.post("/api/knowledge/bases", json=create_data)
|
||||
kb_id = create_response.json()["id"]
|
||||
|
||||
# Add multiple documents
|
||||
for i in range(3):
|
||||
doc_data = {
|
||||
"name": f"document-{i}.txt",
|
||||
"size": f"{1000 + i * 100}",
|
||||
"fileType": "txt"
|
||||
}
|
||||
client.post(
|
||||
f"/api/knowledge/bases/{kb_id}/documents",
|
||||
json=doc_data
|
||||
)
|
||||
|
||||
# Verify documents are listed
|
||||
response = client.get(f"/api/knowledge/bases/{kb_id}")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert len(data["documents"]) == 3
|
||||
132
api/tests/test_voices.py
Normal file
132
api/tests/test_voices.py
Normal file
@@ -0,0 +1,132 @@
|
||||
"""Tests for Voice API endpoints"""
|
||||
import pytest
|
||||
|
||||
|
||||
class TestVoiceAPI:
|
||||
"""Test cases for Voice endpoints"""
|
||||
|
||||
def test_get_voices_empty(self, client):
|
||||
"""Test getting voices when database is empty"""
|
||||
response = client.get("/api/voices")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert "total" in data
|
||||
assert "list" in data
|
||||
|
||||
def test_create_voice(self, client, sample_voice_data):
|
||||
"""Test creating a new voice"""
|
||||
response = client.post("/api/voices", json=sample_voice_data)
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["name"] == sample_voice_data["name"]
|
||||
assert data["vendor"] == sample_voice_data["vendor"]
|
||||
assert data["gender"] == sample_voice_data["gender"]
|
||||
assert data["language"] == sample_voice_data["language"]
|
||||
assert "id" in data
|
||||
|
||||
def test_create_voice_minimal(self, client):
|
||||
"""Test creating a voice with minimal data"""
|
||||
data = {
|
||||
"name": "Minimal Voice",
|
||||
"vendor": "Test",
|
||||
"gender": "Male",
|
||||
"language": "en",
|
||||
"description": ""
|
||||
}
|
||||
response = client.post("/api/voices", json=data)
|
||||
assert response.status_code == 200
|
||||
|
||||
def test_get_voice_by_id(self, client, sample_voice_data):
|
||||
"""Test getting a specific voice by ID"""
|
||||
# Create first
|
||||
create_response = client.post("/api/voices", json=sample_voice_data)
|
||||
voice_id = create_response.json()["id"]
|
||||
|
||||
# Get by ID
|
||||
response = client.get(f"/api/voices/{voice_id}")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["id"] == voice_id
|
||||
assert data["name"] == sample_voice_data["name"]
|
||||
|
||||
def test_get_voice_not_found(self, client):
|
||||
"""Test getting a non-existent voice"""
|
||||
response = client.get("/api/voices/non-existent-id")
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_update_voice(self, client, sample_voice_data):
|
||||
"""Test updating a voice"""
|
||||
# Create first
|
||||
create_response = client.post("/api/voices", json=sample_voice_data)
|
||||
voice_id = create_response.json()["id"]
|
||||
|
||||
# Update
|
||||
update_data = {"name": "Updated Voice", "speed": 1.5}
|
||||
response = client.put(f"/api/voices/{voice_id}", json=update_data)
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["name"] == "Updated Voice"
|
||||
assert data["speed"] == 1.5
|
||||
|
||||
def test_delete_voice(self, client, sample_voice_data):
|
||||
"""Test deleting a voice"""
|
||||
# Create first
|
||||
create_response = client.post("/api/voices", json=sample_voice_data)
|
||||
voice_id = create_response.json()["id"]
|
||||
|
||||
# Delete
|
||||
response = client.delete(f"/api/voices/{voice_id}")
|
||||
assert response.status_code == 200
|
||||
|
||||
# Verify deleted
|
||||
get_response = client.get(f"/api/voices/{voice_id}")
|
||||
assert get_response.status_code == 404
|
||||
|
||||
def test_list_voices_with_pagination(self, client, sample_voice_data):
|
||||
"""Test listing voices with pagination"""
|
||||
# Create multiple voices
|
||||
for i in range(3):
|
||||
data = sample_voice_data.copy()
|
||||
data["name"] = f"Voice {i}"
|
||||
client.post("/api/voices", json=data)
|
||||
|
||||
# Test pagination
|
||||
response = client.get("/api/voices?page=1&limit=2")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["total"] == 3
|
||||
assert len(data["list"]) == 2
|
||||
|
||||
def test_filter_voices_by_vendor(self, client, sample_voice_data):
|
||||
"""Test filtering voices by vendor"""
|
||||
# Create voice with specific vendor
|
||||
sample_voice_data["vendor"] = "FilterTestVendor"
|
||||
client.post("/api/voices", json=sample_voice_data)
|
||||
|
||||
response = client.get("/api/voices?vendor=FilterTestVendor")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
for voice in data["list"]:
|
||||
assert voice["vendor"] == "FilterTestVendor"
|
||||
|
||||
def test_filter_voices_by_language(self, client, sample_voice_data):
|
||||
"""Test filtering voices by language"""
|
||||
sample_voice_data["language"] = "en"
|
||||
client.post("/api/voices", json=sample_voice_data)
|
||||
|
||||
response = client.get("/api/voices?language=en")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
for voice in data["list"]:
|
||||
assert voice["language"] == "en"
|
||||
|
||||
def test_filter_voices_by_gender(self, client, sample_voice_data):
|
||||
"""Test filtering voices by gender"""
|
||||
sample_voice_data["gender"] = "Female"
|
||||
client.post("/api/voices", json=sample_voice_data)
|
||||
|
||||
response = client.get("/api/voices?gender=Female")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
for voice in data["list"]:
|
||||
assert voice["gender"] == "Female"
|
||||
Reference in New Issue
Block a user