Replace subprocess tests with in-process async servers (#2006)

* Use anyio as testing backend

* Remove asyncio markers

* Update streamable http tests

* Replace all subprocess tests

* Replace anyio task groups with asyncio context managers in tests

- Convert run_server_async from anyio task group pattern to asyncio.create_task with async context manager
- Remove task_group fixture from conftest
- Update all test fixtures to use async with run_server_async pattern
- Remove TaskGroup imports from all test files
- Tests now work with pytest-asyncio instead of pytest-anyio

* Update test_github_provider_integration.py
This commit is contained in:
Jeremiah Lowin 2025-10-19 10:47:54 -04:00 committed by GitHub
commit 3321644ad3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
28 changed files with 411 additions and 358 deletions

View file

@ -12,7 +12,7 @@ with the following configuration:
import os
import re
from collections.abc import Generator
from collections.abc import AsyncGenerator
from urllib.parse import parse_qs, urlparse
import httpx
@ -21,7 +21,7 @@ import pytest
from fastmcp import FastMCP
from fastmcp.client import Client
from fastmcp.server.auth.providers.github import GitHubProvider
from fastmcp.utilities.tests import HeadlessOAuth, run_server_in_process
from fastmcp.utilities.tests import HeadlessOAuth, run_server_async
FASTMCP_TEST_AUTH_GITHUB_CLIENT_ID = os.getenv("FASTMCP_TEST_AUTH_GITHUB_CLIENT_ID")
FASTMCP_TEST_AUTH_GITHUB_CLIENT_SECRET = os.getenv(
@ -36,7 +36,7 @@ pytestmark = pytest.mark.xfail(
)
def create_github_server(host: str = "127.0.0.1", port: int = 9100, **kwargs) -> None:
def create_github_server(base_url: str) -> FastMCP:
"""Create FastMCP server with GitHub OAuth protection."""
assert FASTMCP_TEST_AUTH_GITHUB_CLIENT_ID is not None
assert FASTMCP_TEST_AUTH_GITHUB_CLIENT_SECRET is not None
@ -45,7 +45,7 @@ def create_github_server(host: str = "127.0.0.1", port: int = 9100, **kwargs) ->
auth = GitHubProvider(
client_id=FASTMCP_TEST_AUTH_GITHUB_CLIENT_ID,
client_secret=FASTMCP_TEST_AUTH_GITHUB_CLIENT_SECRET,
base_url=f"http://{host}:{port}",
base_url=base_url,
)
# Create FastMCP server with GitHub authentication
@ -61,13 +61,10 @@ def create_github_server(host: str = "127.0.0.1", port: int = 9100, **kwargs) ->
"""Returns user info from OAuth context."""
return "📝 GitHub OAuth user authenticated successfully"
# Run the server
server.run(host=host, port=port, **kwargs)
return server
def create_github_server_with_mock_callback(
host: str = "127.0.0.1", port: int = 9100, **kwargs
) -> None:
def create_github_server_with_mock_callback(base_url: str) -> FastMCP:
"""Create FastMCP server with GitHub OAuth that mocks the callback for testing."""
assert FASTMCP_TEST_AUTH_GITHUB_CLIENT_ID is not None
assert FASTMCP_TEST_AUTH_GITHUB_CLIENT_SECRET is not None
@ -76,7 +73,7 @@ def create_github_server_with_mock_callback(
auth = GitHubProvider(
client_id=FASTMCP_TEST_AUTH_GITHUB_CLIENT_ID,
client_secret=FASTMCP_TEST_AUTH_GITHUB_CLIENT_SECRET,
base_url=f"http://{host}:{port}",
base_url=base_url,
)
# Mock the authorize method to return a fake code instead of redirecting to GitHub
@ -159,29 +156,31 @@ def create_github_server_with_mock_callback(
"""Returns user info from OAuth context."""
return "📝 GitHub OAuth user authenticated successfully"
# Run the server
server.run(host=host, port=port, **kwargs)
return server
@pytest.fixture(scope="module")
def github_server() -> Generator[str, None, None]:
"""Start GitHub OAuth server in background process on fixed port 9100."""
with run_server_in_process(
create_github_server, transport="http", host="127.0.0.1", port=9100
) as url:
yield f"{url}/mcp"
@pytest.fixture
async def github_server() -> AsyncGenerator[str, None]:
"""Start GitHub OAuth server on a random available port."""
from fastmcp.utilities.http import find_available_port
port = find_available_port()
base_url = f"http://127.0.0.1:{port}"
server = create_github_server(base_url)
async with run_server_async(server, port=port, transport="http") as url:
yield url
@pytest.fixture(scope="module")
def github_server_with_mock() -> Generator[str, None, None]:
"""Start GitHub OAuth server with mocked callback in background process on port 9101."""
with run_server_in_process(
create_github_server_with_mock_callback,
transport="http",
host="127.0.0.1",
port=9101,
) as url:
yield f"{url}/mcp"
@pytest.fixture
async def github_server_with_mock() -> AsyncGenerator[str, None]:
"""Start GitHub OAuth server with mocked callback on a random available port."""
from fastmcp.utilities.http import find_available_port
port = find_available_port()
base_url = f"http://127.0.0.1:{port}"
server = create_github_server_with_mock_callback(base_url)
async with run_server_async(server, port=port, transport="http") as url:
yield url
@pytest.fixture