`tests/server/login_flow/test_management_api.py` had `[pytest.mark.integration, pytest.mark.oauth]` while every other test in `tests/server/login_flow/` uses `[pytest.mark.integration, pytest.mark.login_flow]`. The single-user CI matrix filter is `(integration and not keycloak and not login_flow and not multi_user_basic)`, so the missing `login_flow` mark let this test collect and run under single-user mode against `localhost:8004` (which isn't up there, hitting the bug being reported), even though it's specifically driving the login-flow MCP server. Also `oauth` isn't a registered marker (see `[tool.pytest.ini_options]` in pyproject.toml), so it was emitting an unregistered-marker warning. Replacing the marker aligns this file with its siblings: single-user / multi-user-basic / keycloak filters all deselect it now, and the login-flow filter still picks it up. Verified: `pytest --collect-only -m "<single-user filter>"` reports 2 deselected; `-m login_flow` collects both tests.
53 lines
2.0 KiB
Python
53 lines
2.0 KiB
Python
"""Integration tests for the management API on the login-flow MCP server.
|
|
|
|
These tests drive a real OAuth flow against Nextcloud's `oidc` app using the
|
|
static `nextcloudMcpServerUIPublicClient` client (which is allowlisted on the
|
|
`mcp-login-flow` container via `ALLOWED_MGMT_CLIENT`), then hit the
|
|
management API endpoints with the resulting bearer token.
|
|
|
|
Regression coverage for the bug where /api/v1/apps proxied to OCS v1
|
|
/cloud/apps and always 401'd. The handler now uses /ocs/v2.php/cloud/capabilities,
|
|
which is reachable for OAuth bearer tokens.
|
|
"""
|
|
|
|
import httpx
|
|
import pytest
|
|
|
|
LOGIN_FLOW_API_BASE_URL = "http://localhost:8004"
|
|
|
|
pytestmark = [pytest.mark.integration, pytest.mark.login_flow]
|
|
|
|
|
|
async def test_get_installed_apps_returns_capability_keys(
|
|
login_flow_static_client_token: str,
|
|
):
|
|
"""GET /api/v1/apps returns 200 with a list of enabled-app capability keys."""
|
|
async with httpx.AsyncClient(timeout=30.0) as client:
|
|
response = await client.get(
|
|
f"{LOGIN_FLOW_API_BASE_URL}/api/v1/apps",
|
|
headers={"Authorization": f"Bearer {login_flow_static_client_token}"},
|
|
)
|
|
|
|
assert response.status_code == 200, (
|
|
f"/api/v1/apps returned {response.status_code}: {response.text}"
|
|
)
|
|
|
|
data = response.json()
|
|
assert "apps" in data
|
|
assert isinstance(data["apps"], list)
|
|
|
|
# Anonymous capabilities always exposes core; authenticated also exposes
|
|
# files. Both should be present whether or not the oidc app's
|
|
# BearerAuthMiddleware ran for this OCS route.
|
|
apps = data["apps"]
|
|
assert "core" in apps, f"expected 'core' in apps, got {apps}"
|
|
assert "files" in apps, f"expected 'files' in apps, got {apps}"
|
|
|
|
|
|
async def test_get_installed_apps_requires_bearer_token():
|
|
"""No Authorization header → 401 (handler's token validator rejects it)."""
|
|
async with httpx.AsyncClient(timeout=30.0) as client:
|
|
response = await client.get(f"{LOGIN_FLOW_API_BASE_URL}/api/v1/apps")
|
|
|
|
assert response.status_code == 401
|