diff --git a/tests/test_resource_limits.py b/tests/test_resource_limits.py index d577797c57..a55ecaccd1 100644 --- a/tests/test_resource_limits.py +++ b/tests/test_resource_limits.py @@ -2,6 +2,10 @@ from __future__ import annotations +from pathlib import Path +import subprocess +import sys +import textwrap from types import SimpleNamespace import pytest @@ -53,6 +57,19 @@ def test_default_is_clamped_to_hard_limit(monkeypatch): assert fake_resource.limits == (1024, 1024) +def test_finite_soft_limit_raises_when_hard_limit_is_infinite(monkeypatch): + fake_resource = _FakeResource(soft=256, hard=_FakeResource.RLIM_INFINITY) + monkeypatch.setattr(resource_limits, "_resource", fake_resource) + + assert resource_limits.apply_nofile_soft_limit({}) is True + assert fake_resource.set_calls == [ + ( + fake_resource.RLIMIT_NOFILE, + (4096, fake_resource.RLIM_INFINITY), + ), + ] + + def test_never_lowers_an_already_higher_soft_limit(monkeypatch): fake_resource = _FakeResource(soft=8192, hard=16384) monkeypatch.setattr(resource_limits, "_resource", fake_resource) @@ -81,6 +98,36 @@ def test_unsupported_platform_is_a_safe_noop(monkeypatch): assert resource_limits.apply_nofile_soft_limit({}) is False +def test_fresh_process_import_without_posix_resource_is_a_safe_noop(): + code = textwrap.dedent( + """ + import importlib.util + import pathlib + import sys + + sys.modules["resource"] = None + module_path = pathlib.Path(sys.argv[1]) + spec = importlib.util.spec_from_file_location( + "hermes_cli._resource_limits_without_posix_resource", + module_path, + ) + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + + assert module._resource is None + assert module.apply_nofile_soft_limit({}) is False + """ + ) + + subprocess.run( + [sys.executable, "-c", code, resource_limits.__file__], + check=True, + cwd=Path(resource_limits.__file__).resolve().parents[1], + capture_output=True, + text=True, + ) + + @pytest.mark.parametrize("invalid", [True, -1, 4096.0, "4096", object()]) def test_invalid_values_are_safe_noops(monkeypatch, invalid): fake_resource = _FakeResource(soft=256, hard=4096) @@ -104,6 +151,18 @@ def test_setrlimit_denial_is_a_safe_noop(monkeypatch): assert fake_resource.limits == (256, 4096) +def test_getrlimit_failure_is_a_safe_noop(monkeypatch): + class _BrokenResource(_FakeResource): + def getrlimit(self, resource: int) -> tuple[int, int]: + raise OSError("simulated getrlimit failure") + + fake_resource = _BrokenResource(soft=256, hard=4096) + monkeypatch.setattr(resource_limits, "_resource", fake_resource) + + assert resource_limits.apply_nofile_soft_limit({}) is False + assert fake_resource.set_calls == [] + + def test_never_lowers_an_unlimited_soft_limit(monkeypatch): fake_resource = _FakeResource(soft=-1, hard=-1) fake_resource.RLIM_INFINITY = -1