claude-os/tests/conftest.py

197 lines
5.8 KiB
Python
Raw Permalink Normal View History

2025-10-24 16:17:47 -05:00
"""
2025-10-27 17:41:44 -05:00
Pytest configuration and shared fixtures for Claude OS tests.
2025-10-24 16:17:47 -05:00
"""
import os
import pytest
import tempfile
import json
from pathlib import Path
2025-10-24 16:17:47 -05:00
from typing import Generator, Dict, Any
from unittest.mock import Mock, MagicMock
import numpy as np
# Set test environment variables (only if not already set)
# Don't override SQLITE_DB_PATH globally - let tests use their own paths
if "SQLITE_DB_PATH" not in os.environ:
os.environ["SQLITE_DB_PATH"] = os.getenv("TEST_SQLITE_DB_PATH", ":memory:")
os.environ.setdefault("OLLAMA_HOST", "http://localhost:11434")
os.environ.setdefault("EMBEDDING_MODEL", "nomic-embed-text")
os.environ.setdefault("LLM_MODEL", "llama3.1")
os.environ.setdefault("REDIS_HOST", "localhost")
os.environ.setdefault("REDIS_PORT", "6379")
2025-10-24 16:17:47 -05:00
@pytest.fixture(scope="session")
def test_db_config() -> Dict[str, str]:
"""Database configuration for tests."""
return {
"db_path": os.getenv("SQLITE_DB_PATH"),
"embedding_model": os.getenv("EMBEDDING_MODEL"),
"llm_model": os.getenv("LLM_MODEL"),
2025-10-24 16:17:47 -05:00
}
@pytest.fixture
def clean_db():
2025-10-24 16:17:47 -05:00
"""
Create a clean SQLite database for each test.
2025-10-24 16:17:47 -05:00
"""
from app.core.sqlite_manager import SQLiteManager
2025-10-24 16:17:47 -05:00
# Use a temporary file for the test database
with tempfile.NamedTemporaryFile(suffix=".db", delete=False) as temp_file:
temp_db_path = temp_file.name
2025-10-24 16:17:47 -05:00
# Create and initialize the database
manager = SQLiteManager(temp_db_path)
2025-10-24 16:17:47 -05:00
yield manager
# Clean up after test
if Path(temp_db_path).exists():
Path(temp_db_path).unlink()
2025-10-24 16:17:47 -05:00
@pytest.fixture
def sample_kb(clean_db):
"""Create a sample knowledge base for testing."""
from app.core.kb_types import KBType
kb_data = clean_db.create_collection(
name="test_kb",
kb_type=KBType.GENERIC,
description="Test knowledge base"
)
2025-10-24 16:17:47 -05:00
return {
"id": kb_data["id"],
2025-10-24 16:17:47 -05:00
"name": "test_kb",
"kb_type": KBType.GENERIC.value,
"description": "Test knowledge base",
"metadata": {}
2025-10-24 16:17:47 -05:00
}
@pytest.fixture
def sample_embedding() -> list:
"""Generate a sample 768-dimensional embedding."""
np.random.seed(42) # For reproducibility
return np.random.randn(768).tolist()
@pytest.fixture
def sample_documents(sample_kb, sample_embedding, clean_db):
"""Create sample documents with embeddings."""
2025-10-24 16:17:47 -05:00
documents = []
for i in range(5):
# Generate slightly different embeddings
np.random.seed(42 + i)
embedding = np.random.randn(768).tolist()
node_id = f"node_doc_{i}"
text_content = f"This is test document {i} with some content about testing."
metadata = {"filename": f"test_{i}.txt", "chunk_index": i}
# Add document to collection
doc_data = {
2025-10-24 16:17:47 -05:00
"node_id": node_id,
"text": text_content,
"metadata": metadata,
"embedding": embedding
}
2025-10-24 16:17:47 -05:00
# Store the document (implementation depends on SQLiteManager methods)
# This is a placeholder - adjust based on actual SQLiteManager API
documents.append(doc_data)
2025-10-24 16:17:47 -05:00
return documents
@pytest.fixture
def mock_ollama_embedding():
"""Mock Ollama embedding model."""
mock = MagicMock()
mock.get_text_embedding.return_value = np.random.randn(768).tolist()
return mock
@pytest.fixture
def mock_ollama_llm():
"""Mock Ollama LLM."""
mock = MagicMock()
mock_response = MagicMock()
mock_response.message.content = "This is a test response from the LLM."
mock.chat.return_value = mock_response
return mock
@pytest.fixture
def sample_text_file(tmp_path):
"""Create a sample text file for testing."""
file_path = tmp_path / "test_document.txt"
file_path.write_text("This is a test document.\n\nIt has multiple paragraphs.\n\nFor testing purposes.")
return file_path
@pytest.fixture
def sample_pdf_file(tmp_path):
"""Create a sample PDF file for testing (requires PyMuPDF)."""
try:
import fitz # PyMuPDF
file_path = tmp_path / "test_document.pdf"
doc = fitz.open()
page = doc.new_page()
page.insert_text((72, 72), "This is a test PDF document.\n\nIt has multiple paragraphs.\n\nFor testing purposes.")
doc.save(str(file_path))
doc.close()
return file_path
except ImportError:
pytest.skip("PyMuPDF not installed")
@pytest.fixture
def sample_markdown_file(tmp_path):
"""Create a sample Markdown file for testing."""
file_path = tmp_path / "test_document.md"
content = """# Test Document
This is a test document.
## Section 1
Some content here.
## Section 2
More content here.
"""
file_path.write_text(content)
return file_path
@pytest.fixture
def api_client(clean_db):
"""Create a test client for FastAPI with test database."""
from unittest.mock import patch
2025-10-24 16:17:47 -05:00
from fastapi.testclient import TestClient
from mcp_server.server import app
# Patch get_sqlite_manager to return the test database
with patch('app.core.sqlite_manager.get_sqlite_manager', return_value=clean_db):
with patch('mcp_server.server.get_sqlite_manager', return_value=clean_db):
yield TestClient(app)
2025-10-24 16:17:47 -05:00
# Markers for test categorization
def pytest_configure(config):
"""Configure custom markers."""
config.addinivalue_line("markers", "unit: Unit tests (fast, no external dependencies)")
config.addinivalue_line("markers", "integration: Integration tests (require database, Ollama)")
config.addinivalue_line("markers", "slow: Slow tests (may take several seconds)")
config.addinivalue_line("markers", "embeddings: Tests involving embedding generation")
config.addinivalue_line("markers", "vector: Tests involving vector operations")
config.addinivalue_line("markers", "rag: Tests involving RAG engine")
config.addinivalue_line("markers", "api: Tests involving API endpoints")