Skip to content

Commit 66a428e

Browse files
authored
Increase test coverage (#434)
1 parent 0dfc86e commit 66a428e

File tree

2 files changed

+112
-1
lines changed

2 files changed

+112
-1
lines changed

tests/test_async_filelock.py

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,3 +179,92 @@ async def _release(self) -> None: # type: ignore[override]
179179
await lock.release()
180180
assert acquired
181181
assert released
182+
183+
184+
@pytest.mark.parametrize("lock_type", [AsyncFileLock, AsyncSoftFileLock])
185+
@pytest.mark.asyncio
186+
async def test_wait_message_logged(
187+
lock_type: type[BaseAsyncFileLock], tmp_path: Path, caplog: pytest.LogCaptureFixture
188+
) -> None:
189+
caplog.set_level(logging.DEBUG)
190+
lock_path = tmp_path / "a"
191+
first_lock = lock_type(str(lock_path))
192+
second_lock = lock_type(str(lock_path), timeout=0.2)
193+
194+
# Hold the lock so second_lock has to wait
195+
await first_lock.acquire()
196+
with pytest.raises(Timeout):
197+
await second_lock.acquire()
198+
assert any("waiting" in msg for msg in caplog.messages)
199+
200+
201+
@pytest.mark.parametrize("lock_type", [AsyncSoftFileLock, AsyncFileLock])
202+
@pytest.mark.asyncio
203+
async def test_attempting_to_acquire_branch(
204+
lock_type: type[BaseAsyncFileLock], tmp_path: Path, caplog: pytest.LogCaptureFixture
205+
) -> None:
206+
caplog.set_level(logging.DEBUG)
207+
208+
lock = lock_type(str(tmp_path / "a"))
209+
await lock.acquire()
210+
assert any("Attempting to acquire lock" in m for m in caplog.messages)
211+
await lock.release()
212+
213+
214+
@pytest.mark.asyncio
215+
async def test_thread_local_run_in_executor(tmp_path: Path) -> None: # noqa: RUF029
216+
with pytest.raises(ValueError, match="run_in_executor is not supported when thread_local is True"):
217+
AsyncSoftFileLock(str(tmp_path / "a"), thread_local=True, run_in_executor=True)
218+
219+
220+
@pytest.mark.parametrize("lock_type", [AsyncSoftFileLock, AsyncFileLock])
221+
@pytest.mark.asyncio
222+
async def test_attempting_to_acquire(
223+
lock_type: type[BaseAsyncFileLock], tmp_path: Path, caplog: pytest.LogCaptureFixture
224+
) -> None:
225+
caplog.set_level(logging.DEBUG)
226+
lock = lock_type(str(tmp_path / "a.lock"), run_in_executor=False)
227+
await lock.acquire(timeout=0.1)
228+
assert any("Attempting to acquire lock" in m for m in caplog.messages)
229+
await lock.release()
230+
231+
232+
@pytest.mark.parametrize("lock_type", [AsyncSoftFileLock, AsyncFileLock])
233+
@pytest.mark.asyncio
234+
async def test_attempting_to_release(
235+
lock_type: type[BaseAsyncFileLock], tmp_path: Path, caplog: pytest.LogCaptureFixture
236+
) -> None:
237+
caplog.set_level(logging.DEBUG)
238+
lock = lock_type(str(tmp_path / "a.lock"), run_in_executor=False)
239+
240+
await lock.acquire(timeout=0.1) # lock_counter = 1, is_locked = True
241+
await lock.acquire(timeout=0.1) # lock_counter = 2 (reentrant)
242+
await lock.release(force=True)
243+
244+
assert any("Attempting to release lock" in m for m in caplog.messages)
245+
assert any("released" in m for m in caplog.messages)
246+
247+
248+
@pytest.mark.parametrize("lock_type", [AsyncFileLock, AsyncSoftFileLock])
249+
@pytest.mark.asyncio
250+
async def test_release_early_exit_when_unlocked(lock_type: type[BaseAsyncFileLock], tmp_path: Path) -> None:
251+
lock = lock_type(str(tmp_path / "a.lock"), run_in_executor=False)
252+
assert not lock.is_locked
253+
await lock.release()
254+
assert not lock.is_locked
255+
256+
257+
@pytest.mark.parametrize("lock_type", [AsyncFileLock, AsyncSoftFileLock])
258+
@pytest.mark.asyncio
259+
async def test_release_nonzero_counter_exit(
260+
lock_type: type[BaseAsyncFileLock], tmp_path: Path, caplog: pytest.LogCaptureFixture
261+
) -> None:
262+
caplog.set_level(logging.DEBUG)
263+
lock = lock_type(str(tmp_path / "a.lock"), run_in_executor=False)
264+
await lock.acquire()
265+
await lock.acquire()
266+
await lock.release() # counter goes 2→1
267+
assert lock.lock_counter == 1
268+
assert lock.is_locked
269+
assert not any("Attempting to release" in m for m in caplog.messages)
270+
await lock.release()

tests/test_filelock.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -691,7 +691,8 @@ def __init__(
691691
my_param: int = 0,
692692
**kwargs: dict[str, Any], # noqa: ARG002
693693
) -> None:
694-
super().__init__(lock_file, timeout, mode, thread_local, blocking=True, is_singleton=True)
694+
super().__init__(lock_file, timeout, mode, thread_local, is_singleton=True)
695+
self.blocking = True
695696
self.my_param = my_param
696697

697698
lock_path = tmp_path / "a"
@@ -814,3 +815,24 @@ def __init__(self, file_path: str) -> None:
814815
lock_path = tmp_path / "a"
815816
lock = FilePathLock(str(lock_path))
816817
assert lock.lock_file == str(lock_path) + ".lock"
818+
819+
820+
@pytest.mark.parametrize(
821+
("lock_type", "expected_exc"),
822+
[
823+
(SoftFileLock, TimeoutError),
824+
(FileLock, TimeoutError) if sys.platform == "win32" else (FileLock, PermissionError),
825+
],
826+
)
827+
def test_mtime_zero_exit_branch(
828+
lock_type: type[BaseFileLock], expected_exc: type[BaseException], tmp_path: Path
829+
) -> None:
830+
p = tmp_path / "z.lock"
831+
p.touch()
832+
Path(p).chmod(0o444)
833+
os.utime(p, (0, 0))
834+
835+
lock = lock_type(str(p))
836+
837+
with pytest.raises(expected_exc):
838+
lock.acquire(timeout=0)

0 commit comments

Comments
 (0)