Add store_result common attribute to test items

Allows any test item to store its result (or PASS/FAIL status when result
is None) into a named global variable, available to subsequent items via
$(variable_name). store_result runs after expected_result but before
no_fail so the real outcome is always captured.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-20 22:26:47 +02:00
parent 95912dd3e1
commit 276d485905
3 changed files with 140 additions and 1 deletions

View File

@@ -87,6 +87,10 @@ if not provided is given in the table as well.
| | | see :ref:`Expected result<sec_expected_result>` | | | | see :ref:`Expected result<sec_expected_result>` |
| | | for details. | | | | for details. |
+-----------------------+-------------------+-------------------------------------------------------+ +-----------------------+-------------------+-------------------------------------------------------+
| ``store_result`` | / | Store the test result in a global variable. |
| | | see :ref:`Store result<sec_store_result>` |
| | | for details. |
+-----------------------+-------------------+-------------------------------------------------------+
last test result last test result
@@ -183,6 +187,61 @@ If the result and the expected_result is equal, the test will be *PASSED* if ``T
The special ``$(result)`` variable is replaced in the ``expected_result`` attribute content with the test result value. The special ``$(result)`` variable is replaced in the ``expected_result`` attribute content with the test result value.
.. _sec_store_result:
Store result
-----------------------------------------------
The ``store_result`` attribute stores the test result into a named global variable,
making it available to subsequent test items via ``$(variable_name)``.
If the test item returns a value (e.g. ``py_func``, ``json_rpc``), that value is stored.
If ``process_result`` is also specified, the stored value is the post-processed result.
If the test item produces no value (result is ``None``), the stored value is the
test status string: ``"PASS"`` or ``"FAIL"``, evaluated after ``expected_result``
but **before** ``no_fail``. This ensures the real outcome is captured even when
``no_fail: True`` would otherwise mask a failure.
.. code-block:: yaml
:caption: Store a function return value
- py_func:
name: Read sensor
func_name: read_temperature
store_result: temperature
- py_func:
name: Check temperature in range
func_name: check_range
param: [$(temperature), 20, 30]
.. code-block:: yaml
:caption: Store a post-processed value
- py_func:
name: Get firmware version string
func_name: get_version
process_result: "'$(result)'.split('.')[0]"
store_result: fw_major
.. code-block:: yaml
:caption: Store the pass/fail status of a test with no return value
- console:
name: Send command
console_name: device
steps:
- writeln: reboot
- read_until: {expected: "ready", timeout: 10}
store_result: reboot_status
- py_func:
name: Use reboot status
func_name: log_status
param: [$(reboot_status)]
Export attribute Export attribute
----------------------------------------------- -----------------------------------------------

View File

@@ -101,6 +101,7 @@ class TestItem:
self.status_queue = status_queue self.status_queue = status_queue
self._execute_on_stop = False self._execute_on_stop = False
self._post_eval = None self._post_eval = None
self._store_result = None
self._expected_result = None self._expected_result = None
self._no_fail = None self._no_fail = None
self._is_stopped = False self._is_stopped = False
@@ -155,6 +156,9 @@ class TestItem:
if "process_result" in dict_item: if "process_result" in dict_item:
self._post_eval = dict_item["process_result"] self._post_eval = dict_item["process_result"]
if "store_result" in dict_item:
self._store_result = dict_item["store_result"]
if "expected_result" in dict_item: if "expected_result" in dict_item:
self._expected_result = dict_item["expected_result"] self._expected_result = dict_item["expected_result"]
@@ -277,6 +281,9 @@ class TestItem:
self.process_result() self.process_result()
# expected_result treatment # expected_result treatment
self.result_expected() self.result_expected()
# Store result in a global variable if requested (before no_fail so
# the real outcome is captured when result.value is None)
self.store_result()
# Case of the no_fail true parameter # Case of the no_fail true parameter
self.process_no_fail() self.process_no_fail()
@@ -319,6 +326,17 @@ class TestItem:
print(e) print(e)
self.result.set(TestValue.FAILURE, "Result processing failed") self.result.set(TestValue.FAILURE, "Result processing failed")
def store_result(self):
if self._store_result is None:
return
var_name = self._prms.expanse(self._store_result)
if self.result.value is None:
value = str(self.result.test_result)
else:
value = self.result.value
tm.setgd(var_name, value)
print(f"Stored result in '$({var_name})': {value}")
def process_report(self, report_eval): def process_report(self, report_eval):
tm.print_debug(f"Export reported values:") tm.print_debug(f"Export reported values:")
rep_eval = self._prms.expanse(report_eval) rep_eval = self._prms.expanse(report_eval)

View File

@@ -99,7 +99,7 @@
file: $(test_path)$(psep)results$(psep)results.py file: $(test_path)$(psep)results$(psep)results.py
func_name: echo func_name: echo
param: [ 44 ] param: [ 44 ]
process_result: "tm.setgd('process_result_value', $(result))" store_result: process_result_value
- py_func: - py_func:
name: Check the saved global variable name: Check the saved global variable
key: $(test)_PASS key: $(test)_PASS
@@ -108,6 +108,68 @@
param: [ 44 ] param: [ 44 ]
expected_result: $(process_result_value) expected_result: $(process_result_value)
- py_func:
name: store_result with process_result
key: $(test)_PASS
file: $(test_path)$(psep)results$(psep)results.py
func_name: echo
param: [ $(str_example) ]
process_result: "'$(result)'.upper()"
store_result: upper_str_example
- py_func:
name: Check store_result with process_result
key: $(test)_PASS
file: $(test_path)$(psep)results$(psep)results.py
func_name: echo
param: [ $(str_example) ]
process_result: "'$(result)'.upper()"
expected_result: $(upper_str_example)
- let:
name: store_result on let item (None value → stores PASS)
key: $(test)_PASS
values:
- dummy: 0
store_result: let_store_result
- py_func:
name: Check store_result on let stores PASS
key: $(test)_PASS
file: $(test_path)$(psep)results$(psep)results.py
func_name: echo
param: [PASS]
expected_result: $(let_store_result)
- py_func:
name: store_result on failing test (None value → stores FAIL)
key: $(test)_FAIL
file: $(test_path)$(psep)results$(psep)results.py
func_name: return_none
expected_result: FAIL
store_result: none_fail_store_result
- py_func:
name: Check store_result on failing test stores FAIL
key: $(test)_PASS
file: $(test_path)$(psep)results$(psep)results.py
func_name: echo
param: [FAIL]
expected_result: $(none_fail_store_result)
- py_func:
name: store_result with no_fail (None value → stores real FAIL, not forced PASS)
key: $(test)_PASS
file: $(test_path)$(psep)results$(psep)results.py
func_name: return_none
expected_result: FAIL
no_fail: True
store_result: none_nofail_store_result
- py_func:
name: Check store_result with no_fail stores real FAIL
key: $(test)_PASS
file: $(test_path)$(psep)results$(psep)results.py
func_name: echo
param: [FAIL]
expected_result: $(none_nofail_store_result)
- py_func: - py_func:
name: Process result when result is None (must fail) name: Process result when result is None (must fail)
key: $(test)_FAIL key: $(test)_FAIL