Skip to content

pytest-xdist is not reporting the same nodeid as pytest does #445

@elyezer

Description

@elyezer

Running pytest and pytest -n <executors> does not produce the same nodeid for the tests and therefore this is preventing lastfailed from running properly. Since the nodeids in the cache don't match any test collected, it ends up running tests that are not meant to run.

I have the following workflow:

  1. Run the tests that can run in parallel using xdist
  2. Run the tests that need to run serially without using xdist's -n option
  3. Run pytest with the --last-failed option to try rerunning the failures to check if they are flaky. This is again without using xdist's -n option

Here is the reproducer project structure:

$ ls -1R
.:
pytest.cfg
tests

./tests:
api

./tests/api:
__pycache__
test_bar.py
test_foo.py

Here are the file contents:

$ cat tests/api/test_bar.py 
def test_bar_1():
    assert True


def test_bar_2():
    assert True


def test_bar_3():
    assert False

$ cat tests/api/test_foo.py 
import os


def test_foo_fail():
    assert os.environ.get('FOO_PASS', 'false') == 'true'


def test_foo_ok():
    assert True

$ cat pytest.cfg 
[tool:pytest]
python_files = *.py
testpaths = tests/api

Considering the project described above, if you run pytest -n <executors> it shows the following (mind the tests' nodeids):

$ pytest -v --tb=no -c pytest.cfg -n 2
================================ test session starts ================================
platform linux -- Python 3.7.3, pytest-4.6.3, py-1.8.0, pluggy-0.12.0 -- /home/elyezer/.local/venvs/pytest/bin/python3
cachedir: .pytest_cache
rootdir: /home/elyezer/code/xdist-reproducer, inifile: pytest.cfg, testpaths: tests/api
plugins: xdist-1.29.0, forked-1.0.2
[gw0] linux Python 3.7.3 cwd: /home/elyezer/code/xdist-reproducer
[gw1] linux Python 3.7.3 cwd: /home/elyezer/code/xdist-reproducer
[gw0] Python 3.7.3 (default, May 11 2019, 00:38:04)  -- [GCC 9.1.1 20190503 (Red Hat 9.1.1-1)]
[gw1] Python 3.7.3 (default, May 11 2019, 00:38:04)  -- [GCC 9.1.1 20190503 (Red Hat 9.1.1-1)]
gw0 [5] / gw1 [5]
scheduling tests via LoadScheduling

test_bar.py::test_bar_1 
test_bar.py::test_bar_2 
[gw1] [ 20%] PASSED test_bar.py::test_bar_2 
[gw0] [ 40%] PASSED test_bar.py::test_bar_1 
test_bar.py::test_bar_3 
test_foo.py::test_foo_fail 
[gw0] [ 60%] FAILED test_bar.py::test_bar_3 
test_foo.py::test_foo_ok 
[gw0] [ 80%] PASSED test_foo.py::test_foo_ok 
[gw1] [100%] FAILED test_foo.py::test_foo_fail 

======================== 2 failed, 3 passed in 0.32 seconds =========================

But if we run without the -n option here is the output:

$ pytest -v --tb=no -c pytest.cfg     
================================ test session starts ================================
platform linux -- Python 3.7.3, pytest-4.6.3, py-1.8.0, pluggy-0.12.0 -- /home/elyezer/.local/venvs/pytest/bin/python3
cachedir: .pytest_cache
rootdir: /home/elyezer/code/xdist-reproducer, inifile: pytest.cfg, testpaths: tests/api
plugins: xdist-1.29.0, forked-1.0.2
collected 5 items                                                                   

tests/api/test_bar.py::test_bar_1 PASSED                                      [ 20%]
tests/api/test_bar.py::test_bar_2 PASSED                                      [ 40%]
tests/api/test_bar.py::test_bar_3 FAILED                                      [ 60%]
tests/api/test_foo.py::test_foo_fail FAILED                                   [ 80%]
tests/api/test_foo.py::test_foo_ok PASSED                                     [100%]

======================== 2 failed, 3 passed in 0.04 seconds =========================

As you can see both calls has the same rootdir but produce different nodeids for the tests. And if we check the cache for lastfailed:

$ pytest -c pytest.cfg --cache-show=cache/lastfailed
================================ test session starts ================================
platform linux -- Python 3.7.3, pytest-4.6.3, py-1.8.0, pluggy-0.12.0
rootdir: /home/elyezer/code/xdist-reproducer, inifile: pytest.cfg, testpaths: tests/api
plugins: xdist-1.29.0, forked-1.0.2
cachedir: /home/elyezer/code/xdist-reproducer/.pytest_cache
------------------------ cache values for 'cache/lastfailed' ------------------------
cache/lastfailed contains:
  {'test_bar.py::test_bar_3': True,
   'test_foo.py::test_foo_fail': True,
   'tests/api/test_bar.py::test_bar_3': True,
   'tests/api/test_foo.py::test_foo_fail': True}

=========================== no tests ran in 0.00 seconds ============================

pytest-xdist test nodeid generation is not consistent with plain pytest nodeid generation and this inconsistency is breaking plugins such as the lastfailed that relies on the nodeids to do its job.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions