File: conftest.py

package info (click to toggle)
austin 3.7.0-7
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 11,444 kB
  • sloc: ansic: 8,622; python: 2,669; sh: 106; makefile: 54
file content (87 lines) | stat: -rw-r--r-- 2,350 bytes parent folder | download | duplicates (2)
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
import os
import sys
import typing as t
from pathlib import Path
from subprocess import PIPE
from test.cunit import SRC
from test.utils import bt
from test.utils import run
from types import FunctionType

import pytest


class SegmentationFault(Exception):
    pass


class CUnitTestFailure(Exception):
    pass


def pytest_configure(config: pytest.Config) -> None:
    # register an additional marker
    config.addinivalue_line("markers", "exitcode(code): the expected exit code")


def pytest_pycollect_makeitem(
    collector: pytest.Collector, name: str, obj: t.Any
) -> None:
    if (
        not os.getenv("PYTEST_CUNIT")
        and isinstance(obj, FunctionType)
        and name.startswith("test_")
    ):
        obj.__cunit__ = (str(collector.fspath), name)


def cunit(
    module: str, name: str, full_name: str, exit_code: int = 0
) -> t.Callable[[t.Any, t.Any], None]:
    def _(*_, **__):
        test = f"{module}::{name}"
        env = os.environ.copy()
        env["PYTEST_CUNIT"] = full_name

        result = run(
            [sys.executable, "-m", "pytest", "-svv", test],
            stdout=PIPE,
            stderr=PIPE,
            env=env,
        )

        if result.returncode == exit_code:
            return

        if result.returncode == -11:
            binary_name = Path(module).stem.replace("test_", "")
            raise SegmentationFault(
                bt((SRC / binary_name).with_suffix(".so"), result.pid)
            )

        raise CUnitTestFailure(
            f"\n{result.stdout.decode()}\n"
            f"Process terminated with exit code {result.returncode} "
            "(expected {exit_code})"
        )

    return _


def pytest_collection_modifyitems(
    session: pytest.Session,
    config: pytest.Config,
    items: list[pytest.Item],
) -> None:
    if test_name := os.getenv("PYTEST_CUNIT"):
        # We are inside the sandbox process. We select the only test we care
        items[:] = [_ for _ in items if _.name == test_name]
        return

    for item in items:
        if hasattr(item._obj, "__cunit__"):
            exit_code_marker = list(item.iter_markers(name="exitcode"))
            exit_code = exit_code_marker[0].args[0] if exit_code_marker else 0
            item._obj = cunit(
                *item._obj.__cunit__, full_name=item.name, exit_code=exit_code
            )