Skip to content

Commit 8f57bce

Browse files
committed
Ensure --dist=loadscope is used when running pytest in parallel
The loadscope setting is required for parallel execution of our system tests using pytest. The option ensure that all tests within a single (module) scope will be assigned to the same worker. This is neccessary because the worker sets up the nameservers for all the tests within a module scope. If tests from the same module would be assigned to different workers, then the setup could happen multiple times, causing a race condition. This happens because each module uses deterministic port numbers for the nameservers.
1 parent 4dbe8e5 commit 8f57bce

File tree

4 files changed

+24
-14
lines changed

4 files changed

+24
-14
lines changed

.gitlab-ci.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ stages:
325325
- *find_pytest
326326
- cd bin/tests/system
327327
- >
328-
"$PYTEST" --junit-xml="$CI_PROJECT_DIR"/junit.xml -n "$TEST_PARALLEL_JOBS" --dist loadscope | tee pytest.out.txt
328+
"$PYTEST" --junit-xml="$CI_PROJECT_DIR"/junit.xml -n "$TEST_PARALLEL_JOBS" | tee pytest.out.txt
329329
- '( ! grep -F "grep: warning:" pytest.out.txt )'
330330
after_script:
331331
- awk '/^=+ FAILURES =+/{flag=1;next}/^=+.*=+$/{flag=0}flag' bin/tests/system/pytest.out.txt || true

bin/tests/system/README

+7-10
Original file line numberDiff line numberDiff line change
@@ -97,12 +97,7 @@ Issuing plain `pytest` command without any argument will execute all tests
9797
sequenatially. To execute them in parallel, ensure you have pytest-xdist
9898
installed and run:
9999

100-
pytest --dist loadscope -n <number-of-workers>
101-
102-
It is vital to provide the `--dist loadscope` option when running the tests in
103-
parallel to ensure tests from a single module are executed from the same
104-
thread. Otherwise, there's a risk of port contention and inefficient use of
105-
resources.
100+
pytest -n <number-of-workers>
106101

107102

108103
Running the System Tests Using the Legacy Runner
@@ -704,11 +699,13 @@ collisions are likely to occur.
704699

705700
Pytest-xdist is used for executing pytest test cases in parallel using the `-n
706701
N_WORKERS` option. By default, xdist will distribute any test case to any
707-
worker, which would lead to the issue described above. Therefore, it is vital
708-
to use the `--dist loadscope` option which ensures that test cases within the
709-
same (module) scope will be handled by the same worker.
702+
worker, which would lead to the issue described above. Therefore, conftest.py
703+
enforces equivalent of `--dist loadscope` option which ensures that test cases
704+
within the same (module) scope will be handled by the same worker. Parallelism
705+
is automatically disabled when xdist.scheduler.loadscope library is not
706+
available.
710707

711-
$ pytest -n auto --dist loadscope
708+
$ pytest -n auto
712709

713710
Test selection
714711
---

bin/tests/system/conftest.py

+15-1
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ def pytest_addoption(parser):
130130
help="don't remove the temporary test directories with artifacts",
131131
)
132132

133-
def pytest_configure():
133+
def pytest_configure(config):
134134
# Ensure this hook only runs on the main pytest instance if xdist is
135135
# used to spawn other workers.
136136
if not XDIST_WORKER:
@@ -156,6 +156,20 @@ def pytest_configure():
156156
raise exc
157157
logging.debug(proc.stdout)
158158

159+
if config.pluginmanager.has_plugin("xdist") and config.option.numprocesses:
160+
# system tests depend on module scope for setup & teardown
161+
# enforce use "loadscope" scheduler or disable paralelism
162+
try:
163+
import xdist.scheduler.loadscope # pylint: disable=unused-import
164+
except ImportError:
165+
logging.debug(
166+
"xdist is too old and does not have "
167+
"scheduler.loadscope, disabling parallelism"
168+
)
169+
config.option.dist = "no"
170+
else:
171+
config.option.dist = "loadscope"
172+
159173
def pytest_ignore_collect(path):
160174
# System tests are executed in temporary directories inside
161175
# bin/tests/system. These temporary directories contain all files

bin/tests/system/run.sh

+1-2
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ def into_pytest_args(in_args):
2828
if in_args.expression is None:
2929
# running all tests - execute in parallel
3030
args.extend(["-n", "auto"])
31-
args.extend(["--dist", "loadscope"])
3231
else:
3332
args.extend(["-k", in_args.expression])
3433
if in_args.noclean:
@@ -48,7 +47,7 @@ def main():
4847
"Using pytest system test runner\n\n"
4948
'Please consider invoking "pytest" directly for more control:\n'
5049
" single test: pytest -k dns64\n"
51-
" parallel tests: pytest -n auto --dist loadscope\n\n"
50+
" parallel tests: pytest -n auto\n\n"
5251
"Alternately, use ./legacy.run.sh for the legacy system test runner.\n"
5352
)
5453

0 commit comments

Comments
 (0)