Files
DocsMCP/tests/conftest.py
T
2026-06-05 23:02:55 +01:00

191 lines
5.4 KiB
Python

"""
Pytest configuration and fixtures for local-context7 tests.
This module provides:
- Mocks for external dependencies (Qdrant, FastEmbed)
- Database fixtures for SQLite operations
- Common test utilities
"""
from unittest.mock import MagicMock, patch
import pytest
import os
import json
from pathlib import Path
from backend.app.db import init_db, upsert_library, insert_document_chunk, get_chunks_for_library, list_libraries, clear_library_documents, get_connection
# =============================================================================
# FIXTURES
# =============================================================================
@pytest.fixture(scope="function")
def test_database():
"""
Create a fresh SQLite database for testing.
Yields:
Database connection with tables initialized
"""
# Use an in-memory or temporary file database
db_path = Path(__file__).parent.parent / "backend" / "data" / "test_db.sqlite"
# Ensure data directory exists
db_path.parent.mkdir(parents=True, exist_ok=True)
# Remove existing test DB if present
if db_path.exists():
db_path.unlink()
# Initialize database with tables
result = init_db()
assert result["success"], f"Failed to initialize test DB: {result.get('error')}"
yield
# Cleanup: remove test database after tests
if db_path.exists():
db_path.unlink()
@pytest.fixture(scope="function")
def sample_text():
"""Sample text for chunking tests."""
return """# Introduction
This is the introduction section.
## Background
Background information goes here to make this longer and test chunking.
This paragraph has more content about the background topic.
### Details
Specific details about the background are provided in this subsection.
More details follow here to ensure we have enough text to properly test heading preservation.
## Conclusion
The conclusion wraps up everything nicely."""
# =============================================================================
# MOCKS
# =============================================================================
@pytest.fixture
def mock_embedding_model():
"""
Mock FastEmbed model that returns dummy vectors.
This avoids needing to download and load the actual embedding model.
Returns 384-dimensional zero vectors for any input.
"""
mock_model = MagicMock()
# Mock embed method - returns list of lists with float values
def mock_embed(texts):
return [
[0.0] * 384 # Zero vector placeholder
for _ in texts
]
mock_model.embed = mock_embed
return mock_model
@pytest.fixture
def mock_qdrant_client():
"""
Mock Qdrant client that returns empty or test results.
Allows testing search logic without needing a running Qdrant server.
"""
mock_client = MagicMock()
# Mock search method
def mock_search(collection_name, query_vector, limit=10, search_filter=None):
# Return empty list (simulating no results)
return []
mock_client.search = mock_search
# Mock delete_collection for cleanup
mock_client.delete_collection = MagicMock(return_value=True)
return mock_client
@pytest.fixture
def mock_embedding_model_batch():
"""
Batch embedding model mock that returns deterministic fake vectors.
Returns slightly different vectors for different input lengths/first chars,
allowing tests to verify vector retrieval if needed.
"""
def hash_text(text):
# Simple hash-based pseudo-random vector generation
text_hash = hash(text) % 1000000
return [(hash_text(text) / 1000000 + (i * 0.001)) for i in range(384)]
mock_model = MagicMock()
mock_model.embed = lambda texts: [hash_text(t) for t in texts]
return mock_model
# =============================================================================
# SETUP TEARDOWN FIXTURES
# =============================================================================
@pytest.fixture(autouse=True)
def clear_test_database(test_database):
"""
Clear test database before and after each test function.
Note: This fixture runs the teardown (cleanup) AFTER the test,
so we manually clear at the end of the yield context.
The db_path is cleaned up by the test_database fixture's yield block.
"""
pass # Cleanup handled in test_database fixture
@pytest.fixture
def empty_vector():
"""Empty/dummy embedding vector for tests."""
return [0.0] * 384
@pytest.fixture
def fake_embeddings(sample_text):
"""Fake embedding vectors for sample text."""
def hash_text(text):
return [(hash(text) + len(text)) % 1000 / 10000 for _ in range(384)]
return [hash_text(s) for s in sample_text.split("\n\n") if s.strip()]
# =============================================================================
# UTILITY FUNCTIONS
# =============================================================================
@pytest.fixture
def temp_file(tmp_path):
"""Create a temporary file and yield its path."""
test_file = tmp_path / "test.txt"
return test_file
# Register custom marker for slow tests (if needed)
def pytest_configure(config):
config.addinivalue_line("markers", "slow: marks tests as slow (deselect with '-m \"not slow\"')")
def pytest_runtest_setup(item):
"""Add custom markers if needed."""
pass