Merge pull request #878 from cbcoutinho/fix/windows-resource-import-877

fix(documents): guard Unix-only resource import for Windows (#877)
This commit is contained in:
Chris Coutinho
2026-06-08 16:22:42 +02:00
committed by GitHub
6 changed files with 113 additions and 8 deletions
+51 -1
View File
@@ -13,7 +13,7 @@ check on the sample PDFs, not here (unit tests must not spawn the heavy worker
or depend on the sample files).
"""
import resource
import sys
import anyio
import anyio.to_process
@@ -27,8 +27,20 @@ from nextcloud_mcp_server.document_processors._isolation import (
run_isolated_pdf_parse,
)
# ``resource`` is a Unix-only stdlib module (absent on Windows, #877). Guard the
# import so this test module stays importable on Windows; the rlimit-computation
# tests below are skipped there via the ``requires_resource`` marker.
try:
import resource
except ImportError: # pragma: no cover - only reached on Windows
resource = None # type: ignore[assignment]
pytestmark = pytest.mark.unit
requires_resource = pytest.mark.skipif(
resource is None, reason="resource module is Unix-only (absent on Windows)"
)
def _tiny_pdf() -> bytes:
doc = pymupdf.open()
@@ -111,6 +123,7 @@ async def test_timeout_kills_and_classifies_as_timeout(monkeypatch):
# --- _apply_mem_limit computation (mocked; never applied to the test proc) ---
@requires_resource
def test_apply_mem_limit_caps_soft_below_finite_hard(monkeypatch):
captured = {}
monkeypatch.setattr(_isolation, "_MEM_LIMIT_APPLIED", False)
@@ -129,6 +142,7 @@ def test_apply_mem_limit_caps_soft_below_finite_hard(monkeypatch):
assert hard == 4 * 1024**3
@requires_resource
def test_apply_mem_limit_uses_target_when_hard_unlimited(monkeypatch):
captured = {}
monkeypatch.setattr(_isolation, "_MEM_LIMIT_APPLIED", False)
@@ -147,6 +161,7 @@ def test_apply_mem_limit_uses_target_when_hard_unlimited(monkeypatch):
assert hard == resource.RLIM_INFINITY
@requires_resource
def test_apply_mem_limit_is_applied_once(monkeypatch):
calls = []
monkeypatch.setattr(_isolation, "_MEM_LIMIT_APPLIED", False)
@@ -161,6 +176,41 @@ def test_apply_mem_limit_is_applied_once(monkeypatch):
assert len(calls) == 1 # second call is a no-op
# --- Windows / no-``resource`` platform compatibility (#877) -----------------
def test_apply_mem_limit_noop_when_resource_unavailable(monkeypatch):
"""On a platform without ``resource`` (e.g. Windows) the cap is skipped.
Regression for #877: ``resource`` is Unix-only, so ``_apply_mem_limit`` must
degrade to a no-op (rather than crash) when the module is unavailable.
"""
monkeypatch.setattr(_isolation, "_MEM_LIMIT_APPLIED", False)
monkeypatch.setattr(_isolation, "resource", None)
_isolation._apply_mem_limit(1536) # must not raise
assert _isolation._MEM_LIMIT_APPLIED is True
def test_isolation_imports_on_windows_without_resource(monkeypatch):
"""Importing ``_isolation`` on Windows must not crash on ``import resource``.
Regression for #877: a module-scope ``import resource`` raised
``ModuleNotFoundError`` on Windows and took down server startup. With
``sys.platform == 'win32'`` the module must import cleanly and bind
``resource`` to ``None``.
"""
import importlib
monkeypatch.setattr(sys, "platform", "win32")
monkeypatch.delitem(
sys.modules,
"nextcloud_mcp_server.document_processors._isolation",
raising=False,
)
mod = importlib.import_module("nextcloud_mcp_server.document_processors._isolation")
assert mod.resource is None
# --- PyMuPDF processor wiring ------------------------------------------------