forked from innovacion/searchbox
195 lines
7.6 KiB
Markdown
195 lines
7.6 KiB
Markdown
# Engine Module Test Suite
|
|
|
|
This directory contains comprehensive tests for the vector search engine module, covering all components from the abstract base engine to concrete implementations and the factory pattern.
|
|
|
|
## Test Structure
|
|
|
|
### Core Test Files
|
|
|
|
- **`test_base_engine.py`** - Tests for the abstract `BaseEngine` class
|
|
- **`test_qdrant_engine.py`** - Tests for the `QdrantEngine` implementation
|
|
- **`test_factory.py`** - Tests for the engine factory and `EngineType` enum
|
|
- **`test_integration.py`** - End-to-end integration tests
|
|
- **`conftest.py`** - Shared fixtures and test configuration
|
|
|
|
## Test Coverage
|
|
|
|
### BaseEngine Tests (`test_base_engine.py`)
|
|
- ✅ Abstract class enforcement - ensures BaseEngine cannot be instantiated
|
|
- ✅ Abstract method verification - validates required method signatures
|
|
- ✅ Generic typing constraints - tests TypeVar functionality
|
|
- ✅ Semantic search workflow - tests the complete search flow
|
|
- ✅ Condition transformation - tests with various condition types
|
|
- ✅ Response transformation - tests data structure conversion
|
|
- ✅ Parameter validation - tests default values and edge cases
|
|
|
|
### QdrantEngine Tests (`test_qdrant_engine.py`)
|
|
- ✅ Inheritance verification - ensures proper BaseEngine inheritance
|
|
- ✅ Generic type parameters - validates `BaseEngine[list[ScoredPoint], Filter]`
|
|
- ✅ Condition transformation - tests conversion to Qdrant Filter objects
|
|
- Match conditions → `MatchValue`
|
|
- MatchAny conditions → `MatchAny`
|
|
- MatchExclude conditions → `MatchExcept`
|
|
- ✅ Response transformation - tests `ScoredPoint` to `SearchRow` conversion
|
|
- ✅ Null payload filtering - ensures entries with null payloads are excluded
|
|
- ✅ Client interaction - mocks and verifies Qdrant client calls
|
|
- ✅ Error propagation - ensures client exceptions bubble up correctly
|
|
- ✅ Initialization - tests Settings and AsyncQdrantClient setup
|
|
|
|
### Factory Tests (`test_factory.py`)
|
|
- ✅ Backend type enumeration - tests `Backend` enum values and behavior
|
|
- ✅ Factory function typing - validates overload signatures for type safety
|
|
- ✅ Engine instantiation - tests creation of concrete engine instances
|
|
- ✅ Error handling - validates behavior with invalid inputs
|
|
- ✅ Caching behavior - ensures `@cache` decorator works correctly (same instances)
|
|
- ✅ COSMOS engine handling - tests NotImplementedError for unimplemented engines
|
|
- ✅ String enum behavior - tests StrEnum functionality and JSON serialization
|
|
|
|
### Integration Tests (`test_integration.py`)
|
|
- ✅ Complete workflow - factory → conditions → search → response transformation
|
|
- ✅ Parameter passing - verifies correct parameter flow through all layers
|
|
- ✅ Complex conditions - tests multiple condition types together
|
|
- ✅ Large result sets - tests handling of 100+ search results
|
|
- ✅ Edge cases - empty conditions, null payloads, error scenarios
|
|
- ✅ Named vectors - tests support for Qdrant NamedVector objects
|
|
- ✅ Multiple engine instances - tests independence and concurrent usage
|
|
|
|
## Test Fixtures (`conftest.py`)
|
|
|
|
### Automatic Fixtures
|
|
- `clear_engine_cache` - Auto-clears `@cache` decorator before/after each test
|
|
|
|
### Mock Objects
|
|
- `mock_qdrant_client` - AsyncMock for Qdrant client with default responses
|
|
- `mock_settings` - Mock Settings object with test configuration
|
|
- `mock_qdrant_engine_dependencies` - Complete mocked environment
|
|
|
|
### Sample Data
|
|
- `sample_embedding` - Standard test embedding vector
|
|
- `sample_conditions` - Common condition objects for testing
|
|
- `sample_scored_points` - Realistic ScoredPoint objects
|
|
- `sample_search_rows` - Expected SearchRow outputs
|
|
- `qdrant_filter_single/multiple` - Pre-built Qdrant Filter objects
|
|
|
|
## Running Tests
|
|
|
|
### Run All Engine Tests
|
|
```bash
|
|
uv run pytest tests/test_engine/ -v
|
|
```
|
|
|
|
### Run Specific Test File
|
|
```bash
|
|
uv run pytest tests/test_engine/test_base_engine.py -v
|
|
uv run pytest tests/test_engine/test_qdrant_engine.py -v
|
|
uv run pytest tests/test_engine/test_factory.py -v
|
|
uv run pytest tests/test_engine/test_integration.py -v
|
|
```
|
|
|
|
### Run Specific Test Class or Method
|
|
```bash
|
|
uv run pytest tests/test_engine/test_factory.py::TestEngineFactory::test_get_engine_qdrant -v
|
|
uv run pytest tests/test_engine/test_integration.py::TestEngineIntegration -v
|
|
```
|
|
|
|
### Coverage Report
|
|
```bash
|
|
uv run pytest tests/test_engine/ --cov=src/vector_search_mcp/engine --cov-report=html
|
|
```
|
|
|
|
## Test Patterns Used
|
|
|
|
### Mocking Strategy
|
|
- **External dependencies** - All external services (Qdrant client, Settings) are mocked
|
|
- **Dependency injection** - Tests inject mocks through constructor parameters
|
|
- **Return value control** - Mocks return predictable test data for assertions
|
|
|
|
### Async Testing
|
|
- Uses `@pytest.mark.asyncio` for async method testing
|
|
- `AsyncMock` objects for async client methods
|
|
- Proper await/async syntax throughout
|
|
|
|
### Type Testing
|
|
- Generic type parameter validation
|
|
- Overload signature verification
|
|
- Runtime type checking where applicable
|
|
|
|
### Error Testing
|
|
- Exception propagation validation
|
|
- Invalid input handling
|
|
- Boundary condition testing
|
|
|
|
## Key Test Insights
|
|
|
|
### Generic Typing Validation
|
|
The tests verify that the generic `BaseEngine[ResponseType, ConditionType]` pattern works correctly:
|
|
- `QdrantEngine` is typed as `BaseEngine[list[ScoredPoint], Filter]`
|
|
- Type checkers can verify correct usage at compile time
|
|
- Runtime behavior matches type declarations
|
|
|
|
### Factory Pattern Testing
|
|
The overload tests ensure proper type inference:
|
|
```python
|
|
# Type checker knows this returns QdrantEngine
|
|
engine = get_engine(Backend.QDRANT)
|
|
|
|
# Type checker knows this returns BaseEngine (generic)
|
|
backend: Backend = some_variable
|
|
engine = get_engine(backend)
|
|
```
|
|
|
|
### Caching Behavior
|
|
Tests verify that the `@cache` decorator works correctly:
|
|
```python
|
|
# Both calls return the same instance
|
|
engine1 = get_engine(Backend.QDRANT)
|
|
engine2 = get_engine(Backend.QDRANT)
|
|
assert engine1 is engine2 # Same instance due to caching
|
|
```
|
|
|
|
### Integration Flow Validation
|
|
Integration tests verify the complete data flow:
|
|
1. `get_engine()` creates proper engine instance
|
|
2. `semantic_search()` calls `transform_conditions()`
|
|
3. Transformed conditions passed to `run_similarity_query()`
|
|
4. Query response processed by `transform_response()`
|
|
5. Final `SearchRow` objects returned to caller
|
|
|
|
## Maintenance Notes
|
|
|
|
### Adding New Engine Types
|
|
When adding new engines:
|
|
1. Add enum value to `Backend`
|
|
2. Add overload signature to `get_engine()`
|
|
3. Update factory tests for new count and behavior
|
|
4. Create engine-specific test file following `test_qdrant_engine.py` pattern
|
|
5. Remember that `@cache` decorator will cache instances per backend type
|
|
|
|
### Mock Updates
|
|
If engine interfaces change:
|
|
1. Update fixture return types in `conftest.py`
|
|
2. Verify mock method signatures match real implementations
|
|
3. Update integration tests for new parameter flows
|
|
4. Ensure cache clearing fixture handles any new caching behavior
|
|
|
|
### Performance Testing
|
|
Current tests focus on correctness. For performance testing:
|
|
- Use `pytest-benchmark` for timing critical paths
|
|
- Test with realistic data sizes (1000+ embeddings)
|
|
- Mock network I/O but measure transformation logic
|
|
- Consider cache warming effects when benchmarking
|
|
|
|
## Recent Fixes Applied
|
|
|
|
### After Formatter Changes
|
|
The following issues were resolved after code formatting:
|
|
|
|
1. **Enum Rename**: `EngineType` → `Backend` - All tests updated
|
|
2. **Caching Addition**: `@cache` decorator added to `get_engine()`
|
|
- Tests updated to expect same instances (not different ones)
|
|
- Auto-cache clearing fixture added to `conftest.py`
|
|
3. **Mock Isolation**: Improved mock setup to prevent real network calls
|
|
- Proper patch contexts in all integration tests
|
|
- Cache clearing ensures clean test state
|
|
|
|
All 62 tests now pass successfully! 🎉 |