pytest-dev / pytest-dev/pytest-xdist

xdist causes duplicate reports for collector errors

Open
#1,140 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
1.9k
Forks
287
Avg merge
9h 30m
Merged PRs (30d)
2

Description

hi,

when running pytest with --numprocesses=4 (or any non 0 number) if you generate an xml or json report using the json plugin and some of the modules fail during collection, xdist will cause pytest to generate a collector error for the same file for each worker. ex.: 4 processes will cause 4 entries for each failed collection, 2 processes -> 2 entries per failed collection etc.

json example when using --numprocesses=4

    "collectors": [
        {
            "nodeid": "tests/test_other2.py",
            "outcome": "failed",
            "result": [],
            "longrepr": "<stacktrace message>"
        },
        {
            "nodeid": "tests/test_other2.py",
            "outcome": "failed",
            "result": [],
            "longrepr": "<stacktrace message>"
        },
        {
            "nodeid": "tests/test_other2.py",
            "outcome": "failed",
            "result": [],
            "longrepr": "<stacktrace message>"
        },
        {
            "nodeid": "tests/test_other2.py",
            "outcome": "failed",
            "result": [],
            "longrepr": "<stacktrace message>"
        }
    ]

correct output when using --numprocesses=0

    "collectors": [
        {
            "nodeid": "",
            "outcome": "passed",
            "result": [
                {
                    "nodeid": "tests/test_other2.py",
                    "type": "Module"
                }
            ]
        },
        {
            "nodeid": "tests/test_other2.py",
            "outcome": "failed",
            "result": [],
            "longrepr": "<stacktrace>"
        }
    ],

also, when running using json report, normally the collectors key should be added for all collected files but when using xdist only failed collections get added.

example with --numprocesses=4 and 2 files: 1 that fails during collection and 1 that doesn't. notice how none of the successful collections show up and the failed collection shows up 4 times.

    "collectors": [
        {
            "nodeid": "tests/test_other2.py",
            "outcome": "failed",
            "result": [],
            "longrepr": "<stacktrace message>"
        },
        {
            "nodeid": "tests/test_other2.py",
            "outcome": "failed",
            "result": [],
            "longrepr": "<stacktrace message>"
        },
        {
            "nodeid": "tests/test_other2.py",
            "outcome": "failed",
            "result": [],
            "longrepr": "<stacktrace message>"
        },
        {
            "nodeid": "tests/test_other2.py",
            "outcome": "failed",
            "result": [],
            "longrepr": "<stacktrace message>"
        }
    ]

correct output: when using --numprocesses=0 all collected items are shown including the successful ones and the failed collections only show once per file.

    "collectors": [
        {
            "nodeid": "",
            "outcome": "passed",
            "result": [
                {
                    "nodeid": "tests/test_other.py",
                    "type": "Module"
                },
                {
                    "nodeid": "tests/test_other2.py",
                    "type": "Module"
                }
            ]
        },
        {
            "nodeid": "tests/test_other.py",
            "outcome": "passed",
            "result": [
                {
                    "nodeid": "tests/test_other.py::test_skipped",
                    "type": "Function",
                    "lineno": 3
                },
                {
                    "nodeid": "tests/test_other.py::test_will_pass",
                    "type": "Function",
                    "lineno": 9
                },
                {
                    "nodeid": "tests/test_other.py::test_will_fail",
                    "type": "Function",
                    "lineno": 15
                },
                {
                    "nodeid": "tests/test_other.py::test_will_xfail",
                    "type": "Function",
                    "lineno": 29
                },
                {
                    "nodeid": "tests/test_other.py::test_will_xpass",
                    "type": "Function",
                    "lineno": 36
                },
                {
                    "nodeid": "tests/test_other.py::test_fixture_exception",
                    "type": "Function",
                    "lineno": 43
                },
                {
                    "nodeid": "tests/test_other.py::test_fixture_missing",
                    "type": "Function",
                    "lineno": 49
                }
            ]
        },
        {
            "nodeid": "tests/test_other2.py",
            "outcome": "failed",
            "result": [],
            "longrepr": "<stacktrace>"
        }
    ],

to cause a collection error you can raise an exception at the top of the file or you can import a class that raises an exception inside its __init__ method.

raise Exception("testing expection from module")


def test_import_exception(session_id: str):
    print(session_id)
    assert True
    return

or

from some.folder import InvalidImport


def test_import_exception(session_id: str):
    print(session_id)
    assert True
    return

# some.folder
class InvalidImport:

    raise Exception("testing exception from import")

this affects the pytest xml as well in that the failed collections get printed there multiple times as well, the difference being that xml doesn't have a collectors section, so no successful collections show up.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the issue with pytest-xdist using --numprocesses greater than 0, a collection-time exception, and XML or JSON reporting. Compare the reports with --numprocesses=0, then trace how collection results and errors are combined. Done means each failed collection appears once and successful collections are included when xdist is enabled.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
distributed-systems, testing-qa
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.