-
Notifications
You must be signed in to change notification settings - Fork 351
Expand file tree
/
Copy pathtest_cross_platform_locks.py
More file actions
81 lines (63 loc) · 2.91 KB
/
Copy pathtest_cross_platform_locks.py
File metadata and controls
81 lines (63 loc) · 2.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
"""Cross-platform behaviour for openkb.locks / openkb.config.
The locking layer (#86) originally hard-imported ``fcntl`` and called
``os.fchmod`` / directory ``os.fsync`` unconditionally — all Unix-only — which
crashed OpenKB at import time on Windows (``ModuleNotFoundError: No module
named 'fcntl'``, reported in VectifyAI/OpenKB#93). These tests pin the
platform-neutral behaviour and simulate the Windows path on this host.
"""
from __future__ import annotations
import os
import subprocess
import sys
import types
import pytest
from openkb import locks
def test_config_and_locks_import_without_fcntl():
"""openkb.config / openkb.locks must import on a host without fcntl (Windows)."""
code = (
"import sys\n"
"sys.modules['fcntl'] = None\n" # make `import fcntl` raise ImportError
"import openkb.locks, openkb.config\n"
"assert openkb.locks.fcntl is None\n"
"print('OK')\n"
)
result = subprocess.run(
[sys.executable, "-c", code], capture_output=True, text=True
)
assert result.returncode == 0, result.stderr
assert "OK" in result.stdout
def test_flock_funlock_roundtrip(tmp_path):
"""flock/funlock acquire and release an advisory lock on the real platform."""
lock_path = tmp_path / "test.lock"
with lock_path.open("a+", encoding="utf-8") as fh:
locks.flock(fh, exclusive=True)
locks.funlock(fh) # must not raise
def test_flock_uses_msvcrt_when_fcntl_absent(monkeypatch, tmp_path):
"""When fcntl is unavailable (Windows), locking is delegated to msvcrt."""
calls = []
fake_msvcrt = types.SimpleNamespace(
LK_LOCK=1, LK_NBLCK=2, LK_UNLCK=0,
locking=lambda fd, mode, nbytes: calls.append((mode, nbytes)),
)
monkeypatch.setattr(locks, "fcntl", None)
monkeypatch.setitem(sys.modules, "msvcrt", fake_msvcrt)
lock_path = tmp_path / "test.lock"
with lock_path.open("a+", encoding="utf-8") as fh:
locks.flock(fh, exclusive=True)
locks.funlock(fh)
modes = [mode for mode, _ in calls]
assert fake_msvcrt.LK_NBLCK in modes # acquire used the non-blocking lock
assert fake_msvcrt.LK_UNLCK in modes # release unlocked
def test_atomic_write_bytes_without_fchmod(monkeypatch, tmp_path):
"""atomic_write_bytes must still work where os.fchmod is missing (Windows)."""
monkeypatch.delattr(os, "fchmod", raising=False)
target = tmp_path / "data.bin"
locks.atomic_write_bytes(target, b"hello")
assert target.read_bytes() == b"hello"
def test_fsync_directory_skipped_on_windows(monkeypatch, tmp_path):
"""Directory fsync (unsupported on Windows) must be skipped, not attempted."""
monkeypatch.setattr(os, "name", "nt")
def _no_open(*args, **kwargs):
raise AssertionError("os.open must not be called for dir fsync on Windows")
monkeypatch.setattr(os, "open", _no_open)
locks._fsync_directory(tmp_path) # must return without touching os.open