Migrate to package
This commit is contained in:
1
tests/__init__.py
Normal file
1
tests/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
"""Tests for knowledge-search-mcp."""
|
||||
36
tests/conftest.py
Normal file
36
tests/conftest.py
Normal file
@@ -0,0 +1,36 @@
|
||||
"""Pytest configuration and shared fixtures."""
|
||||
|
||||
import os
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def mock_env_vars(monkeypatch):
|
||||
"""Set required environment variables for testing."""
|
||||
test_env = {
|
||||
"PROJECT_ID": "test-project",
|
||||
"LOCATION": "us-central1",
|
||||
"BUCKET": "test-bucket",
|
||||
"INDEX_NAME": "test-index",
|
||||
"DEPLOYED_INDEX_ID": "test-deployed-index",
|
||||
"ENDPOINT_NAME": "projects/test/locations/us-central1/indexEndpoints/test",
|
||||
"ENDPOINT_DOMAIN": "test.us-central1-aiplatform.googleapis.com",
|
||||
}
|
||||
for key, value in test_env.items():
|
||||
monkeypatch.setenv(key, value)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_gcs_storage():
|
||||
"""Mock Google Cloud Storage client."""
|
||||
mock = MagicMock()
|
||||
return mock
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_vector_search():
|
||||
"""Mock vector search client."""
|
||||
mock = MagicMock()
|
||||
return mock
|
||||
56
tests/test_config.py
Normal file
56
tests/test_config.py
Normal file
@@ -0,0 +1,56 @@
|
||||
"""Tests for configuration management."""
|
||||
|
||||
import os
|
||||
|
||||
import pytest
|
||||
from pydantic import ValidationError
|
||||
|
||||
from knowledge_search_mcp.config import Settings
|
||||
|
||||
|
||||
def test_settings_from_env():
|
||||
"""Test that Settings can be loaded from environment variables."""
|
||||
# Environment is set by conftest.py fixture
|
||||
settings = Settings.model_validate({})
|
||||
|
||||
assert settings.project_id == "test-project"
|
||||
assert settings.location == "us-central1"
|
||||
assert settings.bucket == "test-bucket"
|
||||
assert settings.index_name == "test-index"
|
||||
assert settings.deployed_index_id == "test-deployed-index"
|
||||
|
||||
|
||||
def test_settings_defaults():
|
||||
"""Test that Settings has correct default values."""
|
||||
settings = Settings.model_validate({})
|
||||
|
||||
assert settings.embedding_model == "gemini-embedding-001"
|
||||
assert settings.search_limit == 10
|
||||
assert settings.log_name == "va_agent_evaluation_logs"
|
||||
assert settings.log_level == "INFO"
|
||||
|
||||
|
||||
def test_settings_custom_values(monkeypatch):
|
||||
"""Test that Settings can be customized via environment."""
|
||||
monkeypatch.setenv("EMBEDDING_MODEL", "custom-embedding-model")
|
||||
monkeypatch.setenv("SEARCH_LIMIT", "20")
|
||||
monkeypatch.setenv("LOG_LEVEL", "DEBUG")
|
||||
|
||||
settings = Settings.model_validate({})
|
||||
|
||||
assert settings.embedding_model == "custom-embedding-model"
|
||||
assert settings.search_limit == 20
|
||||
assert settings.log_level == "DEBUG"
|
||||
|
||||
|
||||
def test_settings_validation_error():
|
||||
"""Test that Settings raises ValidationError when required fields are missing."""
|
||||
# Clear all env vars temporarily
|
||||
required_vars = [
|
||||
"PROJECT_ID", "LOCATION", "BUCKET", "INDEX_NAME",
|
||||
"DEPLOYED_INDEX_ID", "ENDPOINT_NAME", "ENDPOINT_DOMAIN"
|
||||
]
|
||||
|
||||
# This should work with conftest fixture
|
||||
settings = Settings.model_validate({})
|
||||
assert settings.project_id == "test-project"
|
||||
108
tests/test_search.py
Normal file
108
tests/test_search.py
Normal file
@@ -0,0 +1,108 @@
|
||||
"""Tests for vector search functionality."""
|
||||
|
||||
import io
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from knowledge_search_mcp.main import (
|
||||
GoogleCloudFileStorage,
|
||||
GoogleCloudVectorSearch,
|
||||
SourceNamespace,
|
||||
)
|
||||
|
||||
|
||||
class TestGoogleCloudFileStorage:
|
||||
"""Tests for GoogleCloudFileStorage."""
|
||||
|
||||
def test_init(self):
|
||||
"""Test storage initialization."""
|
||||
storage = GoogleCloudFileStorage(bucket="test-bucket")
|
||||
assert storage.bucket_name == "test-bucket"
|
||||
assert storage._cache == {}
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_cache_hit(self):
|
||||
"""Test that cached files are returned without fetching."""
|
||||
storage = GoogleCloudFileStorage(bucket="test-bucket")
|
||||
test_content = b"cached content"
|
||||
storage._cache["test.md"] = test_content
|
||||
|
||||
result = await storage.async_get_file_stream("test.md")
|
||||
|
||||
assert result.read() == test_content
|
||||
assert result.name == "test.md"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_cache_miss(self):
|
||||
"""Test that uncached files are fetched from GCS."""
|
||||
storage = GoogleCloudFileStorage(bucket="test-bucket")
|
||||
test_content = b"fetched content"
|
||||
|
||||
# Mock the storage download
|
||||
with patch.object(storage, '_get_aio_storage') as mock_storage_getter:
|
||||
mock_storage = AsyncMock()
|
||||
mock_storage.download = AsyncMock(return_value=test_content)
|
||||
mock_storage_getter.return_value = mock_storage
|
||||
|
||||
result = await storage.async_get_file_stream("test.md")
|
||||
|
||||
assert result.read() == test_content
|
||||
assert storage._cache["test.md"] == test_content
|
||||
|
||||
|
||||
class TestGoogleCloudVectorSearch:
|
||||
"""Tests for GoogleCloudVectorSearch."""
|
||||
|
||||
def test_init(self):
|
||||
"""Test vector search client initialization."""
|
||||
vs = GoogleCloudVectorSearch(
|
||||
project_id="test-project",
|
||||
location="us-central1",
|
||||
bucket="test-bucket",
|
||||
index_name="test-index",
|
||||
)
|
||||
|
||||
assert vs.project_id == "test-project"
|
||||
assert vs.location == "us-central1"
|
||||
assert vs.index_name == "test-index"
|
||||
|
||||
def test_configure_index_endpoint(self):
|
||||
"""Test endpoint configuration."""
|
||||
vs = GoogleCloudVectorSearch(
|
||||
project_id="test-project",
|
||||
location="us-central1",
|
||||
bucket="test-bucket",
|
||||
)
|
||||
|
||||
vs.configure_index_endpoint(
|
||||
name="test-endpoint",
|
||||
public_domain="test.domain.com",
|
||||
)
|
||||
|
||||
assert vs._endpoint_name == "test-endpoint"
|
||||
assert vs._endpoint_domain == "test.domain.com"
|
||||
|
||||
def test_configure_index_endpoint_validation(self):
|
||||
"""Test that endpoint configuration validates inputs."""
|
||||
vs = GoogleCloudVectorSearch(
|
||||
project_id="test-project",
|
||||
location="us-central1",
|
||||
bucket="test-bucket",
|
||||
)
|
||||
|
||||
with pytest.raises(ValueError, match="endpoint name"):
|
||||
vs.configure_index_endpoint(name="", public_domain="test.com")
|
||||
|
||||
with pytest.raises(ValueError, match="endpoint domain"):
|
||||
vs.configure_index_endpoint(name="test", public_domain="")
|
||||
|
||||
|
||||
class TestSourceNamespace:
|
||||
"""Tests for SourceNamespace enum."""
|
||||
|
||||
def test_source_namespace_values(self):
|
||||
"""Test that SourceNamespace has expected values."""
|
||||
assert SourceNamespace.EDUCACION_FINANCIERA.value == "Educacion Financiera"
|
||||
assert SourceNamespace.PRODUCTOS_Y_SERVICIOS.value == "Productos y Servicios"
|
||||
assert SourceNamespace.FUNCIONALIDADES_APP_MOVIL.value == "Funcionalidades de la App Movil"
|
||||
Reference in New Issue
Block a user