11from contextlib import suppress
22from pathlib import Path
3+ import sys
4+ import os
35
46import execnet
57from xdist .workermanage import NodeManager
68
79import pytest
810
911
12+ @pytest .fixture
13+ def monkeypatch_3_cpus (monkeypatch : pytest .MonkeyPatch ):
14+ """Make pytest-xdist believe the system has 3 CPUs"""
15+ monkeypatch .setitem (sys .modules , "psutil" , None ) # block import
16+ monkeypatch .delattr (os , "sched_getaffinity" , raising = False )
17+ monkeypatch .setattr (os , "cpu_count" , lambda : 3 )
18+
19+
1020def test_dist_incompatibility_messages (pytester : pytest .Pytester ) -> None :
1121 result = pytester .runpytest ("--pdb" , "--looponfail" )
1222 assert result .ret != 0
@@ -41,7 +51,6 @@ def test_dist_options(pytester: pytest.Pytester) -> None:
4151def test_auto_detect_cpus (
4252 pytester : pytest .Pytester , monkeypatch : pytest .MonkeyPatch
4353) -> None :
44- import os
4554 from xdist .plugin import pytest_cmdline_main as check_options
4655
4756 with suppress (ImportError ):
@@ -102,6 +111,20 @@ def test_auto_detect_cpus_psutil(
102111 assert config .getoption ("numprocesses" ) == 84
103112
104113
114+ def test_auto_detect_cpus_os (
115+ pytester : pytest .Pytester , monkeypatch : pytest .MonkeyPatch , monkeypatch_3_cpus
116+ ) -> None :
117+ from xdist .plugin import pytest_cmdline_main as check_options
118+
119+ config = pytester .parseconfigure ("-nauto" )
120+ check_options (config )
121+ assert config .getoption ("numprocesses" ) == 3
122+
123+ config = pytester .parseconfigure ("-nlogical" )
124+ check_options (config )
125+ assert config .getoption ("numprocesses" ) == 3
126+
127+
105128def test_hook_auto_num_workers (
106129 pytester : pytest .Pytester , monkeypatch : pytest .MonkeyPatch
107130) -> None :
@@ -122,6 +145,105 @@ def pytest_xdist_auto_num_workers():
122145 assert config .getoption ("numprocesses" ) == 42
123146
124147
148+ def test_hook_auto_num_workers_arg (
149+ pytester : pytest .Pytester , monkeypatch : pytest .MonkeyPatch
150+ ) -> None :
151+ # config.option.numprocesses is a pytest feature,
152+ # but we document it so let's test it.
153+ from xdist .plugin import pytest_cmdline_main as check_options
154+
155+ pytester .makeconftest (
156+ """
157+ def pytest_xdist_auto_num_workers(config):
158+ if config.option.numprocesses == 'auto':
159+ return 42
160+ if config.option.numprocesses == 'logical':
161+ return 8
162+ """
163+ )
164+ config = pytester .parseconfigure ("-nauto" )
165+ check_options (config )
166+ assert config .getoption ("numprocesses" ) == 42
167+
168+ config = pytester .parseconfigure ("-nlogical" )
169+ check_options (config )
170+ assert config .getoption ("numprocesses" ) == 8
171+
172+
173+ def test_hook_auto_num_workers_none (
174+ pytester : pytest .Pytester , monkeypatch : pytest .MonkeyPatch , monkeypatch_3_cpus
175+ ) -> None :
176+ # Returning None from a hook to skip it is pytest behavior,
177+ # but we document it so let's test it.
178+ from xdist .plugin import pytest_cmdline_main as check_options
179+
180+ pytester .makeconftest (
181+ """
182+ def pytest_xdist_auto_num_workers():
183+ return None
184+ """
185+ )
186+ config = pytester .parseconfigure ("-nauto" )
187+ check_options (config )
188+ assert config .getoption ("numprocesses" ) == 3
189+
190+ monkeypatch .setenv ("PYTEST_XDIST_AUTO_NUM_WORKERS" , "5" )
191+
192+ config = pytester .parseconfigure ("-nauto" )
193+ check_options (config )
194+ assert config .getoption ("numprocesses" ) == 5
195+
196+
197+ def test_envvar_auto_num_workers (
198+ pytester : pytest .Pytester , monkeypatch : pytest .MonkeyPatch
199+ ) -> None :
200+ from xdist .plugin import pytest_cmdline_main as check_options
201+
202+ monkeypatch .setenv ("PYTEST_XDIST_AUTO_NUM_WORKERS" , "7" )
203+
204+ config = pytester .parseconfigure ("-nauto" )
205+ check_options (config )
206+ assert config .getoption ("numprocesses" ) == 7
207+
208+ config = pytester .parseconfigure ("-nlogical" )
209+ check_options (config )
210+ assert config .getoption ("numprocesses" ) == 7
211+
212+
213+ def test_envvar_auto_num_workers_warn (
214+ pytester : pytest .Pytester , monkeypatch : pytest .MonkeyPatch , monkeypatch_3_cpus
215+ ) -> None :
216+ from xdist .plugin import pytest_cmdline_main as check_options
217+
218+ monkeypatch .setenv ("PYTEST_XDIST_AUTO_NUM_WORKERS" , "fourscore" )
219+
220+ config = pytester .parseconfigure ("-nauto" )
221+ with pytest .warns (UserWarning ):
222+ check_options (config )
223+ assert config .getoption ("numprocesses" ) == 3
224+
225+
226+ def test_auto_num_workers_hook_overrides_envvar (
227+ pytester : pytest .Pytester , monkeypatch : pytest .MonkeyPatch , monkeypatch_3_cpus
228+ ) -> None :
229+ from xdist .plugin import pytest_cmdline_main as check_options
230+
231+ monkeypatch .setenv ("PYTEST_XDIST_AUTO_NUM_WORKERS" , "987" )
232+ pytester .makeconftest (
233+ """
234+ def pytest_xdist_auto_num_workers():
235+ return 2
236+ """
237+ )
238+ config = pytester .parseconfigure ("-nauto" )
239+ check_options (config )
240+ assert config .getoption ("numprocesses" ) == 2
241+
242+ config = pytester .parseconfigure ("-nauto" )
243+ check_options (config )
244+ assert config .getoption ("numprocesses" ) == 2
245+
246+
125247def test_dsession_with_collect_only (pytester : pytest .Pytester ) -> None :
126248 from xdist .plugin import pytest_cmdline_main as check_options
127249 from xdist .plugin import pytest_configure as configure
0 commit comments