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"""
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
        create_cleanup_lock(path)
 | 
					        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