"""Tests for _resolve_user_id_from_request in unity_transport.py.""" import sys import types from unittest.mock import AsyncMock import pytest from core.config import config from services.api_key_service import ApiKeyService, ValidationResult @pytest.fixture(autouse=True) def _reset_api_key_singleton(): ApiKeyService._instance = None yield ApiKeyService._instance = None class TestResolveUserIdFromRequest: @pytest.mark.asyncio async def test_returns_none_when_not_remote_hosted(self, monkeypatch): monkeypatch.setattr(config, "http_remote_hosted", False) from transport.unity_transport import _resolve_user_id_from_request result = await _resolve_user_id_from_request() assert result is None @pytest.mark.asyncio async def test_returns_none_when_service_not_initialized(self, monkeypatch): monkeypatch.setattr(config, "http_remote_hosted", True) # ApiKeyService._instance is None (from fixture) from transport.unity_transport import _resolve_user_id_from_request result = await _resolve_user_id_from_request() assert result is None @pytest.mark.asyncio async def test_returns_user_id_for_valid_key(self, monkeypatch): monkeypatch.setattr(config, "http_remote_hosted", True) svc = ApiKeyService(validation_url="https://auth.example.com/validate") svc.validate = AsyncMock( return_value=ValidationResult(valid=True, user_id="user-123") ) # Stub the fastmcp dependency that provides HTTP headers deps_mod = types.ModuleType("fastmcp.server.dependencies") deps_mod.get_http_headers = lambda include_all=False: { "x-api-key": "sk-valid"} monkeypatch.setitem( sys.modules, "fastmcp.server.dependencies", deps_mod) from transport.unity_transport import _resolve_user_id_from_request result = await _resolve_user_id_from_request() assert result == "user-123" svc.validate.assert_called_once_with("sk-valid") @pytest.mark.asyncio async def test_returns_none_for_invalid_key(self, monkeypatch): monkeypatch.setattr(config, "http_remote_hosted", True) svc = ApiKeyService(validation_url="https://auth.example.com/validate") svc.validate = AsyncMock( return_value=ValidationResult(valid=False, error="bad key") ) deps_mod = types.ModuleType("fastmcp.server.dependencies") deps_mod.get_http_headers = lambda include_all=False: { "x-api-key": "sk-bad"} monkeypatch.setitem( sys.modules, "fastmcp.server.dependencies", deps_mod) from transport.unity_transport import _resolve_user_id_from_request result = await _resolve_user_id_from_request() assert result is None @pytest.mark.asyncio async def test_returns_none_on_exception(self, monkeypatch): monkeypatch.setattr(config, "http_remote_hosted", True) svc = ApiKeyService(validation_url="https://auth.example.com/validate") svc.validate = AsyncMock(side_effect=RuntimeError("boom")) deps_mod = types.ModuleType("fastmcp.server.dependencies") deps_mod.get_http_headers = lambda include_all=False: { "x-api-key": "sk-err"} monkeypatch.setitem( sys.modules, "fastmcp.server.dependencies", deps_mod) from transport.unity_transport import _resolve_user_id_from_request result = await _resolve_user_id_from_request() assert result is None @pytest.mark.asyncio async def test_returns_none_when_no_api_key_header(self, monkeypatch): monkeypatch.setattr(config, "http_remote_hosted", True) ApiKeyService(validation_url="https://auth.example.com/validate") deps_mod = types.ModuleType("fastmcp.server.dependencies") deps_mod.get_http_headers = lambda include_all=False: {} # No x-api-key monkeypatch.setitem( sys.modules, "fastmcp.server.dependencies", deps_mod) from transport.unity_transport import _resolve_user_id_from_request result = await _resolve_user_id_from_request() assert result is None