Merge pull request #4222 from RonnyPfannschmidt/pathlib-fixes
handle race condition when creation and deletion of a numbered dir overlap
This commit is contained in:
commit
d59786fcc4
|
@ -0,0 +1 @@
|
||||||
|
Handle race condition between creation and deletion of temporary folders.
|
|
@ -185,9 +185,15 @@ def register_cleanup_lock_removal(lock_path, register=atexit.register):
|
||||||
return register(cleanup_on_exit)
|
return register(cleanup_on_exit)
|
||||||
|
|
||||||
|
|
||||||
def delete_a_numbered_dir(path):
|
def maybe_delete_a_numbered_dir(path):
|
||||||
"""removes a numbered directory"""
|
"""removes a numbered directory if its lock can be obtained"""
|
||||||
create_cleanup_lock(path)
|
try:
|
||||||
|
create_cleanup_lock(path)
|
||||||
|
except (OSError, EnvironmentError):
|
||||||
|
# known races:
|
||||||
|
# * other process did a cleanup at the same time
|
||||||
|
# * deletable folder was found
|
||||||
|
return
|
||||||
parent = path.parent
|
parent = path.parent
|
||||||
|
|
||||||
garbage = parent.joinpath("garbage-{}".format(uuid.uuid4()))
|
garbage = parent.joinpath("garbage-{}".format(uuid.uuid4()))
|
||||||
|
@ -217,7 +223,7 @@ def ensure_deletable(path, consider_lock_dead_if_created_before):
|
||||||
def try_cleanup(path, consider_lock_dead_if_created_before):
|
def try_cleanup(path, consider_lock_dead_if_created_before):
|
||||||
"""tries to cleanup a folder if we can ensure its deletable"""
|
"""tries to cleanup a folder if we can ensure its deletable"""
|
||||||
if ensure_deletable(path, consider_lock_dead_if_created_before):
|
if ensure_deletable(path, consider_lock_dead_if_created_before):
|
||||||
delete_a_numbered_dir(path)
|
maybe_delete_a_numbered_dir(path)
|
||||||
|
|
||||||
|
|
||||||
def cleanup_candidates(root, prefix, keep):
|
def cleanup_candidates(root, prefix, keep):
|
||||||
|
|
|
@ -7,6 +7,7 @@ import sys
|
||||||
import six
|
import six
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
from _pytest import pathlib
|
||||||
from _pytest.pathlib import Path
|
from _pytest.pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
@ -287,11 +288,17 @@ class TestNumberedDir(object):
|
||||||
rmtree(adir, force=True)
|
rmtree(adir, force=True)
|
||||||
assert not adir.exists()
|
assert not adir.exists()
|
||||||
|
|
||||||
def test_cleanup_symlink(self, tmp_path):
|
def test_cleanup_ignores_symlink(self, tmp_path):
|
||||||
the_symlink = tmp_path / (self.PREFIX + "current")
|
the_symlink = tmp_path / (self.PREFIX + "current")
|
||||||
attempt_symlink_to(the_symlink, tmp_path / (self.PREFIX + "5"))
|
attempt_symlink_to(the_symlink, tmp_path / (self.PREFIX + "5"))
|
||||||
self._do_cleanup(tmp_path)
|
self._do_cleanup(tmp_path)
|
||||||
|
|
||||||
|
def test_removal_accepts_lock(self, tmp_path):
|
||||||
|
folder = pathlib.make_numbered_dir(root=tmp_path, prefix=self.PREFIX)
|
||||||
|
pathlib.create_cleanup_lock(folder)
|
||||||
|
pathlib.maybe_delete_a_numbered_dir(folder)
|
||||||
|
assert folder.is_dir()
|
||||||
|
|
||||||
|
|
||||||
def attempt_symlink_to(path, to_path):
|
def attempt_symlink_to(path, to_path):
|
||||||
"""Try to make a symlink from "path" to "to_path", skipping in case this platform
|
"""Try to make a symlink from "path" to "to_path", skipping in case this platform
|
||||||
|
|
Loading…
Reference in New Issue