Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 35 additions & 21 deletions launchable/test_runners/pytest.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,27 +264,41 @@ def parse_func(
stderr = ""
longrepr = data.get("longrepr", None)
if longrepr:
message = None
reprcrash = longrepr.get("reprcrash", None)
if reprcrash:
message = reprcrash.get("message", None)

text = None
reprtraceback = longrepr.get("reprtraceback", None)
if reprtraceback:
reprentries = reprtraceback.get("reprentries", None)
if reprentries:
for r in reprentries:
d = r.get("data", None)
if d:
text = "\n".join(d.get("lines", []))

if message and text:
stderr = message + "\n" + text
elif message:
stderr = stderr + message
elif text:
stderr = stderr + text
# https://github.com/pytest-dev/pytest/blob/1d7d63555e431d4562bcacbdc97038b0613d20ba/src/_pytest/reports.py#L60
if isinstance(longrepr, dict):
# https://github.com/pytest-dev/pytest/blob/1d7d63555e431d4562bcacbdc97038b0613d20ba/src/_pytest/reports.py#L361
message = None
reprcrash = longrepr.get("reprcrash", None)
if reprcrash:
message = reprcrash.get("message", None)

text = None
reprtraceback = longrepr.get("reprtraceback", None)
if reprtraceback:
reprentries = reprtraceback.get("reprentries", None)
if reprentries:
for r in reprentries:
d = r.get("data", None)
if d:
text = "\n".join(d.get("lines", []))

if message and text:
stderr = message + "\n" + text
elif message:
stderr = stderr + message
elif text:
stderr = stderr + text
elif isinstance(longrepr, list):
# [path, lineno, messge]
# https://github.com/pytest-dev/pytest/blob/1d7d63555e431d4562bcacbdc97038b0613d20ba/src/_pytest/reports.py#L371
if len(longrepr) == 3:
stderr = longrepr[2]

elif isinstance(longrepr, str):
# When longrepr is a string, it is the same as the stderr.
# https://github.com/pytest-dev/pytest/blob/1d7d63555e431d4562bcacbdc97038b0613d20ba/src/_pytest/reports.py#L377
# https://github.com/pytest-dev/pytest/blob/1d7d63555e431d4562bcacbdc97038b0613d20ba/src/_pytest/nodes.py#L470
stderr = longrepr

test_path = _parse_pytest_nodeid(nodeid)
for path in test_path:
Expand Down
65 changes: 63 additions & 2 deletions tests/test_runners/test_pytest.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import gzip
import json
import os
from unittest import mock
import tempfile
from unittest import TestCase, mock

import responses # type: ignore

from launchable.test_runners.pytest import _parse_pytest_nodeid
from launchable.test_runners.pytest import PytestJSONReportParser, _parse_pytest_nodeid
from tests.cli_test_case import CliTestCase


Expand Down Expand Up @@ -77,3 +78,63 @@ def test_parse_pytest_nodeid(self):
{"type": "class", "name": "tests.fooo.func4_test"},
{"type": "testcase", "name": "test_func6"},
])


class PytestJSONReportParserLongreprTest(TestCase):
class DummyClient:
pass

def setUp(self):
self.parser = PytestJSONReportParser(self.DummyClient())

def _parse_line(self, data):
with tempfile.NamedTemporaryFile(mode="w+", delete=False) as f:
f.write(json.dumps(data) + "\n")
f.flush()
results = list(self.parser.parse_func(f.name))
return results

def _make_event_data(self, longrepr):
return {
"nodeid": "tests/test_sample.py::test_fail",
"when": "call",
"outcome": "failed",
"longrepr": longrepr,
}

def _assert_stderr(self, events, expected_stderr):
self.assertEqual(events[0]["stderr"], expected_stderr)

def test_longrepr_dict_message_and_text(self):
data = self._make_event_data(
{
"reprcrash": {"message": "AssertionError: fail"},
"reprtraceback": {
"reprentries": [{"data": {"lines": ["line1", "line2"]}}]
},
}
)
events = self._parse_line(data)
self._assert_stderr(events, "AssertionError: fail\nline1\nline2")

def test_longrepr_dict_only_message(self):
data = self._make_event_data({"reprcrash": {"message": "Only message"}})
events = self._parse_line(data)
self._assert_stderr(events, "Only message")

def test_longrepr_dict_only_text(self):
data = self._make_event_data(
{"reprtraceback": {"reprentries": [{"data": {"lines": ["text only"]}}]}}
)
events = self._parse_line(data)
self._assert_stderr(events, "text only")

def test_longrepr_list(self):
data = self._make_event_data(["file.py", 10, "list message"])
events = self._parse_line(data)
self._assert_stderr(events, "list message")

def test_longrepr_str(self):
data = self._make_event_data("string message")
events = self._parse_line(data)
self._assert_stderr(events, "string message")