fix(tests): Remove session-scoped fixture overrides from MCP conftest

The MCP conftest.py was overriding session-scoped `server` and
`graph_cleanup` fixtures with no-op versions. Having two session-scoped
fixtures with the same name at different directory levels caused
pytest-asyncio event loop conflicts, making all oauth_test.py tests
fail with "Event loop is closed".

Since these fixtures are session-scoped and shared across the entire
test run, the override was unnecessary — the SpinTestServer is already
created for other tests.

Also adds defensive `access_token` key validation in MCP OAuth token
exchange and refresh to prevent KeyError on malformed responses.
This commit is contained in:
Zamil Majdy
2026-02-10 20:17:07 +04:00
parent 3e38b141dd
commit e934f0d0c2
2 changed files with 12 additions and 16 deletions

View File

@@ -1,13 +1,11 @@
"""
Conftest for MCP block tests.
Override the session-scoped server and graph_cleanup fixtures from
backend/conftest.py so that MCP integration tests don't spin up the
full SpinTestServer infrastructure.
Registers the e2e marker and --run-e2e CLI option so MCP end-to-end tests
(which hit real external servers) can be gated behind a flag.
"""
import pytest
import pytest_asyncio
def pytest_configure(config: pytest.Config) -> None:
@@ -29,15 +27,3 @@ def pytest_addoption(parser: pytest.Parser) -> None:
parser.addoption(
"--run-e2e", action="store_true", default=False, help="run e2e tests"
)
@pytest_asyncio.fixture(scope="session", loop_scope="session")
async def server():
"""No-op override — MCP tests don't need the full platform server."""
yield None
@pytest_asyncio.fixture(scope="session", loop_scope="session", autouse=True)
async def graph_cleanup(server):
"""No-op override — MCP tests don't create graphs."""
yield

View File

@@ -109,6 +109,11 @@ class MCPOAuthHandler(BaseOAuthHandler):
f"Token exchange failed: {tokens.get('error_description', tokens['error'])}"
)
if "access_token" not in tokens:
raise RuntimeError(
"OAuth token response missing 'access_token' field"
)
now = int(time.time())
expires_in = tokens.get("expires_in")
@@ -158,6 +163,11 @@ class MCPOAuthHandler(BaseOAuthHandler):
f"Token refresh failed: {tokens.get('error_description', tokens['error'])}"
)
if "access_token" not in tokens:
raise RuntimeError(
"OAuth refresh response missing 'access_token' field"
)
now = int(time.time())
expires_in = tokens.get("expires_in")