Update backend schema

This commit is contained in:
Xin Wang
2026-02-08 14:26:19 +08:00
parent b9a315177a
commit 727fe8a997
16 changed files with 1532 additions and 94 deletions

1
api/tests/__init__.py Normal file
View File

@@ -0,0 +1 @@
# Tests package

102
api/tests/conftest.py Normal file
View 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"
}

View 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
View 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
View 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
View 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"