tribuchet: building on jamie ============================= test session starts ============================== platform linux -- Python 3.13.9, pytest-8.4.2, pluggy-1.6.0 -- /nix/store/3lll9y925zz9393sa59h653xik66srjb-python3-3.13.9/bin/python3.13 cachedir: .pytest_cache rootdir: /build collecting ... collected 23 items tests-functional/test_eval.py::test_flake PASSED [ 4%] tests-functional/test_eval.py::test_query_cache_status PASSED [ 8%] tests-functional/test_eval.py::test_expression PASSED [ 13%] tests-functional/test_eval.py::test_input_drvs PASSED [ 17%] tests-functional/test_eval.py::test_eval_error PASSED [ 21%] tests-functional/test_eval.py::test_no_gcroot_dir PASSED [ 26%] tests-functional/test_eval.py::test_daemon_only_settings_do_not_warn PASSED [ 30%] tests-functional/test_eval.py::test_constituents PASSED [ 34%] tests-functional/test_eval.py::test_constituents_all PASSED [ 39%] tests-functional/test_eval.py::test_constituents_glob_misc PASSED [ 43%] tests-functional/test_eval.py::test_constituents_cycle PASSED [ 47%] tests-functional/test_eval.py::test_constituents_error PASSED [ 52%] tests-functional/test_eval.py::test_empty_needed PASSED [ 56%] tests-functional/test_eval.py::test_apply PASSED [ 60%] tests-functional/test_eval.py::test_select_flake PASSED [ 65%] tests-functional/test_eval.py::test_recursion_error PASSED [ 69%] tests-functional/test_eval.py::test_no_instantiate_mode PASSED [ 73%] tests-functional/test_eval.py::test_fod_with_uncached_input_issue413[file] PASSED [ 78%] tests-functional/test_eval.py::test_fod_with_uncached_input_issue413[http] PASSED [ 82%] tests-functional/test_eval.py::test_worker_log_format_survives_fork PASSED [ 86%] tests-functional/test_eval.py::test_worker_restart_on_last_job_exits_cleanly PASSED [ 91%] tests-functional/test_eval.py::test_fetchers_survive_worker_restart PASSED [ 95%] tests-functional/test_eval.py::test_workers_do_not_race_flake_fetch FAILED [100%] =================================== FAILURES =================================== _____________________ test_workers_do_not_race_flake_fetch _____________________ tmp_path = PosixPath('/build/pytest-of-nixbld/pytest-0/test_workers_do_not_race_flake0') def test_workers_do_not_race_flake_fetch(tmp_path: Path) -> None: """Workers fetching the same flake input concurrently spam "waiting for another Nix process to finish fetching input" (issue #432).""" env = _hermetic_nix_env(tmp_path) repo = tmp_path / "flake" repo.mkdir() jobs = "\n".join( f""" job-{i} = derivation {{ name = "race-{i}"; system = "x86_64-linux"; builder = "/bin/sh"; args = [ "-c" "echo {i} > $out" ]; }};""" for i in range(8) ) repo.joinpath("flake.nix").write_text(f"{{ outputs = _: {{ hydraJobs = {{ {jobs} }}; }}; }}") > subprocess.run(["git", "init", "-q"], cwd=repo, check=True, env=env) tests-functional/test_eval.py:875: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /nix/store/3lll9y925zz9393sa59h653xik66srjb-python3-3.13.9/lib/python3.13/subprocess.py:554: in run with Popen(*popenargs, **kwargs) as process: ^^^^^^^^^^^^^^^^^^^^^^^^^^^ /nix/store/3lll9y925zz9393sa59h653xik66srjb-python3-3.13.9/lib/python3.13/subprocess.py:1039: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['git', 'init', '-q'], executable = b'git', preexec_fn = None close_fds = True, pass_fds = () cwd = PosixPath('/build/pytest-of-nixbld/pytest-0/test_workers_do_not_race_flake0/flake') env = {'CONFIG_SHELL': '/nix/store/rlq03x4cwf8zn73hxaxnx0zn5q9kifls-bash-5.3p3/bin/bash', 'DETERMINISTIC_BUILD': '1', 'GZIP_NO_TIMESTAMPS': '1', 'HOME': '/build/pytest-of-nixbld/pytest-0/test_workers_do_not_race_flake0/home', ...} startupinfo = None, creationflags = 0, shell = False, p2cread = -1 p2cwrite = -1, c2pread = -1, c2pwrite = -1, errread = -1, errwrite = -1 restore_signals = True, gid = None, gids = None, uid = None, umask = -1 start_new_session = False, process_group = -1 def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, os.PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [args] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ('/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/nix/store/rlq03x4cwf8zn73hxaxnx0zn5q9kifls-bash-5.3p3/bin/sh') args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] sys.audit("subprocess.Popen", executable, args, cwd, env) if (_USE_POSIX_SPAWN and os.path.dirname(executable) and preexec_fn is None and (not close_fds or _HAVE_POSIX_SPAWN_CLOSEFROM) and not pass_fds and cwd is None and (p2cread == -1 or p2cread > 2) and (c2pwrite == -1 or c2pwrite > 2) and (errwrite == -1 or errwrite > 2) and not start_new_session and process_group == -1 and gid is None and gids is None and uid is None and umask < 0): self._posix_spawn(args, executable, env, restore_signals, close_fds, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite) return orig_executable = executable # For transferring possible exec failure from child to parent. # Data format: "exception name:hex errno:description" # Pickle is not used; it is complex and involves memory allocation. errpipe_read, errpipe_write = os.pipe() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: # We must avoid complex work that could involve # malloc or free in the child process to avoid # potential deadlocks, thus we do all this here. # and pass it to fork_exec() if env is not None: env_list = [] for k, v in env.items(): k = os.fsencode(k) if b'=' in k: raise ValueError("illegal environment variable name") env_list.append(k + b'=' + os.fsencode(v)) else: env_list = None # Use execv instead of execve. executable = os.fsencode(executable) if os.path.dirname(executable): executable_list = (executable,) else: # This matches the behavior of os._execvpe(). executable_list = tuple( os.path.join(os.fsencode(dir), executable) for dir in os.get_exec_path(env)) fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self.pid = _fork_exec( args, executable_list, close_fds, tuple(sorted(map(int, fds_to_keep))), cwd, env_list, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, errpipe_read, errpipe_write, restore_signals, start_new_session, process_group, gid, gids, uid, umask, preexec_fn, _USE_VFORK) self._child_created = True finally: # be sure the FD is closed no matter what os.close(errpipe_write) self._close_pipe_fds(p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite) # Wait for exec to fail or succeed; possibly raising an # exception (limited in size) errpipe_data = bytearray() while True: part = os.read(errpipe_read, 50000) errpipe_data += part if not part or len(errpipe_data) > 50000: break finally: # be sure the FD is closed no matter what os.close(errpipe_read) if errpipe_data: try: pid, sts = os.waitpid(self.pid, 0) if pid == self.pid: self._handle_exitstatus(sts) else: self.returncode = sys.maxsize except ChildProcessError: pass try: exception_name, hex_errno, err_msg = ( errpipe_data.split(b':', 2)) # The encoding here should match the encoding # written in by the subprocess implementations # like _posixsubprocess err_msg = err_msg.decode() except ValueError: exception_name = b'SubprocessError' hex_errno = b'0' err_msg = 'Bad exception data from child: {!r}'.format( bytes(errpipe_data)) child_exception_type = getattr( builtins, exception_name.decode('ascii'), SubprocessError) if issubclass(child_exception_type, OSError) and hex_errno: errno_num = int(hex_errno, 16) if err_msg == "noexec:chdir": err_msg = "" # The error must be from chdir(cwd). err_filename = cwd elif err_msg == "noexec": err_msg = "" err_filename = None else: err_filename = orig_executable if errno_num != 0: err_msg = os.strerror(errno_num) if err_filename is not None: > raise child_exception_type(errno_num, err_msg, err_filename) E FileNotFoundError: [Errno 2] No such file or directory: 'git' /nix/store/3lll9y925zz9393sa59h653xik66srjb-python3-3.13.9/lib/python3.13/subprocess.py:1972: FileNotFoundError =========================== short test summary info ============================ FAILED tests-functional/test_eval.py::test_workers_do_not_race_flake_fetch - ... ========================= 1 failed, 22 passed in 4.77s =========================