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
77 lines
2.7 KiB
Python
77 lines
2.7 KiB
Python
"""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)
|