pytest-testinel 0.1.0__py3-none-any.whl → 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pytest_testinel/results_reporter.py +26 -2
- pytest_testinel/testinel.py +21 -8
- {pytest_testinel-0.1.0.dist-info → pytest_testinel-0.2.0.dist-info}/METADATA +18 -1
- pytest_testinel-0.2.0.dist-info/RECORD +8 -0
- {pytest_testinel-0.1.0.dist-info → pytest_testinel-0.2.0.dist-info}/WHEEL +2 -2
- pytest_testinel-0.1.0.dist-info/RECORD +0 -8
- {pytest_testinel-0.1.0.dist-info → pytest_testinel-0.2.0.dist-info}/entry_points.txt +0 -0
- {pytest_testinel-0.1.0.dist-info → pytest_testinel-0.2.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import abc, datetime, json, uuid
|
|
1
|
+
import abc, datetime, json, os, uuid
|
|
2
|
+
from urllib.parse import unquote, urlparse
|
|
2
3
|
|
|
3
4
|
import requests
|
|
4
5
|
|
|
@@ -14,6 +15,11 @@ class ReportingBackend(abc.ABC):
|
|
|
14
15
|
return
|
|
15
16
|
|
|
16
17
|
|
|
18
|
+
class NoopReportingBackend(ReportingBackend):
|
|
19
|
+
def record_event(self, event: dict) -> None:
|
|
20
|
+
return
|
|
21
|
+
|
|
22
|
+
|
|
17
23
|
class FileReportingBackend(ReportingBackend):
|
|
18
24
|
events: list[dict]
|
|
19
25
|
filename: str
|
|
@@ -55,7 +61,25 @@ class ResultsReporter:
|
|
|
55
61
|
if backend:
|
|
56
62
|
self.backend = backend
|
|
57
63
|
else:
|
|
58
|
-
self.backend =
|
|
64
|
+
self.backend = self._backend_from_dsn(dsn)
|
|
65
|
+
|
|
66
|
+
def _backend_from_dsn(self, dsn: str) -> ReportingBackend:
|
|
67
|
+
parsed = urlparse(dsn)
|
|
68
|
+
if parsed.scheme in {"http", "https"}:
|
|
69
|
+
return HttpReportingBackend(url=dsn)
|
|
70
|
+
if parsed.scheme == "file":
|
|
71
|
+
if parsed.netloc:
|
|
72
|
+
raise ValueError(
|
|
73
|
+
"Unsupported file DSN with host component. Use file:///path/to/file."
|
|
74
|
+
)
|
|
75
|
+
filename = unquote(parsed.path)
|
|
76
|
+
return FileReportingBackend(filename=filename)
|
|
77
|
+
if parsed.scheme == "":
|
|
78
|
+
return FileReportingBackend(filename=os.fspath(dsn))
|
|
79
|
+
raise ValueError(
|
|
80
|
+
f"Unsupported TESTINEL_DSN scheme '{parsed.scheme}'. "
|
|
81
|
+
"Use https://... or file:///path/to/file."
|
|
82
|
+
)
|
|
59
83
|
|
|
60
84
|
def report_start(self, payload: dict) -> None:
|
|
61
85
|
self.backend.on_start()
|
pytest_testinel/testinel.py
CHANGED
|
@@ -7,7 +7,7 @@ from typing import Callable, Generator, Any, Final, Set
|
|
|
7
7
|
import pytest
|
|
8
8
|
from _pytest._code.code import ExceptionChainRepr
|
|
9
9
|
|
|
10
|
-
from .results_reporter import ResultsReporter
|
|
10
|
+
from .results_reporter import NoopReportingBackend, ResultsReporter
|
|
11
11
|
|
|
12
12
|
ENV_VAR_WHITELIST: Final[Set] = {
|
|
13
13
|
"CI",
|
|
@@ -33,9 +33,22 @@ ENV_VAR_WHITELIST: Final[Set] = {
|
|
|
33
33
|
"BITBUCKET_STEP_RUN_NUMBER",
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
_test_reporter: ResultsReporter | None = None
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _get_test_reporter() -> ResultsReporter:
|
|
40
|
+
global _test_reporter
|
|
41
|
+
if _test_reporter is None:
|
|
42
|
+
dsn = os.environ.get("TESTINEL_DSN")
|
|
43
|
+
if not dsn:
|
|
44
|
+
_test_reporter = ResultsReporter(
|
|
45
|
+
dsn="",
|
|
46
|
+
backend=NoopReportingBackend(),
|
|
47
|
+
)
|
|
48
|
+
else:
|
|
49
|
+
_test_reporter = ResultsReporter(dsn=dsn)
|
|
50
|
+
return _test_reporter
|
|
51
|
+
|
|
39
52
|
|
|
40
53
|
def serialize_repr(long_repr: ExceptionChainRepr) -> dict:
|
|
41
54
|
return asdict(long_repr)
|
|
@@ -86,7 +99,7 @@ def pytest_runtest_makereport(
|
|
|
86
99
|
|
|
87
100
|
repr_info = serialize_repr(report.longrepr)
|
|
88
101
|
|
|
89
|
-
|
|
102
|
+
_get_test_reporter().report_event(
|
|
90
103
|
event=report.when,
|
|
91
104
|
payload={
|
|
92
105
|
"test": to_test_dict(item),
|
|
@@ -114,7 +127,7 @@ def pytest_runtest_makereport(
|
|
|
114
127
|
@pytest.fixture(scope="session", autouse=True)
|
|
115
128
|
def reporter(request):
|
|
116
129
|
config = request.config
|
|
117
|
-
|
|
130
|
+
_get_test_reporter().report_start(
|
|
118
131
|
payload={
|
|
119
132
|
"args": config.args,
|
|
120
133
|
"options": vars(config.option),
|
|
@@ -124,9 +137,9 @@ def reporter(request):
|
|
|
124
137
|
}
|
|
125
138
|
)
|
|
126
139
|
yield
|
|
127
|
-
|
|
140
|
+
_get_test_reporter().report_end()
|
|
128
141
|
|
|
129
142
|
|
|
130
143
|
def pytest_collection_finish(session):
|
|
131
144
|
tests = [to_test_dict(item) for item in session.items]
|
|
132
|
-
|
|
145
|
+
_get_test_reporter().tests = tests
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pytest-testinel
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Testinel’s pytest plugin captures structured test execution data directly from pytest and sends it to Testinel, where your test results become searchable, comparable, and actually useful.
|
|
5
5
|
Author: Volodymyr Obrizan
|
|
6
6
|
Author-email: Volodymyr Obrizan <obrizan@first.institute>
|
|
@@ -38,3 +38,20 @@ pip install --upgrade pytest-testinel
|
|
|
38
38
|
### Configuration
|
|
39
39
|
|
|
40
40
|
Set Testinel reporter DSN environment variable `TESTINEL_DSN`.
|
|
41
|
+
|
|
42
|
+
Examples:
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
# Report to Testinel (HTTPS)
|
|
46
|
+
export TESTINEL_DSN="https://your.testinel.endpoint/ingest"
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
# Report to a local file (JSON)
|
|
51
|
+
export TESTINEL_DSN="file:///tmp/testinel-results.json"
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
# Or use a direct file path
|
|
56
|
+
export TESTINEL_DSN="./testinel-results.json"
|
|
57
|
+
```
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
pytest_testinel/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
pytest_testinel/results_reporter.py,sha256=HSLdSumSjHswJ2oVbVLVMKVk1dY8sxaGKGfVtp977ic,3283
|
|
3
|
+
pytest_testinel/testinel.py,sha256=pIA05QYyqAex5Vn9NEsApBRi7rDIbYtnsKTfX4l3rT0,4152
|
|
4
|
+
pytest_testinel-0.2.0.dist-info/licenses/LICENSE,sha256=g-9SNaCTpjdaj63-SMa03OHuKdcZXsXk4cRKZcLfD1c,1065
|
|
5
|
+
pytest_testinel-0.2.0.dist-info/WHEEL,sha256=XV0cjMrO7zXhVAIyyc8aFf1VjZ33Fen4IiJk5zFlC3g,80
|
|
6
|
+
pytest_testinel-0.2.0.dist-info/entry_points.txt,sha256=-vjKXhLEcZLenCKBgXoFNmlNc5DM7qI04yqsDUWH-Ok,49
|
|
7
|
+
pytest_testinel-0.2.0.dist-info/METADATA,sha256=WAPX_4BvsMSjj5DNQB7UgwHF2fdEVeC8nUH7p5Gdhrc,1903
|
|
8
|
+
pytest_testinel-0.2.0.dist-info/RECORD,,
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
pytest_testinel/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
pytest_testinel/results_reporter.py,sha256=IGf2dLK3Po3G_KNkYxZVo7PoKXq66gKP8nxe_NhP0ko,2369
|
|
3
|
-
pytest_testinel/testinel.py,sha256=nG2DDgDhVNF4vUQx84BCxq8SmKrrNu1PNtIj4uWphYs,3731
|
|
4
|
-
pytest_testinel-0.1.0.dist-info/licenses/LICENSE,sha256=g-9SNaCTpjdaj63-SMa03OHuKdcZXsXk4cRKZcLfD1c,1065
|
|
5
|
-
pytest_testinel-0.1.0.dist-info/WHEEL,sha256=RRVLqVugUmFOqBedBFAmA4bsgFcROUBiSUKlERi0Hcg,79
|
|
6
|
-
pytest_testinel-0.1.0.dist-info/entry_points.txt,sha256=-vjKXhLEcZLenCKBgXoFNmlNc5DM7qI04yqsDUWH-Ok,49
|
|
7
|
-
pytest_testinel-0.1.0.dist-info/METADATA,sha256=UUKD5yaMfgChwXVkV5yQs_EJ8P2cJ1EDAg5AAwfpFW8,1614
|
|
8
|
-
pytest_testinel-0.1.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|