Skip to content

Commit

Permalink
Merge pull request #7352 from nicoddemus/lock-unlink-5456
Browse files Browse the repository at this point in the history
Suppress errors while removing tmpdir's lock files
  • Loading branch information
nicoddemus committed Jun 12, 2020
2 parents 0821c5c + ab331c9 commit 72344a5
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 4 deletions.
2 changes: 2 additions & 0 deletions changelog/5456.bugfix.rst
@@ -0,0 +1,2 @@
Fix a possible race condition when trying to remove lock files used to control access to folders
created by ``tmp_path`` and ``tmpdir``.
13 changes: 9 additions & 4 deletions src/_pytest/pathlib.py
@@ -1,4 +1,5 @@
import atexit
import contextlib
import fnmatch
import itertools
import os
Expand Down Expand Up @@ -290,10 +291,14 @@ def ensure_deletable(path: Path, consider_lock_dead_if_created_before: float) ->
return False
else:
if lock_time < consider_lock_dead_if_created_before:
lock.unlink()
return True
else:
return False
# wa want to ignore any errors while trying to remove the lock such as:
# - PermissionDenied, like the file permissions have changed since the lock creation
# - FileNotFoundError, in case another pytest process got here first.
# and any other cause of failure.
with contextlib.suppress(OSError):
lock.unlink()
return True
return False


def try_cleanup(path: Path, consider_lock_dead_if_created_before: float) -> None:
Expand Down
21 changes: 21 additions & 0 deletions testing/test_pathlib.py
@@ -1,9 +1,11 @@
import os.path
import sys
import unittest.mock

import py

import pytest
from _pytest.pathlib import ensure_deletable
from _pytest.pathlib import fnmatch_ex
from _pytest.pathlib import get_extended_length_path_str
from _pytest.pathlib import get_lock_path
Expand Down Expand Up @@ -113,3 +115,22 @@ def test_get_extended_length_path_str():
assert get_extended_length_path_str(r"\\share\foo") == r"\\?\UNC\share\foo"
assert get_extended_length_path_str(r"\\?\UNC\share\foo") == r"\\?\UNC\share\foo"
assert get_extended_length_path_str(r"\\?\c:\foo") == r"\\?\c:\foo"


def test_suppress_error_removing_lock(tmp_path):
"""ensure_deletable should not raise an exception if the lock file cannot be removed (#5456)"""
path = tmp_path / "dir"
path.mkdir()
lock = get_lock_path(path)
lock.touch()
mtime = lock.stat().st_mtime

with unittest.mock.patch.object(Path, "unlink", side_effect=OSError):
assert not ensure_deletable(
path, consider_lock_dead_if_created_before=mtime + 30
)
assert lock.is_file()

# check now that we can remove the lock file in normal circumstances
assert ensure_deletable(path, consider_lock_dead_if_created_before=mtime + 30)
assert not lock.is_file()

0 comments on commit 72344a5

Please sign in to comment.