diff --git a/tests/unit/test_base.py b/tests/unit/test_base.py index 80fbe84000..355212832f 100644 --- a/tests/unit/test_base.py +++ b/tests/unit/test_base.py @@ -8,6 +8,7 @@ import tmt import tmt.cli +import tmt.result from tests import CliRunner from tmt.base import FmfId, Link, LinkNeedle, Links, expand_node_data from tmt.utils import Path, SpecificationError @@ -41,7 +42,7 @@ def test_test_defaults(root_logger): assert test.environment == {} assert test.duration == '5m' assert test.enabled is True - assert test.result == 'respect' + assert test.result == tmt.result.ResultInterpret.RESPECT assert test.tag == [] diff --git a/tmt/base.py b/tmt/base.py index c7350fc70f..874c1b70f5 100644 --- a/tmt/base.py +++ b/tmt/base.py @@ -57,7 +57,7 @@ import tmt.utils.jira from tmt.checks import Check from tmt.lint import LinterOutcome, LinterReturn -from tmt.result import Result +from tmt.result import Result, ResultInterpret from tmt.utils import ( Command, Environment, @@ -1074,7 +1074,12 @@ class Test( exporter=lambda environment: environment.to_fmf_spec()) duration: str = DEFAULT_TEST_DURATION_L1 - result: str = 'respect' + result: ResultInterpret = field( + default=ResultInterpret.RESPECT, + normalize=ResultInterpret.normalize, + serialize=lambda result: result.value, + unserialize=ResultInterpret.from_spec, + exporter=lambda result: result.value) where: list[str] = field(default_factory=list) @@ -1353,6 +1358,9 @@ def show(self) -> None: [check.to_spec() for check in cast(list[Check], value)] )) continue + if key == 'result': + echo(tmt.utils.format(key, value.value)) + continue if value not in [None, [], {}]: echo(tmt.utils.format(key, value)) if self.verbosity_level: diff --git a/tmt/result.py b/tmt/result.py index 62037791f1..546346afa6 100644 --- a/tmt/result.py +++ b/tmt/result.py @@ -8,6 +8,7 @@ import fmf.utils import tmt.identifier +import tmt.log import tmt.utils from tmt.checks import CheckEvent from tmt.utils import GeneralError, Path, SerializableContainer, field @@ -50,13 +51,36 @@ class ResultInterpret(enum.Enum): # Special interpret values RESPECT = 'respect' - CUSTOM = 'custom' XFAIL = 'xfail' + CUSTOM = 'custom' + RESTRAINT = 'restraint' @classmethod def is_result_outcome(cls, value: 'ResultInterpret') -> bool: return value.name in list(ResultOutcome.__members__.keys()) + @classmethod + def from_spec(cls, spec: str) -> 'ResultInterpret': + try: + return ResultInterpret(spec) + except ValueError: + raise tmt.utils.SpecificationError(f"Invalid result interpretation '{spec}'.") + + @classmethod + def normalize( + cls, + key_address: str, + value: Any, + logger: tmt.log.Logger) -> 'ResultInterpret': + if isinstance(value, ResultInterpret): + return value + + if isinstance(value, str): + return cls.from_spec(value) + + raise tmt.utils.SpecificationError( + f"Invalid result interpretation '{value}' at {key_address}.") + RESULT_OUTCOME_COLORS: dict[ResultOutcome, str] = { ResultOutcome.PASS: 'green', @@ -296,8 +320,7 @@ def from_test_invocation( guest=ResultGuestData.from_test_invocation(invocation=invocation), data_path=invocation.relative_test_data_path) - return _result.interpret_result(ResultInterpret( - invocation.test.result) if invocation.test.result else ResultInterpret.RESPECT) + return _result.interpret_result(invocation.test.result) def interpret_result(self, interpret: ResultInterpret) -> 'Result': """ diff --git a/tmt/steps/execute/__init__.py b/tmt/steps/execute/__init__.py index e007bf331a..a5f18da10c 100644 --- a/tmt/steps/execute/__init__.py +++ b/tmt/steps/execute/__init__.py @@ -22,7 +22,7 @@ from tmt.checks import CheckEvent from tmt.options import option from tmt.plugins import PluginRegistry -from tmt.result import CheckResult, Result, ResultGuestData, ResultOutcome +from tmt.result import CheckResult, Result, ResultGuestData, ResultInterpret, ResultOutcome from tmt.steps import Action, ActionTask, PhaseQueue, PluginTask, Step from tmt.steps.discover import Discover, DiscoverPlugin, DiscoverStepData from tmt.steps.provision import Guest @@ -895,11 +895,11 @@ def extract_results( self.debug(f"Extract results of '{invocation.test.name}'.") - if invocation.test.result == 'custom': + if invocation.test.result == ResultInterpret.CUSTOM: return self.extract_custom_results(invocation) # Handle the 'tmt-report-result' command results as separate tests - if invocation.test.result == 'restraint': + if invocation.test.result == ResultInterpret.RESTRAINT: return self.extract_tmt_report_results_restraint( invocation=invocation, default_log=invocation.relative_path / TEST_OUTPUT_FILENAME)