test(webdav): pin encode-once contract + nit cleanups (#891 r3)

Round-3 review on PR #891 (no blockers):
- Add test_encode_dav_path_encodes_exactly_once pinning the documented
  decoded-input precondition ("already%20encoded.pdf" -> "already%2520...").
- format_exception_group: proper singular/plural ("1 sub-exception" vs
  "N sub-exceptions") instead of "(s)".
- oauth_sync: use `if doc_task is not None:` to match processor_task's guard.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Chris Coutinho
2026-06-11 06:21:36 +02:00
co-authored by Claude Opus 4.8
parent 7b274cd8e2
commit 801bf108fa
4 changed files with 14 additions and 4 deletions
+2 -1
View File
@@ -21,7 +21,8 @@ def format_exception_group(exc: BaseException) -> str:
if not isinstance(exc, BaseExceptionGroup): if not isinstance(exc, BaseExceptionGroup):
return repr(exc) return repr(exc)
leaves = _flatten(exc) leaves = _flatten(exc)
return f"{len(leaves)} sub-exception(s): " + "; ".join(repr(e) for e in leaves) noun = "sub-exception" if len(leaves) == 1 else "sub-exceptions"
return f"{len(leaves)} {noun}: " + "; ".join(repr(e) for e in leaves)
def _flatten(exc: BaseException) -> list[BaseException]: def _flatten(exc: BaseException) -> list[BaseException]:
+2 -2
View File
@@ -332,7 +332,7 @@ async def multi_user_processor_task(
break break
except NotProvisionedError: except NotProvisionedError:
if doc_task: if doc_task is not None:
logger.warning( logger.warning(
"[BasicAuth] User %s not provisioned, skipping %s_%s", "[BasicAuth] User %s not provisioned, skipping %s_%s",
doc_task.user_id, doc_task.user_id,
@@ -342,7 +342,7 @@ async def multi_user_processor_task(
continue continue
except Exception as e: except Exception as e:
if doc_task: if doc_task is not None:
logger.error( logger.error(
"[BasicAuth] Processor %s error processing %s_%s: %s", "[BasicAuth] Processor %s error processing %s_%s: %s",
worker_id, worker_id,
+9
View File
@@ -540,6 +540,15 @@ def test_webdav_path_encoding(path, expected):
assert client._webdav_path(path) == expected assert client._webdav_path(path) == expected
@pytest.mark.unit
def test_encode_dav_path_encodes_exactly_once():
"""Pins the decoded-input precondition: a literal '%' becomes '%25', so an
already-encoded path passed in error would double-encode (caught here)."""
from nextcloud_mcp_server.client.webdav import _encode_dav_path
assert _encode_dav_path("already%20encoded.pdf") == "already%2520encoded.pdf"
@pytest.mark.unit @pytest.mark.unit
async def test_read_file_encodes_special_chars(mocker): async def test_read_file_encodes_special_chars(mocker):
"""read_file must percent-encode '#', commas, and spaces in the path (card 309). """read_file must percent-encode '#', commas, and spaces in the path (card 309).
+1 -1
View File
@@ -41,4 +41,4 @@ def test_format_nested_exception_group_flattens_all_leaves():
assert "ValueError" in formatted assert "ValueError" in formatted
assert "ConnectError" in formatted assert "ConnectError" in formatted
assert "RuntimeError" in formatted assert "RuntimeError" in formatted
assert "3 sub-exception(s)" in formatted assert "3 sub-exceptions" in formatted