diff --git a/src/xdist/scheduler/loadscope.py b/src/xdist/scheduler/loadscope.py index 0a01cb49..6fddd97c 100644 --- a/src/xdist/scheduler/loadscope.py +++ b/src/xdist/scheduler/loadscope.py @@ -162,6 +162,9 @@ def add_node(self, node: WorkerController) -> None: """ assert node not in self.assigned_work self.assigned_work[node] = {} + self.assigned_work = dict( + sorted(self.assigned_work.items(), key=lambda item: item[0].gateway.id) + ) def remove_node(self, node: WorkerController) -> str | None: """Remove a node from the scheduler. diff --git a/src/xdist/workermanage.py b/src/xdist/workermanage.py index 201c8e71..3d944d50 100644 --- a/src/xdist/workermanage.py +++ b/src/xdist/workermanage.py @@ -1,6 +1,7 @@ from __future__ import annotations from collections.abc import Sequence +from concurrent.futures import ThreadPoolExecutor import enum import fnmatch import os @@ -92,9 +93,17 @@ def setup_nodes( self, putevent: Callable[[tuple[str, dict[str, Any]]], None], ) -> list[WorkerController]: + # create basetemp directory only once + if hasattr(self.config, "_tmp_path_factory"): + self.config._tmp_path_factory.getbasetemp() + self.config.hook.pytest_xdist_setupnodes(config=self.config, specs=self.specs) self.trace("setting up nodes") - return [self.setup_node(spec, putevent) for spec in self.specs] + with ThreadPoolExecutor(max_workers=len(self.specs)) as executor: + futs = [ + executor.submit(self.setup_node, spec, putevent) for spec in self.specs + ] + return [f.result() for f in futs] def setup_node( self, diff --git a/testing/test_workermanage.py b/testing/test_workermanage.py index b3e8a1c7..3f729e94 100644 --- a/testing/test_workermanage.py +++ b/testing/test_workermanage.py @@ -82,11 +82,15 @@ def test_popen_makegateway_events( call = hookrecorder.popcall("pytest_xdist_setupnodes") assert len(call.specs) == 2 - call = hookrecorder.popcall("pytest_xdist_newgateway") - assert call.gateway.spec == execnet.XSpec("execmodel=main_thread_only//popen") - assert call.gateway.id == "gw0" - call = hookrecorder.popcall("pytest_xdist_newgateway") - assert call.gateway.id == "gw1" + # check expected gateways + gw_calls = [ + hookrecorder.popcall("pytest_xdist_newgateway"), + hookrecorder.popcall("pytest_xdist_newgateway"), + ] + assert {c.gateway.id for c in gw_calls} == {"gw0", "gw1"} + assert {c.gateway.spec for c in gw_calls} == { + execnet.XSpec("execmodel=main_thread_only//popen") + } assert len(hm.group) == 2 hm.teardown_nodes() assert not len(hm.group)