115 lines
4.0 KiB
Python
115 lines
4.0 KiB
Python
|
|
"""Tests for auth configuration validation and startup routes."""
|
||
|
|
|
||
|
|
import json
|
||
|
|
import sys
|
||
|
|
from unittest.mock import MagicMock
|
||
|
|
|
||
|
|
import pytest
|
||
|
|
|
||
|
|
from core.config import config
|
||
|
|
from starlette.requests import Request
|
||
|
|
from starlette.responses import JSONResponse
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.fixture(autouse=True)
|
||
|
|
def _restore_config(monkeypatch):
|
||
|
|
"""Prevent main() side effects on the global config from leaking to other tests."""
|
||
|
|
monkeypatch.setattr(config, "http_remote_hosted", config.http_remote_hosted)
|
||
|
|
monkeypatch.setattr(config, "api_key_validation_url", config.api_key_validation_url)
|
||
|
|
monkeypatch.setattr(config, "api_key_login_url", config.api_key_login_url)
|
||
|
|
monkeypatch.setattr(config, "api_key_cache_ttl", config.api_key_cache_ttl)
|
||
|
|
monkeypatch.setattr(config, "api_key_service_token_header", config.api_key_service_token_header)
|
||
|
|
monkeypatch.setattr(config, "api_key_service_token", config.api_key_service_token)
|
||
|
|
|
||
|
|
|
||
|
|
class TestStartupConfigValidation:
|
||
|
|
def test_remote_hosted_flag_without_validation_url_exits(self, monkeypatch):
|
||
|
|
"""--http-remote-hosted without --api-key-validation-url should SystemExit(1)."""
|
||
|
|
monkeypatch.setattr(
|
||
|
|
sys,
|
||
|
|
"argv",
|
||
|
|
[
|
||
|
|
"main",
|
||
|
|
"--transport", "http",
|
||
|
|
"--http-remote-hosted",
|
||
|
|
# Deliberately omit --api-key-validation-url
|
||
|
|
],
|
||
|
|
)
|
||
|
|
monkeypatch.delenv("UNITY_MCP_API_KEY_VALIDATION_URL", raising=False)
|
||
|
|
monkeypatch.delenv("UNITY_MCP_HTTP_REMOTE_HOSTED", raising=False)
|
||
|
|
|
||
|
|
from main import main
|
||
|
|
|
||
|
|
with pytest.raises(SystemExit) as exc_info:
|
||
|
|
main()
|
||
|
|
|
||
|
|
assert exc_info.value.code == 1
|
||
|
|
|
||
|
|
def test_remote_hosted_env_var_without_validation_url_exits(self, monkeypatch):
|
||
|
|
"""UNITY_MCP_HTTP_REMOTE_HOSTED=true without validation URL should SystemExit(1)."""
|
||
|
|
monkeypatch.setattr(
|
||
|
|
sys,
|
||
|
|
"argv",
|
||
|
|
[
|
||
|
|
"main",
|
||
|
|
"--transport", "http",
|
||
|
|
# No --http-remote-hosted flag
|
||
|
|
],
|
||
|
|
)
|
||
|
|
monkeypatch.setenv("UNITY_MCP_HTTP_REMOTE_HOSTED", "true")
|
||
|
|
monkeypatch.delenv("UNITY_MCP_API_KEY_VALIDATION_URL", raising=False)
|
||
|
|
|
||
|
|
from main import main
|
||
|
|
|
||
|
|
with pytest.raises(SystemExit) as exc_info:
|
||
|
|
main()
|
||
|
|
|
||
|
|
assert exc_info.value.code == 1
|
||
|
|
|
||
|
|
|
||
|
|
class TestLoginUrlEndpoint:
|
||
|
|
"""Test the /api/auth/login-url route handler logic.
|
||
|
|
|
||
|
|
These tests replicate the handler inline to avoid full MCP server construction.
|
||
|
|
The logic mirrors main.py's auth_login_url route exactly.
|
||
|
|
"""
|
||
|
|
|
||
|
|
@staticmethod
|
||
|
|
async def _auth_login_url(_request):
|
||
|
|
"""Replicate the route handler from main.py."""
|
||
|
|
if not config.api_key_login_url:
|
||
|
|
return JSONResponse(
|
||
|
|
{
|
||
|
|
"success": False,
|
||
|
|
"error": "API key management not configured. Contact your server administrator.",
|
||
|
|
},
|
||
|
|
status_code=404,
|
||
|
|
)
|
||
|
|
return JSONResponse({
|
||
|
|
"success": True,
|
||
|
|
"login_url": config.api_key_login_url,
|
||
|
|
})
|
||
|
|
|
||
|
|
@pytest.mark.asyncio
|
||
|
|
async def test_login_url_returns_url_when_configured(self, monkeypatch):
|
||
|
|
monkeypatch.setattr(config, "api_key_login_url",
|
||
|
|
"https://app.example.com/keys")
|
||
|
|
|
||
|
|
response = await self._auth_login_url(MagicMock(spec=Request))
|
||
|
|
|
||
|
|
assert response.status_code == 200
|
||
|
|
body = json.loads(response.body.decode())
|
||
|
|
assert body["success"] is True
|
||
|
|
assert body["login_url"] == "https://app.example.com/keys"
|
||
|
|
|
||
|
|
@pytest.mark.asyncio
|
||
|
|
async def test_login_url_returns_404_when_not_configured(self, monkeypatch):
|
||
|
|
monkeypatch.setattr(config, "api_key_login_url", None)
|
||
|
|
|
||
|
|
response = await self._auth_login_url(MagicMock(spec=Request))
|
||
|
|
|
||
|
|
assert response.status_code == 404
|
||
|
|
body = json.loads(response.body.decode())
|
||
|
|
assert body["success"] is False
|
||
|
|
assert "not configured" in body["error"]
|