test(12-05): fix test_nextcloud_connect_persists + compose migration test path
- test_nextcloud_connect_persists: provider=nextcloud routes to NextcloudBackend (not WebDAVBackend) — add storage.nextcloud_backend.validate_cloud_url patch and use AsyncMock for asyncio.to_thread (plain return_value=True is not awaitable, swallowed by except → False). Test now passes HTTP 201. - test_compose_migrations: skip module when docker-compose.yml is not found at the expected repo-root path (file is not mounted inside the backend container). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
043a7817e2
commit
206f564248
@@ -292,6 +292,42 @@ async def test_oauth_callback_invalid_state(async_client, db_session, monkeypatc
|
||||
app.state.redis = None
|
||||
|
||||
|
||||
async def test_nextcloud_connect_persists(async_client, db_session):
|
||||
"""POST /api/cloud/connections/webdav with provider=nextcloud creates a connection.
|
||||
|
||||
Regression for Phase 12 UAT blocker: POST /api/cloud/connections/webdav failed with
|
||||
UndefinedColumn (display_name_override) when the DB was at revision 0005.
|
||||
Uses unittest.mock.patch to stub SSRF validation and health probe at sys.modules level.
|
||||
"""
|
||||
from unittest.mock import patch, AsyncMock
|
||||
|
||||
auth = await _create_user_and_token(db_session, role="user")
|
||||
|
||||
# provider=nextcloud routes to NextcloudBackend (not WebDAVBackend) in the
|
||||
# cloud_backend_factory — patch validate_cloud_url in all namespaces that hold
|
||||
# a from-import binding. asyncio.to_thread is accessed as a module attribute
|
||||
# in both backends, so a single AsyncMock covers both.
|
||||
with patch("api.cloud.connections.validate_cloud_url", return_value=None), \
|
||||
patch("storage.webdav_backend.validate_cloud_url", return_value=None), \
|
||||
patch("storage.nextcloud_backend.validate_cloud_url", return_value=None), \
|
||||
patch("asyncio.to_thread", new_callable=AsyncMock, return_value=True):
|
||||
resp = await async_client.post(
|
||||
"/api/cloud/connections/webdav",
|
||||
json={
|
||||
"server_url": "https://nc.example.com/remote.php/dav",
|
||||
"username": "testuser",
|
||||
"password": "testpass",
|
||||
"provider": "nextcloud",
|
||||
},
|
||||
headers=auth["headers"],
|
||||
)
|
||||
|
||||
assert resp.status_code == 201, f"Unexpected: {resp.status_code} — {resp.text}"
|
||||
data = resp.json()
|
||||
assert data["provider"] == "nextcloud"
|
||||
assert "credentials_enc" not in data
|
||||
|
||||
|
||||
async def test_webdav_connect_validates(async_client, db_session, monkeypatch):
|
||||
"""POST /api/cloud/connections/webdav with localhost URL returns 422 (SSRF blocked)."""
|
||||
auth = await _create_user_and_token(db_session, role="user")
|
||||
|
||||
@@ -21,6 +21,15 @@ import yaml
|
||||
REPO_ROOT = pathlib.Path(__file__).resolve().parents[2]
|
||||
COMPOSE_PATH = REPO_ROOT / "docker-compose.yml"
|
||||
|
||||
# When running inside the Docker container the repo root is not mounted;
|
||||
# skip the whole module rather than erroring with FileNotFoundError.
|
||||
if not COMPOSE_PATH.exists():
|
||||
pytest.skip(
|
||||
f"docker-compose.yml not found at {COMPOSE_PATH} — "
|
||||
"these static analysis tests must run from the host repo root, not inside a container.",
|
||||
allow_module_level=True,
|
||||
)
|
||||
|
||||
APPLICATION_SERVICES = {"backend", "celery-worker", "celery-beat"}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user