Fix integration tests via mockup
This commit is contained in:
parent
deeb2af493
commit
0236ef23d8
3 changed files with 95 additions and 52 deletions
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue