Fix the issue when memoryview obj gets to subunit parser

Change-Id: I26bf6a5847d1852ebd3badbb976320a01c49aa86
This commit is contained in:
Andrey Kurilin
2023-11-29 15:56:48 +01:00
parent 0334380d36
commit 46afd01f5f
3 changed files with 48 additions and 61 deletions

View File

@@ -20,6 +20,12 @@ Changelog
[unreleased] [unreleased]
------------ ------------
Fixed
~~~~~
* Parsing subunit v2 stream (rally-verify component) when the result is
wrapped by ``memoryview`` python object.
Added Added
~~~~~ ~~~~~

View File

@@ -25,33 +25,22 @@ _IGNORE_LIST = [
] ]
def prepare_input_args(func): class TestID(str):
# NOTE(andreykurilin): Variables 'runnable', 'eof', 'route_code' are not
# used in parser.
def inner(self, test_id=None, test_status=None, timestamp=None,
file_name=None, file_bytes=None, mime_type=None, test_tags=None,
runnable=True, eof=False, route_code=None):
if not test_id or test_id in _IGNORE_LIST:
return
if (test_id.startswith("setUpClass (") @staticmethod
or test_id.startswith("tearDown (")): def __new__(cls, value):
test_id = test_id[test_id.find("(") + 1:-1] if (value.startswith("setUpClass (")
or value.startswith("tearDown (")):
value = value[value.find("(") + 1:-1]
return super(TestID, cls).__new__(cls, value)
tags = _parse_test_tags(test_id) def __init__(self, value):
if self.find("[") > -1:
func(self, test_id, test_status, timestamp, tags, self.name, tags = self.split("[", 1)
file_name, file_bytes, test_tags, mime_type) self.tags = tags[:-1].split(",")
else:
return inner self.name = value
self.tags = []
def _parse_test_tags(test_id):
tags = []
if test_id.find("[") > -1:
tags = test_id.split("[")[1][:-1].split(",")
return tags
class SubunitV2StreamResult(object): class SubunitV2StreamResult(object):
@@ -75,13 +64,9 @@ class SubunitV2StreamResult(object):
self._unknown_entities = {} self._unknown_entities = {}
self._is_parsed = False self._is_parsed = False
@staticmethod def _check_expected_failure(self, test_id: TestID):
def _get_test_name(test_id):
return test_id.split("[")[0] if test_id.find("[") > -1 else test_id
def _check_expected_failure(self, test_id):
if (test_id in self._expected_failures if (test_id in self._expected_failures
or self._get_test_name(test_id) in self._expected_failures): or test_id.name in self._expected_failures):
if self._tests[test_id]["status"] == "fail": if self._tests[test_id]["status"] == "fail":
self._tests[test_id]["status"] = "xfail" self._tests[test_id]["status"] = "xfail"
if self._expected_failures[test_id]: if self._expected_failures[test_id]:
@@ -94,16 +79,16 @@ class SubunitV2StreamResult(object):
for t_id in self._skipped_tests.copy(): for t_id in self._skipped_tests.copy():
if t_id not in self._tests: if t_id not in self._tests:
status = "skip" status = "skip"
name = self._get_test_name(t_id) t_id = TestID(t_id)
self._tests[t_id] = {"status": status, self._tests[t_id] = {"status": status,
"name": name, "name": t_id.name,
"duration": "%.3f" % 0, "duration": "%.3f" % 0,
"tags": _parse_test_tags(t_id)} "tags": t_id.tags}
if self._skipped_tests[t_id]: if self._skipped_tests[t_id]:
self._tests[t_id]["reason"] = self._skipped_tests[t_id] self._tests[t_id]["reason"] = self._skipped_tests[t_id]
status += ": %s" % self._tests[t_id]["reason"] status += ": %s" % self._tests[t_id]["reason"]
if self._live: if self._live:
self._logger.info("{-} %s ... %s" % (name, status)) self._logger.info("{-} %s ... %s" % (t_id.name, status))
self._skipped_tests.pop(t_id) self._skipped_tests.pop(t_id)
@@ -158,9 +143,17 @@ class SubunitV2StreamResult(object):
"unexpected_success": len(self.filter_tests("uxsuccess")), "unexpected_success": len(self.filter_tests("uxsuccess")),
"expected_failures": len(self.filter_tests("xfail"))} "expected_failures": len(self.filter_tests("xfail"))}
@prepare_input_args def status(self, test_id=None, test_status=None, timestamp=None,
def status(self, test_id=None, test_status=None, timestamp=None, tags=None, file_name=None, file_bytes=None, mime_type=None, test_tags=None,
file_name=None, file_bytes=None, worker=None, mime_type=None): runnable=True, eof=False, route_code=None):
if not test_id or test_id in _IGNORE_LIST:
return
test_id = TestID(test_id)
if isinstance(file_bytes, memoryview):
file_bytes = file_bytes.tobytes()
if timestamp: if timestamp:
if not self._first_timestamp: if not self._first_timestamp:
self._first_timestamp = timestamp self._first_timestamp = timestamp
@@ -168,9 +161,9 @@ class SubunitV2StreamResult(object):
if test_status == "exists": if test_status == "exists":
self._tests[test_id] = {"status": "init", self._tests[test_id] = {"status": "init",
"name": self._get_test_name(test_id), "name": test_id.name,
"duration": "%.3f" % 0, "duration": "%.3f" % 0,
"tags": tags if tags else []} "tags": test_id.tags}
elif test_id in self._tests: elif test_id in self._tests:
if test_status == "inprogress": if test_status == "inprogress":
# timestamp of test start # timestamp of test start
@@ -219,9 +212,8 @@ class SubunitV2StreamResult(object):
if reason: if reason:
status += ": %s" % reason status += ": %s" % reason
w = "{%s} " % worker.pop().split("-")[1] if worker else "-" w = "{%s} " % test_tags.pop().split("-")[1] if test_tags else "-"
self._logger.info("%s ... %s" self._logger.info(f"{w}{test_id.name} ... {status}")
% (w + self._get_test_name(test_id), status))
def filter_tests(self, status): def filter_tests(self, status):
"""Filter tests by given status.""" """Filter tests by given status."""

View File

@@ -12,7 +12,6 @@
# under the License. # under the License.
import os import os
from unittest import mock
from rally.common.io import subunit_v2 from rally.common.io import subunit_v2
from tests.unit import test from tests.unit import test
@@ -93,23 +92,6 @@ RuntimeError: broken setUp method
self.assertTrue(results._is_parsed) self.assertTrue(results._is_parsed)
def test_prepare_input_args(self):
some_mock = mock.MagicMock()
@subunit_v2.prepare_input_args
def some_a(self_, test_id, test_status, timestamp, test_tags,
file_name, file_bytes, worker, mime_type):
some_mock(test_id, test_tags)
some_a("", "setUpClass (some_test[tag1,tag2])")
some_mock.assert_called_once_with(
"some_test[tag1,tag2]", ["tag1", "tag2"])
some_mock.reset_mock()
some_a("", "tearDown (some_test[tag1,tag2])")
some_mock.assert_called_once_with(
"some_test[tag1,tag2]", ["tag1", "tag2"])
def test_no_status_called(self): def test_no_status_called(self):
self.assertEqual({"tests_count": 0, "tests_duration": "%.3f" % 0, self.assertEqual({"tests_count": 0, "tests_duration": "%.3f" % 0,
"failures": 0, "skipped": 0, "success": 0, "failures": 0, "skipped": 0, "success": 0,
@@ -144,3 +126,10 @@ RuntimeError: broken setUp method
self.assertEqual("skip", tests[test_id]["status"]) self.assertEqual("skip", tests[test_id]["status"])
self.assertEqual("Some details why this test skipped", self.assertEqual("Some details why this test skipped",
tests[test_id]["reason"]) tests[test_id]["reason"])
class TestIDTestCase(test.TestCase):
def test_id_processing(self):
value = subunit_v2.TestID("setUpClass (some_test[tag1,tag2])")
self.assertEqual("some_test", value.name)
self.assertEqual(["tag1", "tag2"], value.tags)