test: add MCP smoke tests over stdio and streamable HTTP, from source and from the built image
ci / gitleaks (push) Successful in 9s
ci / docs-check (push) Failing after 30s
ci / lint (push) Successful in 41s
ci / test-integration (push) Successful in 46s
ci / security (push) Failing after 28s
ci / test-mcp (push) Successful in 1m16s
ci / test-unit (push) Successful in 1m52s
ci / build-and-push (push) Successful in 17s

This commit is contained in:
Latte committed 2026-10-14 16:26:16 +02:00
1 parent cfbf1fb893
commit 5e144772b2
7 files changed
+817

No files matched your search

+76
View File
@@ -0,0 +1,76 @@
"""Opt-in fixtures for the MCP smoke tests.
Tests in this directory are marked ``mcp_smoke`` and skipped unless
``AEGIS_INTEGRATION=1``. They reuse the live-Gitea harness from
``tests/integration`` (one disposable Gitea per session, admin token with the
``all`` scope) and drive the server through a real MCP client over stdio and
streamable HTTP, from source and (when ``AEGIS_MCP_IMAGE`` is set) from the
built image.
"""
from __future__ import annotations
import os
import secrets
from pathlib import Path
import pytest
from tests.integration.conftest import ENABLE_ENV, gitea, integration_enabled
from tests.integration.harness import GITEA_PORT, GiteaInstance
__all__ = ["ENABLE_ENV", "gitea"]
_HERE = Path(__file__).parent.resolve()
IMAGE_ENV = "AEGIS_MCP_IMAGE"
def pytest_configure(config: pytest.Config) -> None:
"""Register the ``mcp_smoke`` marker (idempotent with pyproject)."""
config.addinivalue_line(
"markers", "mcp_smoke: MCP client smoke tests, opt-in via AEGIS_INTEGRATION=1"
)
def _is_mcp_smoke(item: pytest.Item) -> bool:
try:
return _HERE in Path(str(item.path)).resolve().parents
except (OSError, ValueError): # pragma: no cover - defensive
return False
def pytest_collection_modifyitems(config: pytest.Config, items: list[pytest.Item]) -> None:
"""Mark and (unless opted in) skip every test under tests/mcp."""
selected = [item for item in items if _is_mcp_smoke(item)]
skip = pytest.mark.skip(reason=f"MCP smoke tests need {ENABLE_ENV}=1 and Docker")
for item in selected:
item.add_marker(pytest.mark.mcp_smoke)
if not integration_enabled():
item.add_marker(skip)
if selected and len(selected) == len(items):
# A smoke-only run starts the server in subprocesses, so the in-process
# coverage gate does not apply.
for namespace in (config.option, config.known_args_namespace):
if getattr(namespace, "cov_fail_under", None) is not None:
namespace.cov_fail_under = 0
@pytest.fixture(scope="session")
def gitea_internal_url(gitea: GiteaInstance) -> str:
"""URL of the Gitea container for other containers on the harness network."""
return f"http://{gitea.container}:{GITEA_PORT}"
@pytest.fixture(scope="session")
def mcp_image() -> str:
"""The built image under test; the test is skipped when ``AEGIS_MCP_IMAGE`` is unset."""
image = os.environ.get(IMAGE_ENV, "").strip()
if not image:
pytest.skip(f"{IMAGE_ENV} is not set; image smoke tests need a built image")
return image
@pytest.fixture
def bearer_token() -> str:
"""A random 48 character MCP bearer token."""
return secrets.token_urlsafe(36)