Fix integration tests via mockup

This commit is contained in:
Yûki VACHOT 2025-11-29 04:54:37 +01:00
parent deeb2af493
commit 0236ef23d8
3 changed files with 95 additions and 52 deletions

View file

@ -1,19 +1,44 @@
"""Shared test fixtures.""" """Shared test fixtures."""
import os
from unittest.mock import AsyncMock, MagicMock, patch from unittest.mock import AsyncMock, MagicMock, patch
import pytest import pytest
from geoguessr_mcp.api import GeoGuessrClient
from geoguessr_mcp.api.dynamic_response import DynamicResponse from geoguessr_mcp.api.dynamic_response import DynamicResponse
from geoguessr_mcp.auth import SessionManager from geoguessr_mcp.auth import SessionManager, UserSession
from geoguessr_mcp.config import settings
from geoguessr_mcp.models import RoundGuess, Game from geoguessr_mcp.models import RoundGuess, Game
from geoguessr_mcp.services import AnalysisService, GameService, ProfileService from geoguessr_mcp.services import AnalysisService, GameService, ProfileService
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
def mock_env(monkeypatch): def mock_env(request, monkeypatch):
"""Set up environment variables for testing.""" """Set up environment variables for testing."""
monkeypatch.setenv("GEOGUESSR_NCFA_COOKIE", "test_cookie_value") # Skip this fixture if the test has the 'real_env' marker
if 'real_env' in request.keywords:
yield
return
# Clear the default cookie in settings to avoid interference
monkeypatch.setattr(settings, "DEFAULT_NCFA_COOKIE", None)
# Clear schema registry to avoid interference from registered schemas
from geoguessr_mcp.monitoring.schema.schema_registry import schema_registry
# Store original schemas
original_schemas = schema_registry.schemas.copy()
# Clear all schemas for testing
schema_registry.schemas.clear()
# Ensure required settings are set
if not hasattr(settings, "GEOGUESSR_API_URL") or not settings.GEOGUESSR_API_URL:
monkeypatch.setattr(settings, "GEOGUESSR_API_URL", "https://api.geoguessr.com")
if not hasattr(settings, "GEOGUESSR_DOMAIN_NAME") or not settings.GEOGUESSR_DOMAIN_NAME:
monkeypatch.setattr(settings, "GEOGUESSR_DOMAIN_NAME", ".geoguessr.com")
# Restore schemas after test
yield
schema_registry._schemas = original_schemas
@pytest.fixture @pytest.fixture
@ -24,6 +49,35 @@ def mock_client():
return client return client
@pytest.fixture
def real_client():
"""Create a real client with environment authentication."""
real_cookie = os.getenv("GEOGUESSR_NCFA_COOKIE")
session_manager = SessionManager(default_cookie=real_cookie)
return GeoGuessrClient(session_manager)
@pytest.fixture
def client(mock_session_manager):
"""Create a GeoGuessrClient with mocked session manager."""
return GeoGuessrClient(mock_session_manager)
@pytest.fixture
def mock_session_manager():
"""Create a mock session manager."""
manager = MagicMock(spec=SessionManager)
manager.get_session = AsyncMock(
return_value=UserSession(
ncfa_cookie="test_cookie",
user_id="test-user",
username="TestUser",
email="test@example.com",
)
)
return manager
@pytest.fixture @pytest.fixture
def mock_session(): def mock_session():
"""Create a mock async HTTP session.""" """Create a mock async HTTP session."""
@ -35,11 +89,19 @@ def mock_session():
@pytest.fixture @pytest.fixture
def session_manager(): def session_manager():
return SessionManager() """Create a SessionManager without default cookie."""
return SessionManager(default_cookie=None)
@pytest.fixture
def session_manager_with_default():
"""Create a SessionManager with a default cookie."""
return SessionManager(default_cookie="test_cookie_value")
@pytest.fixture @pytest.fixture
def mock_httpx_client(): def mock_httpx_client():
"""Create a mock httpx client for testing."""
with patch("httpx.AsyncClient") as mock_client_class: with patch("httpx.AsyncClient") as mock_client_class:
mock_client = AsyncMock() mock_client = AsyncMock()
mock_client.__aenter__.return_value = mock_client mock_client.__aenter__.return_value = mock_client
@ -89,16 +151,21 @@ def profile_service(mock_client):
@pytest.fixture @pytest.fixture
def mock_dynamic_response(): def mock_dynamic_response():
"""Create a mock DynamicResponse factory.""" """Create a DynamicResponse factory for testing."""
def create_response(data, success=True, status_code=200): def create_response(data, success=True, status_code=200, endpoint="/mock/endpoint"):
response = MagicMock(spec=DynamicResponse) """Create a real DynamicResponse instance for testing.
response.data = data :param data:
response.is_success = success :param status_code:
response.status_code = status_code :param endpoint:
response.available_fields = list(data.keys()) if isinstance(data, dict) else [] :type success: object
response.summarize.return_value = {"data_summary": data} """
return response return DynamicResponse(
data=data,
endpoint=endpoint,
status_code=status_code,
response_time_ms=100.0,
)
return create_response return create_response

View file

@ -11,7 +11,6 @@ import httpx
import pytest import pytest
from geoguessr_mcp.api import DynamicResponse, GeoGuessrClient, EndpointInfo, Endpoints from geoguessr_mcp.api import DynamicResponse, GeoGuessrClient, EndpointInfo, Endpoints
from geoguessr_mcp.auth.session import SessionManager, UserSession
from geoguessr_mcp.config import settings from geoguessr_mcp.config import settings
@ -52,7 +51,7 @@ class TestDynamicResponse:
"""Test available_fields with dict data.""" """Test available_fields with dict data."""
response = DynamicResponse( response = DynamicResponse(
data={"id": "123", "name": "Test", "score": 5000}, data={"id": "123", "name": "Test", "score": 5000},
endpoint="/v3/test", endpoint="/mock/endpoint",
status_code=200, status_code=200,
response_time_ms=100.0, response_time_ms=100.0,
) )
@ -62,7 +61,7 @@ class TestDynamicResponse:
"""Test available_fields with non-dict data.""" """Test available_fields with non-dict data."""
response = DynamicResponse( response = DynamicResponse(
data=["item1", "item2"], data=["item1", "item2"],
endpoint="/v3/test", endpoint="/mock/endpoint",
status_code=200, status_code=200,
response_time_ms=100.0, response_time_ms=100.0,
) )
@ -72,7 +71,7 @@ class TestDynamicResponse:
"""Test getting a simple field.""" """Test getting a simple field."""
response = DynamicResponse( response = DynamicResponse(
data={"id": "123", "name": "Test"}, data={"id": "123", "name": "Test"},
endpoint="/v3/test", endpoint="/mock/endpoint",
status_code=200, status_code=200,
response_time_ms=100.0, response_time_ms=100.0,
) )
@ -90,7 +89,7 @@ class TestDynamicResponse:
} }
} }
}, },
endpoint="/v3/test", endpoint="/mock/endpoint",
status_code=200, status_code=200,
response_time_ms=100.0, response_time_ms=100.0,
) )
@ -101,7 +100,7 @@ class TestDynamicResponse:
"""Test getting missing field returns default.""" """Test getting missing field returns default."""
response = DynamicResponse( response = DynamicResponse(
data={"id": "123"}, data={"id": "123"},
endpoint="/v3/test", endpoint="/mock/endpoint",
status_code=200, status_code=200,
response_time_ms=100.0, response_time_ms=100.0,
) )
@ -137,13 +136,13 @@ class TestDynamicResponse:
], ],
"total": 4, "total": 4,
}, },
endpoint="/v3/test", endpoint="/mock/endpoint",
status_code=200, status_code=200,
response_time_ms=100.0, response_time_ms=100.0,
) )
summary = response.summarize(max_depth=1) summary = response.summarize(max_depth=1)
assert summary["endpoint"] == "/v3/test" assert summary["endpoint"] == "/mock/endpoint"
assert summary["status"] == "success" assert summary["status"] == "success"
assert "data_summary" in summary assert "data_summary" in summary
@ -152,7 +151,7 @@ class TestDynamicResponse:
long_text = "x" * 200 long_text = "x" * 200
response = DynamicResponse( response = DynamicResponse(
data={"description": long_text}, data={"description": long_text},
endpoint="/v3/test", endpoint="/mock/endpoint",
status_code=200, status_code=200,
response_time_ms=100.0, response_time_ms=100.0,
) )
@ -165,25 +164,6 @@ class TestDynamicResponse:
class TestGeoGuessrClient: class TestGeoGuessrClient:
"""Tests for GeoGuessrClient.""" """Tests for GeoGuessrClient."""
@pytest.fixture
def mock_session_manager(self):
"""Create a mock session manager."""
manager = MagicMock(spec=SessionManager)
manager.get_session = AsyncMock(
return_value=UserSession(
ncfa_cookie="test_cookie",
user_id="test-user",
username="TestUser",
email="test@example.com",
)
)
return manager
@pytest.fixture
def client(self, mock_session_manager):
"""Create a GeoGuessrClient with mocked session manager."""
return GeoGuessrClient(mock_session_manager)
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_get_authenticated_client(self, client, mock_session_manager): async def test_get_authenticated_client(self, client, mock_session_manager):
"""Test getting authenticated HTTP client.""" """Test getting authenticated HTTP client."""
@ -268,7 +248,7 @@ class TestGeoGuessrClient:
mock_auth.return_value = mock_http_client mock_auth.return_value = mock_http_client
endpoint = EndpointInfo(path="/v3/test", method="POST") endpoint = EndpointInfo(path="/mock/endpoint", method="POST")
response = await client.post(endpoint, json_data={"data": "test"}) response = await client.post(endpoint, json_data={"data": "test"})
assert response.is_success assert response.is_success
@ -309,6 +289,7 @@ class TestGeoGuessrClient:
@pytest.mark.integration @pytest.mark.integration
@pytest.mark.real_env
class TestGeoGuessrClientIntegration: class TestGeoGuessrClientIntegration:
""" """
Integration tests that would make real API calls. Integration tests that would make real API calls.
@ -318,12 +299,6 @@ class TestGeoGuessrClientIntegration:
authentication cookie. authentication cookie.
""" """
@pytest.fixture
def real_client(self):
"""Create a real client with environment authentication."""
session_manager = SessionManager()
return GeoGuessrClient(session_manager)
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_real_profile_endpoint(self, real_client): async def test_real_profile_endpoint(self, real_client):
"""Test real API call to profile endpoint.""" """Test real API call to profile endpoint."""
@ -335,11 +310,12 @@ class TestGeoGuessrClientIntegration:
response = await real_client.get(Endpoints.PROFILES.GET_PROFILE) response = await real_client.get(Endpoints.PROFILES.GET_PROFILE)
assert response.is_success assert response.is_success
assert "id" in response.available_fields or "nick" in response.available_fields assert "user" in response.available_fields or "email" in response.available_fields
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_real_stats_endpoint(self, real_client): async def test_real_stats_endpoint(self, real_client):
"""Test real API call to stats' endpoint.""" """Test real API call to stats' endpoint."""
# This test requires GEOGUESSR_NCFA_COOKIE to be set
import os import os
if not os.environ.get("GEOGUESSR_NCFA_COOKIE"): if not os.environ.get("GEOGUESSR_NCFA_COOKIE"):
pytest.skip("GEOGUESSR_NCFA_COOKIE not set") pytest.skip("GEOGUESSR_NCFA_COOKIE not set")

View file

@ -375,5 +375,5 @@ class TestRealAuthFlow:
result = await session_manager.validate_cookie(cookie) result = await session_manager.validate_cookie(cookie)
assert result is not None assert result is not None
assert "id" in result assert "user" in result
assert "nick" in result assert "email" in result