From 7067c5fff1eed1580e8e5891b1c53ae0987f0a2b Mon Sep 17 00:00:00 2001 From: Chris Coutinho Date: Tue, 16 Jun 2026 02:10:54 +0200 Subject: [PATCH] test(vector-sync): close round-8 coverage gaps (500 path, non-string list) - route test for purge_doc_types raising on total failure -> 500 - route test for doc_types list containing non-strings -> 400 - reword the capabilities move_to_end comment (no-op on new keys; needed only for the expired-key in-place update) Co-Authored-By: Claude Opus 4.8 (1M context) --- nextcloud_mcp_server/capabilities.py | 5 ++-- tests/unit/test_vector_sync_purge_route.py | 29 ++++++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/nextcloud_mcp_server/capabilities.py b/nextcloud_mcp_server/capabilities.py index 5f7c7256..40fc75c7 100644 --- a/nextcloud_mcp_server/capabilities.py +++ b/nextcloud_mcp_server/capabilities.py @@ -100,8 +100,9 @@ async def allowed_doc_types( result = _parse_enabled_doc_types(payload) _cache[user_id] = (now, result) - # New key: __setitem__ already appends (no-op). Existing expired key: the - # update keeps its old position, so move it to the end to preserve LRU order. + # Needed only for an existing (expired) key: __setitem__ updates it in place, + # keeping its old position, so move it to the end to preserve LRU order. For + # a brand-new key __setitem__ already appends, so this is a harmless no-op. _cache.move_to_end(user_id) while len(_cache) > _CACHE_MAXSIZE: _cache.popitem(last=False) # evict least-recently-used diff --git a/tests/unit/test_vector_sync_purge_route.py b/tests/unit/test_vector_sync_purge_route.py index 77857c55..37d5cdbb 100644 --- a/tests/unit/test_vector_sync_purge_route.py +++ b/tests/unit/test_vector_sync_purge_route.py @@ -98,6 +98,35 @@ def test_bad_request_when_doc_types_not_list(mocker): purge.assert_not_called() +def test_bad_request_when_doc_types_has_non_string(mocker): + # Covers the all(isinstance(d, str)) branch (a list with non-string items). + _patch_token(mocker) + purge = _patch_purge(mocker) + + client = TestClient(_build_app()) + resp = client.post("/api/v1/vector-sync/purge", json={"doc_types": [1, 2]}) + + assert resp.status_code == 400 + purge.assert_not_called() + + +def test_total_failure_returns_500(mocker): + # purge_doc_types raising (total failure) hits the route's except -> 500. + _patch_token(mocker, "admin") + _patch_basic_auth(mocker, "admin") + _patch_outbound_client(mocker) + _patch_groups(mocker, ["admin"]) + mocker.patch( + "nextcloud_mcp_server.api.vector_sync.purge_doc_types", + new=AsyncMock(side_effect=RuntimeError("qdrant down")), + ) + + client = TestClient(_build_app()) + resp = client.post("/api/v1/vector-sync/purge", json={"doc_types": ["file"]}) + + assert resp.status_code == 500 + + def test_forbidden_when_not_admin(mocker): _patch_token(mocker, "bob") _patch_basic_auth(mocker, "bob")