File: test_xfail_behavior.py

package info (click to toggle)
pytest-forked 1.6.0-5
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 220 kB
  • sloc: python: 283; makefile: 6; sh: 4
file content (123 lines) | stat: -rw-r--r-- 4,404 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
"""Tests for xfail support."""
import os
import signal

import pytest

IS_PYTEST4_PLUS = int(pytest.__version__[0]) >= 4  # noqa: WPS609
FAILED_WORD = "FAILED" if IS_PYTEST4_PLUS else "FAIL"
PYTEST_GTE_7_2 = hasattr(pytest, "version_tuple") and pytest.version_tuple >= (7, 2)  # type: ignore[attr-defined]
PYTEST_GTE_8_0 = hasattr(pytest, "version_tuple") and pytest.version_tuple >= (8, 0)  # type: ignore[attr-defined]
PYTEST_GTE_9_0 = hasattr(pytest, "version_tuple") and pytest.version_tuple >= (9, 0)  # type: ignore[attr-defined]

pytestmark = pytest.mark.skipif(  # pylint: disable=invalid-name
    not hasattr(os, "fork"),  # noqa: WPS421
    reason="os.fork required",
)


@pytest.mark.parametrize(
    ("is_crashing", "is_strict"),
    (
        pytest.param(True, True, id="strict xfail"),
        pytest.param(False, True, id="strict xpass"),
        pytest.param(True, False, id="non-strict xfail"),
        pytest.param(False, False, id="non-strict xpass"),
    ),
)
def test_xfail(is_crashing, is_strict, testdir):
    """Test xfail/xpass/strict permutations."""
    # pylint: disable=possibly-unused-variable
    sig_num = signal.SIGTERM.numerator

    test_func_body = (
        "os.kill(os.getpid(), signal.SIGTERM)" if is_crashing else "assert True"
    )

    if is_crashing:
        # marked xfailed and crashing, no matter strict or not
        expected_letter = "x"  # XFAILED
        expected_lowercase = "xfailed"
        expected_word = "XFAIL"
    elif is_strict:
        # strict and not failing as expected should cause failure
        expected_letter = "F"  # FAILED
        expected_lowercase = "failed"
        expected_word = FAILED_WORD
    elif not is_strict:
        # non-strict and not failing as expected should cause xpass
        expected_letter = "X"  # XPASS
        expected_lowercase = "xpassed"
        expected_word = "XPASS"

    session_start_title = "*==== test session starts ====*"
    loaded_pytest_plugins = "plugins:* forked*"
    collected_tests_num = "collected 1 item"
    expected_progress = f"test_xfail.py {expected_letter!s}*"
    failures_title = "*==== FAILURES ====*"
    failures_test_name = "*____ test_function ____*"
    failures_test_reason = "[XPASS(strict)] The process gets terminated"
    short_test_summary_title = "*==== short test summary info ====*"
    short_test_summary = f"{expected_word!s} test_xfail.py::test_function"
    if expected_lowercase == "xpassed":
        # XPASS wouldn't have the crash message from
        # pytest-forked because the crash doesn't happen
        if PYTEST_GTE_8_0:
            short_test_summary += " -"
        short_test_summary += " The process gets terminated"

    reason_string = (
        f"reason: The process gets terminated; "
        f"pytest-forked reason: "
        f"*:*: running the test CRASHED with signal {sig_num:d}"
    )
    if expected_lowercase == "xfailed" and PYTEST_GTE_7_2:
        short_test_summary += " - " + reason_string
    if expected_lowercase == "failed" and PYTEST_GTE_9_0:
        short_test_summary += " - [XPASS(strict)] The process gets termin..."
    total_summary_line = f"*==== 1 {expected_lowercase!s} in 0.*s* ====*"

    expected_lines = (
        session_start_title,
        loaded_pytest_plugins,
        collected_tests_num,
        expected_progress,
    )
    if expected_word == FAILED_WORD:
        # XPASS(strict)
        expected_lines += (
            failures_title,
            failures_test_name,
            failures_test_reason,
        )
    expected_lines += (
        short_test_summary_title,
        short_test_summary,
    )
    if expected_lowercase == "xpassed" and expected_word == FAILED_WORD:
        # XPASS(strict)
        expected_lines += ("  " + reason_string,)
    expected_lines += (total_summary_line,)

    test_module = testdir.makepyfile(
        f"""
        import os
        import signal

        import pytest

        # The current implementation emits RuntimeWarning.
        pytestmark = pytest.mark.filterwarnings('ignore:pytest-forked xfail')

        @pytest.mark.xfail(
            reason='The process gets terminated',
            strict={is_strict!s},
        )
        @pytest.mark.forked
        def test_function():
            {test_func_body!s}
        """
    )

    pytest_run_result = testdir.runpytest(test_module, "-ra")
    pytest_run_result.stdout.fnmatch_lines(expected_lines)