lily_fast_api / tests /test_suite.py
gbrabbit's picture
Fresh start for HF Spaces deployment
526927a
raw
history blame
14.8 kB
#!/usr/bin/env python3
"""
Lily LLM API ์ข…ํ•ฉ ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ
๋ชจ๋“  ์ฃผ์š” ๊ธฐ๋Šฅ์„ ํ…Œ์ŠคํŠธํ•˜๋Š” ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ
"""
import pytest
import requests
import time
import json
import os
import tempfile
from pathlib import Path
# ํ…Œ์ŠคํŠธ ์„ค์ •
BASE_URL = "http://localhost:8001"
TEST_USER_ID = "test_user_123"
TEST_SESSION_ID = "test_session_123"
class TestLilyLLMAPI:
"""Lily LLM API ์ข…ํ•ฉ ํ…Œ์ŠคํŠธ ํด๋ž˜์Šค"""
def setup_method(self):
"""๊ฐ ํ…Œ์ŠคํŠธ ์ „ ์‹คํ–‰"""
self.session = requests.Session()
self.token = None
def teardown_method(self):
"""๊ฐ ํ…Œ์ŠคํŠธ ํ›„ ์‹คํ–‰"""
self.session.close()
def test_01_server_health(self):
"""์„œ๋ฒ„ ์ƒํƒœ ํ™•์ธ"""
response = self.session.get(f"{BASE_URL}/health")
assert response.status_code == 200
data = response.json()
assert "status" in data
assert "current_model" in data
print("โœ… ์„œ๋ฒ„ ์ƒํƒœ ํ™•์ธ ์„ฑ๊ณต")
def test_02_models_endpoint(self):
"""๋ชจ๋ธ ๋ชฉ๋ก ์กฐํšŒ"""
response = self.session.get(f"{BASE_URL}/models")
assert response.status_code == 200
data = response.json()
assert "available_models" in data
assert len(data["available_models"]) > 0
print("โœ… ๋ชจ๋ธ ๋ชฉ๋ก ์กฐํšŒ ์„ฑ๊ณต")
def test_03_text_generation(self):
"""ํ…์ŠคํŠธ ์ƒ์„ฑ ํ…Œ์ŠคํŠธ"""
data = {
"prompt": "์•ˆ๋…•ํ•˜์„ธ์š”! ๊ฐ„๋‹จํ•œ ์ธ์‚ฌ๋ง์„ ํ•ด์ฃผ์„ธ์š”.",
"model_id": "polyglot-ko-1.3b-chat",
"max_length": 100,
"temperature": 0.7,
"top_p": 0.9,
"do_sample": True
}
response = self.session.post(f"{BASE_URL}/generate", data=data)
assert response.status_code == 200
result = response.json()
assert "generated_text" in result
assert len(result["generated_text"]) > 0
print("โœ… ํ…์ŠคํŠธ ์ƒ์„ฑ ์„ฑ๊ณต")
def test_04_user_management(self):
"""์‚ฌ์šฉ์ž ๊ด€๋ฆฌ ํ…Œ์ŠคํŠธ"""
# ์‚ฌ์šฉ์ž ์ƒ์„ฑ
user_data = {
"user_id": TEST_USER_ID,
"username": "ํ…Œ์ŠคํŠธ์‚ฌ์šฉ์ž",
"email": "test@example.com"
}
response = self.session.post(f"{BASE_URL}/user/create", data=user_data)
assert response.status_code == 200
print("โœ… ์‚ฌ์šฉ์ž ์ƒ์„ฑ ์„ฑ๊ณต")
# ์‚ฌ์šฉ์ž ์ •๋ณด ์กฐํšŒ
response = self.session.get(f"{BASE_URL}/user/{TEST_USER_ID}")
assert response.status_code == 200
user_info = response.json()
assert user_info["user_id"] == TEST_USER_ID
print("โœ… ์‚ฌ์šฉ์ž ์ •๋ณด ์กฐํšŒ ์„ฑ๊ณต")
def test_05_authentication(self):
"""์ธ์ฆ ์‹œ์Šคํ…œ ํ…Œ์ŠคํŠธ"""
# ์‚ฌ์šฉ์ž ๋“ฑ๋ก
register_data = {
"username": "testuser",
"email": "test@example.com",
"password": "testpassword123"
}
response = self.session.post(f"{BASE_URL}/auth/register", data=register_data)
assert response.status_code == 200
register_result = response.json()
assert "access_token" in register_result
self.token = register_result["access_token"]
print("โœ… ์‚ฌ์šฉ์ž ๋“ฑ๋ก ์„ฑ๊ณต")
# ๋กœ๊ทธ์ธ
login_data = {
"username": "testuser",
"password": "testpassword123"
}
response = self.session.post(f"{BASE_URL}/auth/login", data=login_data)
assert response.status_code == 200
login_result = response.json()
assert "access_token" in login_result
print("โœ… ๋กœ๊ทธ์ธ ์„ฑ๊ณต")
# ํ˜„์žฌ ์‚ฌ์šฉ์ž ์ •๋ณด ์กฐํšŒ
headers = {"Authorization": f"Bearer {self.token}"}
response = self.session.get(f"{BASE_URL}/auth/me", headers=headers)
assert response.status_code == 200
print("โœ… ํ˜„์žฌ ์‚ฌ์šฉ์ž ์ •๋ณด ์กฐํšŒ ์„ฑ๊ณต")
def test_06_chat_session_management(self):
"""์ฑ„ํŒ… ์„ธ์…˜ ๊ด€๋ฆฌ ํ…Œ์ŠคํŠธ"""
# ์„ธ์…˜ ์ƒ์„ฑ
session_data = {
"user_id": TEST_USER_ID,
"session_name": "ํ…Œ์ŠคํŠธ ์„ธ์…˜"
}
response = self.session.post(f"{BASE_URL}/session/create", data=session_data)
assert response.status_code == 200
session_result = response.json()
session_id = session_result["session_id"]
print("โœ… ์„ธ์…˜ ์ƒ์„ฑ ์„ฑ๊ณต")
# ๋ฉ”์‹œ์ง€ ์ถ”๊ฐ€
message_data = {
"session_id": session_id,
"user_id": TEST_USER_ID,
"message_type": "text",
"content": "์•ˆ๋…•ํ•˜์„ธ์š”! ํ…Œ์ŠคํŠธ ๋ฉ”์‹œ์ง€์ž…๋‹ˆ๋‹ค."
}
response = self.session.post(f"{BASE_URL}/chat/message", data=message_data)
assert response.status_code == 200
print("โœ… ๋ฉ”์‹œ์ง€ ์ถ”๊ฐ€ ์„ฑ๊ณต")
# ์ฑ„ํŒ… ๊ธฐ๋ก ์กฐํšŒ
response = self.session.get(f"{BASE_URL}/chat/history/{session_id}")
assert response.status_code == 200
history = response.json()
assert len(history) > 0
print("โœ… ์ฑ„ํŒ… ๊ธฐ๋ก ์กฐํšŒ ์„ฑ๊ณต")
def test_07_document_upload(self):
"""๋ฌธ์„œ ์—…๋กœ๋“œ ํ…Œ์ŠคํŠธ"""
# ์ž„์‹œ PDF ํŒŒ์ผ ์ƒ์„ฑ
with tempfile.NamedTemporaryFile(suffix=".pdf", delete=False) as tmp_file:
tmp_file.write(b"%PDF-1.4\n1 0 obj\n<<\n/Type /Catalog\n/Pages 2 0 R\n>>\nendobj\n2 0 obj\n<<\n/Type /Pages\n/Kids [3 0 R]\n/Count 1\n>>\nendobj\n3 0 obj\n<<\n/Type /Page\n/Parent 2 0 R\n/MediaBox [0 0 612 792]\n/Contents 4 0 R\n>>\nendobj\n4 0 obj\n<<\n/Length 44\n>>\nstream\nBT\n/F1 12 Tf\n72 720 Td\n(Test PDF) Tj\nET\nendstream\nendobj\nxref\n0 5\n0000000000 65535 f \n0000000009 00000 n \n0000000058 00000 n \n0000000115 00000 n \n0000000204 00000 n \ntrailer\n<<\n/Size 5\n/Root 1 0 R\n>>\nstartxref\n297\n%%EOF\n")
tmp_file_path = tmp_file.name
try:
with open(tmp_file_path, 'rb') as f:
files = {'file': f}
data = {'user_id': TEST_USER_ID}
response = self.session.post(f"{BASE_URL}/document/upload", files=files, data=data)
assert response.status_code == 200
upload_result = response.json()
assert "document_id" in upload_result
print("โœ… ๋ฌธ์„œ ์—…๋กœ๋“œ ์„ฑ๊ณต")
# ์‚ฌ์šฉ์ž ๋ฌธ์„œ ๋ชฉ๋ก ์กฐํšŒ
response = self.session.get(f"{BASE_URL}/documents/db/{TEST_USER_ID}")
assert response.status_code == 200
documents = response.json()
assert len(documents) > 0
print("โœ… ๋ฌธ์„œ ๋ชฉ๋ก ์กฐํšŒ ์„ฑ๊ณต")
finally:
os.unlink(tmp_file_path)
def test_08_rag_functionality(self):
"""RAG ๊ธฐ๋Šฅ ํ…Œ์ŠคํŠธ"""
# RAG ์ฟผ๋ฆฌ
rag_data = {
"query": "ํ…Œ์ŠคํŠธ ์ฟผ๋ฆฌ์ž…๋‹ˆ๋‹ค.",
"user_id": TEST_USER_ID,
"max_length": 200,
"temperature": 0.7
}
response = self.session.post(f"{BASE_URL}/rag/generate", data=rag_data)
assert response.status_code == 200
rag_result = response.json()
assert "response" in rag_result
print("โœ… RAG ์ฟผ๋ฆฌ ์„ฑ๊ณต")
def test_09_background_tasks(self):
"""๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ž‘์—… ํ…Œ์ŠคํŠธ"""
# ๋ฌธ์„œ ์ฒ˜๋ฆฌ ์ž‘์—… ์‹œ์ž‘
task_data = {
"file_path": "/tmp/test_document.pdf",
"user_id": TEST_USER_ID
}
response = self.session.post(f"{BASE_URL}/tasks/document/process", data=task_data)
assert response.status_code == 200
task_result = response.json()
assert "task_id" in task_result
task_id = task_result["task_id"]
print("โœ… ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ž‘์—… ์‹œ์ž‘ ์„ฑ๊ณต")
# ์ž‘์—… ์ƒํƒœ ํ™•์ธ
response = self.session.get(f"{BASE_URL}/tasks/{task_id}")
assert response.status_code == 200
status_result = response.json()
assert "status" in status_result
print("โœ… ์ž‘์—… ์ƒํƒœ ํ™•์ธ ์„ฑ๊ณต")
def test_10_monitoring(self):
"""๋ชจ๋‹ˆํ„ฐ๋ง ๊ธฐ๋Šฅ ํ…Œ์ŠคํŠธ"""
# ์„ฑ๋Šฅ ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์ž‘
response = self.session.post(f"{BASE_URL}/monitoring/start")
assert response.status_code == 200
print("โœ… ์„ฑ๋Šฅ ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์ž‘ ์„ฑ๊ณต")
# ๋ชจ๋‹ˆํ„ฐ๋ง ์ƒํƒœ ์กฐํšŒ
response = self.session.get(f"{BASE_URL}/monitoring/status")
assert response.status_code == 200
status_data = response.json()
assert "current_metrics" in status_data
print("โœ… ๋ชจ๋‹ˆํ„ฐ๋ง ์ƒํƒœ ์กฐํšŒ ์„ฑ๊ณต")
# ์‹œ์Šคํ…œ ๊ฑด๊ฐ• ์ƒํƒœ ์กฐํšŒ
response = self.session.get(f"{BASE_URL}/monitoring/health")
assert response.status_code == 200
health_data = response.json()
assert "status" in health_data
print("โœ… ์‹œ์Šคํ…œ ๊ฑด๊ฐ• ์ƒํƒœ ์กฐํšŒ ์„ฑ๊ณต")
# ์„ฑ๋Šฅ ๋ชจ๋‹ˆํ„ฐ๋ง ์ค‘์ง€
response = self.session.post(f"{BASE_URL}/monitoring/stop")
assert response.status_code == 200
print("โœ… ์„ฑ๋Šฅ ๋ชจ๋‹ˆํ„ฐ๋ง ์ค‘์ง€ ์„ฑ๊ณต")
def test_11_websocket_connection(self):
"""WebSocket ์—ฐ๊ฒฐ ํ…Œ์ŠคํŠธ"""
try:
import websockets
import asyncio
async def test_websocket():
uri = f"ws://localhost:8001/ws/{TEST_USER_ID}"
async with websockets.connect(uri) as websocket:
# ์—ฐ๊ฒฐ ํ…Œ์ŠคํŠธ
await websocket.send(json.dumps({
"type": "ping",
"message": "ํ…Œ์ŠคํŠธ ๋ฉ”์‹œ์ง€"
}))
# ์‘๋‹ต ๋Œ€๊ธฐ
response = await asyncio.wait_for(websocket.recv(), timeout=5.0)
data = json.loads(response)
assert "type" in data
print("โœ… WebSocket ์—ฐ๊ฒฐ ์„ฑ๊ณต")
asyncio.run(test_websocket())
except ImportError:
print("โš ๏ธ websockets ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์„ค์น˜๋˜์ง€ ์•Š์•„ WebSocket ํ…Œ์ŠคํŠธ๋ฅผ ๊ฑด๋„ˆ๋œ๋‹ˆ๋‹ค.")
except Exception as e:
print(f"โš ๏ธ WebSocket ํ…Œ์ŠคํŠธ ์‹คํŒจ: {e}")
def test_12_error_handling(self):
"""์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ ํ…Œ์ŠคํŠธ"""
# ์ž˜๋ชป๋œ ๋ชจ๋ธ ID๋กœ ์š”์ฒญ
data = {
"prompt": "ํ…Œ์ŠคํŠธ",
"model_id": "invalid-model-id",
"max_length": 100
}
response = self.session.post(f"{BASE_URL}/generate", data=data)
assert response.status_code in [400, 404, 422]
print("โœ… ์ž˜๋ชป๋œ ๋ชจ๋ธ ID ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ ์„ฑ๊ณต")
# ์ž˜๋ชป๋œ ์‚ฌ์šฉ์ž ID๋กœ ์š”์ฒญ
response = self.session.get(f"{BASE_URL}/user/invalid-user-id")
assert response.status_code in [404, 422]
print("โœ… ์ž˜๋ชป๋œ ์‚ฌ์šฉ์ž ID ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ ์„ฑ๊ณต")
def test_13_performance_metrics(self):
"""์„ฑ๋Šฅ ๋ฉ”ํŠธ๋ฆญ ํ…Œ์ŠคํŠธ"""
# ์—ฌ๋Ÿฌ ์š”์ฒญ์„ ๋ณด๋‚ด์„œ ์„ฑ๋Šฅ ์ธก์ •
start_time = time.time()
for i in range(5):
data = {
"prompt": f"ํ…Œ์ŠคํŠธ ์š”์ฒญ {i+1}",
"model_id": "polyglot-ko-1.3b-chat",
"max_length": 50,
"temperature": 0.7
}
response = self.session.post(f"{BASE_URL}/generate", data=data)
assert response.status_code == 200
end_time = time.time()
total_time = end_time - start_time
print(f"โœ… ์„ฑ๋Šฅ ํ…Œ์ŠคํŠธ ์™„๋ฃŒ: 5๊ฐœ ์š”์ฒญ์„ {total_time:.2f}์ดˆ์— ์ฒ˜๋ฆฌ")
assert total_time < 60 # 60์ดˆ ์ด๋‚ด์— ์™„๋ฃŒ๋˜์–ด์•ผ ํ•จ
def test_14_data_persistence(self):
"""๋ฐ์ดํ„ฐ ์ง€์†์„ฑ ํ…Œ์ŠคํŠธ"""
# ์‚ฌ์šฉ์ž ์ƒ์„ฑ
user_data = {
"user_id": f"persist_test_user_{int(time.time())}",
"username": "์ง€์†์„ฑํ…Œ์ŠคํŠธ์‚ฌ์šฉ์ž",
"email": "persist@test.com"
}
response = self.session.post(f"{BASE_URL}/user/create", data=user_data)
assert response.status_code == 200
user_id = user_data["user_id"]
# ์„œ๋ฒ„ ์žฌ์‹œ์ž‘ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ (์‹ค์ œ๋กœ๋Š” ์žฌ์‹œ์ž‘ํ•˜์ง€ ์•Š์Œ)
# ๋Œ€์‹  ๋™์ผํ•œ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๋‹ค์‹œ ์กฐํšŒ
response = self.session.get(f"{BASE_URL}/user/{user_id}")
assert response.status_code == 200
user_info = response.json()
assert user_info["user_id"] == user_id
print("โœ… ๋ฐ์ดํ„ฐ ์ง€์†์„ฑ ํ™•์ธ ์„ฑ๊ณต")
def run_comprehensive_test():
"""์ข…ํ•ฉ ํ…Œ์ŠคํŠธ ์‹คํ–‰"""
print("๐Ÿš€ Lily LLM API ์ข…ํ•ฉ ํ…Œ์ŠคํŠธ ์‹œ์ž‘")
print("=" * 60)
test_instance = TestLilyLLMAPI()
# ํ…Œ์ŠคํŠธ ๋ฉ”์„œ๋“œ ๋ชฉ๋ก
test_methods = [
test_instance.test_01_server_health,
test_instance.test_02_models_endpoint,
test_instance.test_03_text_generation,
test_instance.test_04_user_management,
test_instance.test_05_authentication,
test_instance.test_06_chat_session_management,
test_instance.test_07_document_upload,
test_instance.test_08_rag_functionality,
test_instance.test_09_background_tasks,
test_instance.test_10_monitoring,
test_instance.test_11_websocket_connection,
test_instance.test_12_error_handling,
test_instance.test_13_performance_metrics,
test_instance.test_14_data_persistence
]
passed_tests = 0
failed_tests = 0
for i, test_method in enumerate(test_methods, 1):
try:
print(f"\n๐Ÿ“‹ ํ…Œ์ŠคํŠธ {i}/{len(test_methods)}: {test_method.__name__}")
print("-" * 50)
test_method()
passed_tests += 1
except Exception as e:
print(f"โŒ ํ…Œ์ŠคํŠธ ์‹คํŒจ: {e}")
failed_tests += 1
# ๊ฒฐ๊ณผ ์š”์•ฝ
print("\n" + "=" * 60)
print("๐Ÿ“Š ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ ์š”์•ฝ")
print("=" * 60)
print(f"โœ… ํ†ต๊ณผ: {passed_tests}")
print(f"โŒ ์‹คํŒจ: {failed_tests}")
print(f"๐Ÿ“ˆ ์„ฑ๊ณต๋ฅ : {passed_tests/(passed_tests+failed_tests)*100:.1f}%")
if failed_tests == 0:
print("\n๐ŸŽ‰ ๋ชจ๋“  ํ…Œ์ŠคํŠธ๊ฐ€ ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค!")
return True
else:
print(f"\nโš ๏ธ {failed_tests}๊ฐœ์˜ ํ…Œ์ŠคํŠธ๊ฐ€ ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค.")
return False
if __name__ == "__main__":
success = run_comprehensive_test()
exit(0 if success else 1)