Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test_generator_selection fails sporadically when run with xdist #711

Open
Apteryks opened this issue May 12, 2022 · 1 comment
Open

test_generator_selection fails sporadically when run with xdist #711

Apteryks opened this issue May 12, 2022 · 1 comment

Comments

@Apteryks
Copy link

Hello,

Occasionally (once out of 10 builds?) on a 24 cores machine , I get a failure from the test_generator_selection test. Here's the last one i got:

=================================== FAILURES ===================================
___________________________ test_generator_selection ___________________________
[gw16] linux -- Python 3.9.9 /gnu/store/j3cx0yaqdpw0mxizp5bayx93pya44dhn-python-wrapper-3.9.9/bin/python

    def test_generator_selection():
        version = sys.version_info
        env_generator = os.environ.get("CMAKE_GENERATOR")
        this_platform = platform.system().lower()
        get_best_generator = get_platform().get_best_generator
        arch = platform.architecture()[0]
    
        if env_generator:
            assert get_best_generator(env_generator).name == env_generator
    
        if this_platform == "windows":
            # assert that we are running a supported version of python
            py_27_32 = (version.major == 2 and version.minor >= 7) or (version.major == 3 and version.minor <= 2)
    
            py_33_34 = version.major == 3 and (3 <= version.minor <= 4)
    
            py_35 = version.major == 3 and version.minor >= 5
    
            assert len(tuple(filter(bool, (py_27_32, py_33_34, py_35)))) == 1
    
            # Expected Visual Studio version
            if py_27_32:
                vs_generator = "Visual Studio 9 2008"
                vs_version = 9
            elif py_33_34:
                vs_generator = "Visual Studio 10 2010"
                vs_version = 10
            else:
                vs_generator = "Visual Studio 14 2015"
                vs_version = 14
            vs_generator += " Win64" if arch == "64bit" else ""
    
            has_vs_2017 = find_visual_studio(vs_version=VS_YEAR_TO_VERSION["2017"])
            has_vs_2019 = find_visual_studio(vs_version=VS_YEAR_TO_VERSION["2019"])
            has_vs_2022 = find_visual_studio(vs_version=VS_YEAR_TO_VERSION["2022"])
    
            # Apply to VS <= 14 (2015)
            has_vs_ide_vcvars = any(
                [
                    os.path.exists(path_pattern % vs_version)
                    for path_pattern in ["C:/Program Files (x86)/Microsoft Visual Studio %.1f/VC/vcvarsall.bat"]
                ]
            )
    
            # As of Dec 2016, this is available only for VS 9.0
            has_vs_for_python_vcvars = any(
                [
                    os.path.exists(os.path.expanduser(path_pattern % vs_version))
                    for path_pattern in [
                        "~/AppData/Local/Programs/Common/Microsoft/Visual C++ for Python/%.1f/vcvarsall.bat",
                        "C:/Program Files (x86)/Common Files/Microsoft/Visual C++ for Python/%.1f/vcvarsall.bat",
                    ]
                ]
            )
    
            # If environment exists, update the expected generator
            if (has_vs_for_python_vcvars or has_vs_ide_vcvars) and which("ninja.exe"):
                assert get_best_generator().name == "Ninja"
    
            elif has_vs_2017:
                vs_generator = "Visual Studio 15 2017"
                # Early versions of 2017 may not ship with Ninja (TODO: check)
                assert get_best_generator().name in {"Ninja", vs_generator}
    
            elif has_vs_2019 or has_vs_2022:
                # ninja is provided by the CMake extension bundled with Visual Studio 2017
                # C:/Program Files (x86)/Microsoft Visual Studio/2017/Professional/Common7/IDE/CommonExtensions/Microsoft/CMake/Ninja/ninja.exe  # noqa: E501
                assert get_best_generator().name == "Ninja"
    
            elif has_vs_ide_vcvars:
                assert get_best_generator().name == vs_generator
    
            elif has_vs_for_python_vcvars:
                assert get_best_generator().name == "NMake Makefiles"
    
        elif this_platform in ["darwin", "linux"]:
            generator = "Ninja" if which("ninja") else "Unix Makefiles"
>           assert get_best_generator().name == generator

arch       = '64bit'
env_generator = None
generator  = 'Ninja'
get_best_generator = <bound method CMakePlatform.get_best_generator of <skbuild.platform_specifics.linux.LinuxPlatform object at 0x7ffff4336dc0>>
this_platform = 'linux'
version    = sys.version_info(major=3, minor=9, micro=9, releaselevel='final', serial=0)

tests/test_skbuild.py:101: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
skbuild/platform_specifics/abstract.py:165: in get_best_generator
    working_generator = self.compile_test_cmakelist(cmake_executable, candidate_generators, cmake_args)
        architecture = None
        candidate_generators = [<skbuild.platform_specifics.abstract.CMakeGenerator object at 0x7ffff4336d60>,
 <skbuild.platform_specifics.abstract.CMakeGenerator object at 0x7ffff4336130>]
        cleanup    = True
        cmake_args = ()
        cmake_executable = '/gnu/store/zga679c4nldah9l8dhd5a4hdy820hcyf-cmake-minimal-3.21.4/bin/cmake'
        generator_name = None
        languages  = ('CXX', 'C')
        self       = <skbuild.platform_specifics.linux.LinuxPlatform object at 0x7ffff4336dc0>
        skip_generator_test = False
skbuild/utils/__init__.py:58: in inner
    return func(*args, **kwds)
        args       = ('/gnu/store/zga679c4nldah9l8dhd5a4hdy820hcyf-cmake-minimal-3.21.4/bin/cmake',
 [<skbuild.platform_specifics.abstract.CMakeGenerator object at 0x7ffff4336d60>,
  <skbuild.platform_specifics.abstract.CMakeGenerator object at 0x7ffff4336130>],
 ())
        func       = <function CMakePlatform.compile_test_cmakelist at 0x7ffff4bbc310>
        kwds       = {}
        self       = <skbuild.utils.push_dir object at 0x7ffff4bba790>
skbuild/platform_specifics/abstract.py:221: in compile_test_cmakelist
    shutil.rmtree("build")
        _generator_discovery_status_msg = <function CMakePlatform.compile_test_cmakelist.<locals>._generator_discovery_status_msg at 0x7ffff430cc10>
        candidate_generators = [<skbuild.platform_specifics.abstract.CMakeGenerator object at 0x7ffff4336d60>,
 <skbuild.platform_specifics.abstract.CMakeGenerator object at 0x7ffff4336130>]
        cmake_args = ['--no-warn-unused-cli']
        cmake_exe_path = '/gnu/store/zga679c4nldah9l8dhd5a4hdy820hcyf-cmake-minimal-3.21.4/bin/cmake'
        generator  = <skbuild.platform_specifics.abstract.CMakeGenerator object at 0x7ffff4336d60>
        working_generator = None
/gnu/store/b6j1qw1a5rkbfvcy7lc9fm95abbzpa4x-python-3.9.9/lib/python3.9/shutil.py:727: in rmtree
    _rmtree_safe_fd(fd, path, onerror)
        fd         = 13
        ignore_errors = False
        onerror    = <function rmtree.<locals>.onerror at 0x7ffff42d5ca0>
        orig_st    = os.stat_result(st_mode=16877, st_ino=911108156, st_dev=25, st_nlink=1, st_uid=999, st_gid=30000, st_size=20, st_atime=1652373044, st_mtime=1652373044, st_ctime=1652373044)
        path       = 'build'
/gnu/store/b6j1qw1a5rkbfvcy7lc9fm95abbzpa4x-python-3.9.9/lib/python3.9/shutil.py:664: in _rmtree_safe_fd
    _rmtree_safe_fd(dirfd, fullname, onerror)
        dirfd      = 14
        entries    = [<DirEntry 'CMakeFiles'>]
        entry      = <DirEntry 'CMakeFiles'>
        fullname   = 'build/CMakeFiles'
        is_dir     = True
        onerror    = <function rmtree.<locals>.onerror at 0x7ffff42d5ca0>
        orig_st    = os.stat_result(st_mode=16877, st_ino=911108176, st_dev=25, st_nlink=1, st_uid=999, st_gid=30000, st_size=58, st_atime=1652373044, st_mtime=1652373046, st_ctime=1652373046)
        path       = 'build'
        scandir_it = <posix.ScandirIterator object at 0x7ffff4328ab0>
        topfd      = 13
/gnu/store/b6j1qw1a5rkbfvcy7lc9fm95abbzpa4x-python-3.9.9/lib/python3.9/shutil.py:664: in _rmtree_safe_fd
    _rmtree_safe_fd(dirfd, fullname, onerror)
        dirfd      = 15
        entries    = [<DirEntry 'CMakeOutput.log'>, <DirEntry '3.21.4'>, <DirEntry 'CMakeTmp'>]
        entry      = <DirEntry 'CMakeTmp'>
        fullname   = 'build/CMakeFiles/CMakeTmp'
        is_dir     = True
        onerror    = <function rmtree.<locals>.onerror at 0x7ffff42d5ca0>
        orig_st    = os.stat_result(st_mode=16877, st_ino=911108689, st_dev=25, st_nlink=1, st_uid=999, st_gid=30000, st_size=148, st_atime=1652373048, st_mtime=1652373048, st_ctime=1652373048)
        path       = 'build/CMakeFiles'
        scandir_it = <posix.ScandirIterator object at 0x7ffff4328a40>
        topfd      = 14
/gnu/store/b6j1qw1a5rkbfvcy7lc9fm95abbzpa4x-python-3.9.9/lib/python3.9/shutil.py:664: in _rmtree_safe_fd
    _rmtree_safe_fd(dirfd, fullname, onerror)
        dirfd      = 16
        entries    = [<DirEntry 'CMakeFiles'>,
 <DirEntry 'CMakeCache.txt'>,
 <DirEntry 'cmake_install.cmake'>,
 <DirEntry 'build.ninja'>,
 <DirEntry '.ninja_log'>,
 <DirEntry 'cmTC_9455c'>]
        entry      = <DirEntry 'CMakeFiles'>
        fullname   = 'build/CMakeFiles/CMakeTmp/CMakeFiles'
        is_dir     = True
        onerror    = <function rmtree.<locals>.onerror at 0x7ffff42d5ca0>
        orig_st    = os.stat_result(st_mode=16877, st_ino=911108749, st_dev=25, st_nlink=1, st_uid=999, st_gid=30000, st_size=92, st_atime=1652373048, st_mtime=1652373048, st_ctime=1652373048)
        path       = 'build/CMakeFiles/CMakeTmp'
        scandir_it = <posix.ScandirIterator object at 0x7ffff42cf110>
        topfd      = 15
/gnu/store/b6j1qw1a5rkbfvcy7lc9fm95abbzpa4x-python-3.9.9/lib/python3.9/shutil.py:664: in _rmtree_safe_fd
    _rmtree_safe_fd(dirfd, fullname, onerror)
        dirfd      = 17
        entries    = [<DirEntry 'cmTC_9455c.dir'>,
 <DirEntry 'TargetDirectories.txt'>,
 <DirEntry 'rules.ninja'>]
        entry      = <DirEntry 'cmTC_9455c.dir'>
        fullname   = 'build/CMakeFiles/CMakeTmp/CMakeFiles/cmTC_9455c.dir'
        is_dir     = True
        onerror    = <function rmtree.<locals>.onerror at 0x7ffff42d5ca0>
        orig_st    = os.stat_result(st_mode=16877, st_ino=911108765, st_dev=25, st_nlink=1, st_uid=999, st_gid=30000, st_size=342, st_atime=1652373046, st_mtime=1652373047, st_ctime=1652373047)
        path       = 'build/CMakeFiles/CMakeTmp/CMakeFiles'
        scandir_it = <posix.ScandirIterator object at 0x7ffff42cf1f0>
        topfd      = 16
/gnu/store/b6j1qw1a5rkbfvcy7lc9fm95abbzpa4x-python-3.9.9/lib/python3.9/shutil.py:684: in _rmtree_safe_fd
    onerror(os.unlink, fullname, sys.exc_info())
        entries    = [<DirEntry 'FortranDependInfo.json'>,
 <DirEntry 'CMakeFortranCompilerABI.F-pp.f'>,
 <DirEntry 'CMakeFortranCompilerABI.F-pp.f.d'>,
 <DirEntry 'CMakeFortranCompilerABI.F.o.ddi'>,
 <DirEntry 'FortranModules.json'>,
 <DirEntry 'Fortran.dd'>,
 <DirEntry 'CMakeFortranCompilerABI.F.o'>]
        entry      = <DirEntry 'CMakeFortranCompilerABI.F.o'>
        fullname   = 'build/CMakeFiles/CMakeTmp/CMakeFiles/cmTC_9455c.dir/CMakeFortranCompilerABI.F.o'
        is_dir     = False
        onerror    = <function rmtree.<locals>.onerror at 0x7ffff42d5ca0>
        path       = 'build/CMakeFiles/CMakeTmp/CMakeFiles/cmTC_9455c.dir'
        scandir_it = <posix.ScandirIterator object at 0x7ffff42cf0a0>
        topfd      = 17
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

topfd = 17, path = 'build/CMakeFiles/CMakeTmp/CMakeFiles/cmTC_9455c.dir'
onerror = <function rmtree.<locals>.onerror at 0x7ffff42d5ca0>

    def _rmtree_safe_fd(topfd, path, onerror):
        try:
            with os.scandir(topfd) as scandir_it:
                entries = list(scandir_it)
        except OSError as err:
            err.filename = path
            onerror(os.scandir, path, sys.exc_info())
            return
        for entry in entries:
            fullname = os.path.join(path, entry.name)
            try:
                is_dir = entry.is_dir(follow_symlinks=False)
            except OSError:
                is_dir = False
            else:
                if is_dir:
                    try:
                        orig_st = entry.stat(follow_symlinks=False)
                        is_dir = stat.S_ISDIR(orig_st.st_mode)
                    except OSError:
                        onerror(os.lstat, fullname, sys.exc_info())
                        continue
            if is_dir:
                try:
                    dirfd = os.open(entry.name, os.O_RDONLY, dir_fd=topfd)
                except OSError:
                    onerror(os.open, fullname, sys.exc_info())
                else:
                    try:
                        if os.path.samestat(orig_st, os.fstat(dirfd)):
                            _rmtree_safe_fd(dirfd, fullname, onerror)
                            try:
                                os.rmdir(entry.name, dir_fd=topfd)
                            except OSError:
                                onerror(os.rmdir, fullname, sys.exc_info())
                        else:
                            try:
                                # This can only happen if someone replaces
                                # a directory with a symlink after the call to
                                # os.scandir or stat.S_ISDIR above.
                                raise OSError("Cannot call rmtree on a symbolic "
                                              "link")
                            except OSError:
                                onerror(os.path.islink, fullname, sys.exc_info())
                    finally:
                        os.close(dirfd)
            else:
                try:
>                   os.unlink(entry.name, dir_fd=topfd)
E                   FileNotFoundError: [Errno 2] No such file or directory: 'CMakeFortranCompilerABI.F.o'

entries    = [<DirEntry 'FortranDependInfo.json'>,
 <DirEntry 'CMakeFortranCompilerABI.F-pp.f'>,
 <DirEntry 'CMakeFortranCompilerABI.F-pp.f.d'>,
 <DirEntry 'CMakeFortranCompilerABI.F.o.ddi'>,
 <DirEntry 'FortranModules.json'>,
 <DirEntry 'Fortran.dd'>,
 <DirEntry 'CMakeFortranCompilerABI.F.o'>]
entry      = <DirEntry 'CMakeFortranCompilerABI.F.o'>
fullname   = 'build/CMakeFiles/CMakeTmp/CMakeFiles/cmTC_9455c.dir/CMakeFortranCompilerABI.F.o'
is_dir     = False
onerror    = <function rmtree.<locals>.onerror at 0x7ffff42d5ca0>
path       = 'build/CMakeFiles/CMakeTmp/CMakeFiles/cmTC_9455c.dir'
scandir_it = <posix.ScandirIterator object at 0x7ffff42cf0a0>
topfd      = 17

/gnu/store/b6j1qw1a5rkbfvcy7lc9fm95abbzpa4x-python-3.9.9/lib/python3.9/shutil.py:682: FileNotFoundError
----------------------------- Captured stdout call -----------------------------


--------------------------------------------------------------------------------
-- Trying "Ninja" generator
--------------------------------
---------------------------
----------------------
-----------------
------------
-------
--
=============================== warnings summary ===============================
tests/test_hello_cython.py::test_hello_cython_sdist
tests/test_hello_cython.py::test_hello_cython_builds
tests/test_hello_cython.py::test_hello_cython_wheel
  setup.py:3: FutureWarning: package_dir={'hello_cython': 'hello/'} ends with a trailing slash, which is not supported by setuptools.

tests/test_hello_cython_manifest.py::test_hello_cython_sdist
tests/test_hello_cython_manifest.py::test_hello_cython_builds
tests/test_hello_cython_manifest.py::test_hello_cython_wheel
  setup.py:3: FutureWarning: package_dir={'hello_cython_manifest': 'hello/'} ends with a trailing slash, which is not supported by setuptools.

-- Docs: https://docs.pytest.org/en/stable/warnings.html

----------- coverage: platform linux, python 3.9.9-final-0 -----------
Coverage XML written to file tests/coverage.xml

=========================== short test summary info ============================
SKIPPED [1] tests/test_logging.py:5: could not import 'setuptools.logging': No module named 'setuptools.logging'
SKIPPED [1] tests/test_setup.py:323: pypi.org website not reachable
SKIPPED [24] tests/test_setup.py:588: unsupported configuration: python package fully generated by CMake does *NOT* work. At least __init__.py should be in the project source tree
SKIPPED [8] tests/test_skbuild.py:156: Requires Windows
SKIPPED [1] tests/test_skbuild.py:178: Requires Windows
SKIPPED [1] tests/test_skbuild.py:112: NMake Makefiles generator is available only on Linux
SKIPPED [1] tests/test_platform.py:117: Requires Windows
FAILED tests/test_skbuild.py::test_generator_selection - FileNotFoundError: [...
============ 1 failed, 191 passed, 37 skipped, 6 warnings in 50.98s ============

This usually means the test reuse the same directory/files across parameterized tests, which cause races and undefined behavior.

@Apteryks
Copy link
Author

I also had disabled test_generator_cleanup due to unexplained failures, perhaps it is similarly racy.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants
@Apteryks and others