item params: migrate every structured item to declarative PARAMS
Migrates the remaining test items to the ParamSet/Param declaration
introduced in d0721af:
- dialogs: image, question, value, choices, tested_references
- actions: check, run, report
- console: parent + open/read_until actions
- py_func / lua_func
- containers: group, parallel + parallel_branch, unittest
- complex: cycle (sub-block exit_condition documented in
EXIT_CONDITION_PARAMS), git
- runtime_plot: parent + open/close/periodic/last_value actions
- json_rpc: parent + query/receive actions
Items intentionally without PARAMS (and therefore not validated) are
those whose body is the unstructured user value: console write/writeln,
plot add/export, and the json_rpc/console open & close actions. Same
for the internally-instantiated TestItemUnittestElement which passes
dict_item=None.
Behavior on valid .tum files is unchanged (validation suite source
mode: SUCCESS). Typos on declared params now surface as warnings
listing the accepted names; missing required params surface as load-
time errors with file context.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -5,11 +5,22 @@ from runtime.tum_except import ETUMSyntaxError, item_load_context
|
|||||||
import api.testium as tm
|
import api.testium as tm
|
||||||
from interpreter.utils.constants import TestItemType as cst
|
from interpreter.utils.constants import TestItemType as cst
|
||||||
from interpreter.utils.eval import evaluate
|
from interpreter.utils.eval import evaluate
|
||||||
|
from interpreter.utils.param_decl import Param, ParamSet, LIST
|
||||||
|
|
||||||
class TestItemCheckValue(TestItem):
|
class TestItemCheckValue(TestItem):
|
||||||
"""check item usage.
|
"""check item usage.
|
||||||
check usage:{check: {name: check my func output, steps: ['$(pfn_echo) < 5']}}
|
check usage:{check: {name: check my func output, steps: ['$(pfn_echo) < 5']}}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
PARAMS = ParamSet(
|
||||||
|
Param("values", kind=LIST, required=True,
|
||||||
|
doc="List of expressions to evaluate. Each is expanded then "
|
||||||
|
"evaluated; non-truthy results fail the check."),
|
||||||
|
# 'steps' is intentionally not redeclared here — it's the deprecated
|
||||||
|
# alias of 'values' and is already accepted by COMMON_PARAMS for
|
||||||
|
# container items. A runtime warning is emitted when 'steps' is used.
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(self, dict_item, parent = None, status_queue=None, filename=""):
|
def __init__(self, dict_item, parent = None, status_queue=None, filename=""):
|
||||||
self._name = cst.TYPE_CHECK.item_name
|
self._name = cst.TYPE_CHECK.item_name
|
||||||
super().__init__(dict_item, parent, status_queue, filename=filename)
|
super().__init__(dict_item, parent, status_queue, filename=filename)
|
||||||
|
|||||||
@@ -2,11 +2,25 @@ from interpreter.test_items.test_item import test_run
|
|||||||
from interpreter.test_items.test_result import TestValue
|
from interpreter.test_items.test_result import TestValue
|
||||||
from interpreter.test_items.test_item_dialog_base import TestItemDialogBase, _is_text_mode, _is_interactive
|
from interpreter.test_items.test_item_dialog_base import TestItemDialogBase, _is_text_mode, _is_interactive
|
||||||
from interpreter.utils.constants import TestItemType as cst
|
from interpreter.utils.constants import TestItemType as cst
|
||||||
|
from interpreter.utils.param_decl import Param, ParamSet, BLOCK
|
||||||
from runtime.tum_except import item_load_context
|
from runtime.tum_except import item_load_context
|
||||||
import api.testium as tm
|
import api.testium as tm
|
||||||
|
|
||||||
|
|
||||||
class TestItemChoicesDialog(TestItemDialogBase):
|
class TestItemChoicesDialog(TestItemDialogBase):
|
||||||
|
|
||||||
|
PARAMS = ParamSet(
|
||||||
|
Param("question", required=True,
|
||||||
|
doc="Prompt shown above the list of choices."),
|
||||||
|
Param("choices", kind=BLOCK, required=True,
|
||||||
|
doc="Tree of choices: either a list of strings, or a nested "
|
||||||
|
"mapping {label: subchoices, ...} to build a multi-level menu."),
|
||||||
|
Param("icon", default=None,
|
||||||
|
doc="Default icon name shown next to each choice."),
|
||||||
|
Param("auto_result", default=None,
|
||||||
|
doc="Batch-mode selection (path or label). None ⇒ FAILURE."),
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(self, dict_item, parent=None, status_queue=None, filename=""):
|
def __init__(self, dict_item, parent=None, status_queue=None, filename=""):
|
||||||
self._name = cst.TYPE_CHOICES_DLG.item_name
|
self._name = cst.TYPE_CHOICES_DLG.item_name
|
||||||
super().__init__(dict_item, parent, status_queue, filename=filename)
|
super().__init__(dict_item, parent, status_queue, filename=filename)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ from interpreter.test_items.test_item import test_run
|
|||||||
from interpreter.test_items.item_actions import TestItemActions
|
from interpreter.test_items.item_actions import TestItemActions
|
||||||
from interpreter.test_items.item_actions.action import TestItemAction
|
from interpreter.test_items.item_actions.action import TestItemAction
|
||||||
from interpreter.utils.constants import TestItemType as cst
|
from interpreter.utils.constants import TestItemType as cst
|
||||||
|
from interpreter.utils.param_decl import Param, ParamSet
|
||||||
from interpreter.test_items.test_result import TestResult, TestValue
|
from interpreter.test_items.test_result import TestResult, TestValue
|
||||||
|
|
||||||
|
|
||||||
@@ -21,6 +22,38 @@ class TestItemConsoleAction(TestItemAction):
|
|||||||
|
|
||||||
|
|
||||||
class TestItemConsoleOpen(TestItemConsoleAction):
|
class TestItemConsoleOpen(TestItemConsoleAction):
|
||||||
|
|
||||||
|
PARAMS = ParamSet(
|
||||||
|
Param("protocol", required=True,
|
||||||
|
doc="Transport: 'telnet', 'ssh', 'rawtcp', 'serial' or 'terminal'."),
|
||||||
|
Param("write_delay", default=0,
|
||||||
|
doc="Inter-character write delay in ms (slow devices)."),
|
||||||
|
Param("log", doc="Path to a log file capturing the console traffic."),
|
||||||
|
Param("overwrite_log", default=True,
|
||||||
|
doc="If true, truncate the log file at open; else append."),
|
||||||
|
# telnet
|
||||||
|
Param("telnet_host", doc="Hostname/IP for the telnet target."),
|
||||||
|
Param("telnet_port", default=69, doc="TCP port for telnet."),
|
||||||
|
# ssh
|
||||||
|
Param("ssh_host", doc="Hostname/IP for the SSH target."),
|
||||||
|
Param("ssh_user", doc="SSH login user."),
|
||||||
|
Param("ssh_pwd", doc="SSH password (if key-based auth is not used)."),
|
||||||
|
# rawtcp
|
||||||
|
Param("tcp_host", doc="Hostname/IP for a raw-TCP connection."),
|
||||||
|
Param("tcp_port", doc="TCP port for a raw-TCP connection."),
|
||||||
|
# serial
|
||||||
|
Param("serial_port", doc="Serial device path (e.g. /dev/ttyUSB0 or COM3)."),
|
||||||
|
Param("serial_baudrate", doc="Serial baudrate."),
|
||||||
|
Param("buffered", default=True,
|
||||||
|
doc="If true, the serial console buffers received bytes between reads."),
|
||||||
|
# terminal
|
||||||
|
Param("terminal_path",
|
||||||
|
doc="Working directory for the local terminal protocol."),
|
||||||
|
Param("shell",
|
||||||
|
doc="Shell command used for the local terminal protocol "
|
||||||
|
"(default: 'cmd.exe' on Windows, '/usr/bin/env bash' elsewhere)."),
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, action_name, dict_item, parent=None, status_queue=None, filename=""
|
self, action_name, dict_item, parent=None, status_queue=None, filename=""
|
||||||
):
|
):
|
||||||
@@ -283,6 +316,17 @@ class TestItemConsoleWriteLn(TestItemConsoleAction):
|
|||||||
|
|
||||||
|
|
||||||
class TestItemConsoleReadUntil(TestItemConsoleAction):
|
class TestItemConsoleReadUntil(TestItemConsoleAction):
|
||||||
|
|
||||||
|
PARAMS = ParamSet(
|
||||||
|
Param("expected", required=True,
|
||||||
|
doc="Regex matched against incoming console output until found "
|
||||||
|
"or until timeout."),
|
||||||
|
Param("timeout", default=-1,
|
||||||
|
doc="Seconds before giving up. Negative means infinite."),
|
||||||
|
Param("mute", default=False,
|
||||||
|
doc="If true, don't echo received bytes to testium's stdout/log."),
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, action_name, dict_item, parent=None, status_queue=None, filename=""
|
self, action_name, dict_item, parent=None, status_queue=None, filename=""
|
||||||
):
|
):
|
||||||
@@ -336,6 +380,14 @@ class TestItemConsoleReadUntil(TestItemConsoleAction):
|
|||||||
|
|
||||||
|
|
||||||
class TestItemConsole(TestItemActions):
|
class TestItemConsole(TestItemActions):
|
||||||
|
|
||||||
|
PARAMS = ParamSet(
|
||||||
|
Param("console_name", required=True,
|
||||||
|
doc="Identifier of the console — used by every nested action to "
|
||||||
|
"reach back the same transport. Multiple consoles can coexist "
|
||||||
|
"as long as their names differ."),
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(self, dict_item, parent=None, status_queue=None, filename=""):
|
def __init__(self, dict_item, parent=None, status_queue=None, filename=""):
|
||||||
super().__init__(
|
super().__init__(
|
||||||
cst.TYPE_CONSOLE, dict_item, parent, status_queue, filename=filename
|
cst.TYPE_CONSOLE, dict_item, parent, status_queue, filename=filename
|
||||||
|
|||||||
@@ -8,9 +8,36 @@ from interpreter.test_items.test_result import TestResult, TestValue
|
|||||||
import api.testium as tm
|
import api.testium as tm
|
||||||
from interpreter.utils.params import TestItemParams
|
from interpreter.utils.params import TestItemParams
|
||||||
from interpreter.utils.constants import TestItemType as cst
|
from interpreter.utils.constants import TestItemType as cst
|
||||||
|
from interpreter.utils.param_decl import Param, ParamSet, BLOCK
|
||||||
|
|
||||||
|
|
||||||
|
# Sub-block validation: 'cycle' accepts an 'exit_condition:' mapping whose
|
||||||
|
# own params are reported here so unknown keys inside it can be flagged
|
||||||
|
# during a future Block-aware diagnostic pass. For now the parent only
|
||||||
|
# declares that 'exit_condition' is an accepted top-level key.
|
||||||
|
EXIT_CONDITION_PARAMS = ParamSet(
|
||||||
|
Param("time", doc="HH:MM time of day after which the loop exits."),
|
||||||
|
Param("value", doc="Expression; when truthy the loop exits."),
|
||||||
|
Param("file", doc="Python file containing the exit-condition function."),
|
||||||
|
Param("func_name", doc="Function name in 'file' returning the exit value."),
|
||||||
|
Param("param", doc="Arguments passed to the exit function."),
|
||||||
|
Param("eval", default="",
|
||||||
|
doc="Post-evaluation expression applied to the function's return."),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestItemCycle(TestItem):
|
class TestItemCycle(TestItem):
|
||||||
|
|
||||||
|
PARAMS = ParamSet(
|
||||||
|
Param("iterator",
|
||||||
|
doc="Iterable (or string expanding to one) driving the loop. "
|
||||||
|
"The current value is exposed as $(loop_param)."),
|
||||||
|
Param("exit_condition", kind=BLOCK,
|
||||||
|
doc="Optional block stopping the loop early: combine 'time', "
|
||||||
|
"'value', or a 'file'+'func_name' pair (with optional "
|
||||||
|
"'param' and 'eval')."),
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(self, dict_cycle, parent=None, status_queue=None, filename=""):
|
def __init__(self, dict_cycle, parent=None, status_queue=None, filename=""):
|
||||||
self._name = cst.TYPE_CYCLE.item_name
|
self._name = cst.TYPE_CYCLE.item_name
|
||||||
super().__init__(dict_cycle, parent, status_queue, filename=filename)
|
super().__init__(dict_cycle, parent, status_queue, filename=filename)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
from interpreter.test_items.test_item import (TestItem, test_run)
|
from interpreter.test_items.test_item import (TestItem, test_run)
|
||||||
from interpreter.test_items.test_result import (TestValue)
|
from interpreter.test_items.test_result import (TestValue)
|
||||||
from interpreter.utils.constants import TestItemType as cst
|
from interpreter.utils.constants import TestItemType as cst
|
||||||
|
from interpreter.utils.param_decl import Param, ParamSet, LIST
|
||||||
from runtime.tum_except import ETUMParamError, ETUMSyntaxError
|
from runtime.tum_except import ETUMParamError, ETUMSyntaxError
|
||||||
import interpreter.utils.version as git
|
import interpreter.utils.version as git
|
||||||
|
|
||||||
@@ -8,6 +9,13 @@ class TestItemGit(TestItem):
|
|||||||
"""
|
"""
|
||||||
This item expect only one parameter which is a string or list of string being the path to the git folder
|
This item expect only one parameter which is a string or list of string being the path to the git folder
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
PARAMS = ParamSet(
|
||||||
|
Param("repo", kind=LIST, required=True,
|
||||||
|
doc="Path to a git checkout, or list of such paths. Each is "
|
||||||
|
"reported with its current version (tag + dirty state)."),
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(self, dict_item, parent = None, status_queue=None, filename=""):
|
def __init__(self, dict_item, parent = None, status_queue=None, filename=""):
|
||||||
self._name = cst.TYPE_GIT.item_name
|
self._name = cst.TYPE_GIT.item_name
|
||||||
super().__init__(dict_item, parent, status_queue, filename=filename)
|
super().__init__(dict_item, parent, status_queue, filename=filename)
|
||||||
|
|||||||
@@ -1,10 +1,17 @@
|
|||||||
from interpreter.test_items.test_item import (TestItem, test_run)
|
from interpreter.test_items.test_item import (TestItem, test_run)
|
||||||
from interpreter.test_items.test_result import (TestResult, TestValue)
|
from interpreter.test_items.test_result import (TestResult, TestValue)
|
||||||
from interpreter.utils.constants import TestItemType as cst
|
from interpreter.utils.constants import TestItemType as cst
|
||||||
|
from interpreter.utils.param_decl import ParamSet
|
||||||
from runtime.tum_except import ETUMSyntaxError
|
from runtime.tum_except import ETUMSyntaxError
|
||||||
import api.testium as tm
|
import api.testium as tm
|
||||||
|
|
||||||
class TestItemGroup(TestItem):
|
class TestItemGroup(TestItem):
|
||||||
|
|
||||||
|
# 'group' has no item-specific parameters; 'steps' is handled by COMMON_PARAMS.
|
||||||
|
# Declaring an empty ParamSet still opts in to unknown-param validation
|
||||||
|
# (e.g. typo 'stop_on_failures').
|
||||||
|
PARAMS = ParamSet()
|
||||||
|
|
||||||
def __init__(self, dict_cycle, parent = None, status_queue=None, filename=""):
|
def __init__(self, dict_cycle, parent = None, status_queue=None, filename=""):
|
||||||
self._name = cst.TYPE_GROUP.item_name
|
self._name = cst.TYPE_GROUP.item_name
|
||||||
super().__init__(dict_cycle, parent, status_queue, filename=filename)
|
super().__init__(dict_cycle, parent, status_queue, filename=filename)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ from interpreter.test_items.test_item import test_run
|
|||||||
from interpreter.test_items.test_result import TestValue
|
from interpreter.test_items.test_result import TestValue
|
||||||
from interpreter.test_items.test_item_dialog_base import TestItemDialogBase, _is_text_mode, _is_interactive
|
from interpreter.test_items.test_item_dialog_base import TestItemDialogBase, _is_text_mode, _is_interactive
|
||||||
from interpreter.utils.constants import TestItemType as cst
|
from interpreter.utils.constants import TestItemType as cst
|
||||||
|
from interpreter.utils.param_decl import Param, ParamSet
|
||||||
from runtime.tum_except import item_load_context
|
from runtime.tum_except import item_load_context
|
||||||
import api.testium as tm
|
import api.testium as tm
|
||||||
|
|
||||||
@@ -12,6 +13,17 @@ class TestItemImageDialog(TestItemDialogBase):
|
|||||||
"""dialog_image item usage.
|
"""dialog_image item usage.
|
||||||
dialog_image name: Nice image, question: could you press the red button, filename: img.jpg
|
dialog_image name: Nice image, question: could you press the red button, filename: img.jpg
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
PARAMS = ParamSet(
|
||||||
|
Param("question", required=True,
|
||||||
|
doc="Prompt shown above the image."),
|
||||||
|
Param("filename", required=True,
|
||||||
|
doc="Path to the image file (relative to the test directory or absolute)."),
|
||||||
|
Param("auto_result", default=None,
|
||||||
|
doc="Outcome used in batch/non-interactive mode. Truthy ⇒ SUCCESS, "
|
||||||
|
"None ⇒ FAILURE."),
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(self, dict_item, parent=None, status_queue=None, filename=""):
|
def __init__(self, dict_item, parent=None, status_queue=None, filename=""):
|
||||||
self._name = cst.TYPE_IMAGE_DLG.item_name
|
self._name = cst.TYPE_IMAGE_DLG.item_name
|
||||||
super().__init__(dict_item, parent, status_queue, filename=filename)
|
super().__init__(dict_item, parent, status_queue, filename=filename)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ from interpreter.test_items.item_actions.action import TestItemAction
|
|||||||
|
|
||||||
from interpreter.utils.constants import TestItemType as cst
|
from interpreter.utils.constants import TestItemType as cst
|
||||||
from interpreter.utils.eval import evaluate
|
from interpreter.utils.eval import evaluate
|
||||||
|
from interpreter.utils.param_decl import Param, ParamSet, BLOCK
|
||||||
|
|
||||||
from interpreter.test_items.test_item_json_rpc.jsonrpc_adapters import (
|
from interpreter.test_items.test_item_json_rpc.jsonrpc_adapters import (
|
||||||
JrpcAdapter,
|
JrpcAdapter,
|
||||||
@@ -76,6 +77,20 @@ class TestItemJSRPCActionClose(TestItemAction):
|
|||||||
|
|
||||||
class TestItemJSRPCActionQuery(TestItemAction):
|
class TestItemJSRPCActionQuery(TestItemAction):
|
||||||
|
|
||||||
|
PARAMS = ParamSet(
|
||||||
|
Param("method", required=True,
|
||||||
|
doc="JSON-RPC method name to call."),
|
||||||
|
Param("params",
|
||||||
|
doc="Parameters payload (list, dict or scalar) sent to the method."),
|
||||||
|
Param("id", default="rand",
|
||||||
|
doc="JSON-RPC request id. 'rand' (default) ⇒ a random integer is used."),
|
||||||
|
Param("no_wait", default=False,
|
||||||
|
doc="If true, send the request without waiting for a response."),
|
||||||
|
Param("timeout", default=None,
|
||||||
|
doc="Seconds to wait for a response. None ⇒ inherits the transport "
|
||||||
|
"default."),
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, action_name, dict_item, parent=None, status_queue=None, filename=""
|
self, action_name, dict_item, parent=None, status_queue=None, filename=""
|
||||||
):
|
):
|
||||||
@@ -129,6 +144,13 @@ class TestItemJSRPCActionQuery(TestItemAction):
|
|||||||
|
|
||||||
class TestItemJSRPCActionReceive(TestItemAction):
|
class TestItemJSRPCActionReceive(TestItemAction):
|
||||||
|
|
||||||
|
PARAMS = ParamSet(
|
||||||
|
Param("id", required=True,
|
||||||
|
doc="JSON-RPC request id whose response we expect."),
|
||||||
|
Param("timeout", default=None,
|
||||||
|
doc="Seconds to wait for the response. None ⇒ transport default."),
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, action_name, dict_item, parent=None, status_queue=None, filename=""
|
self, action_name, dict_item, parent=None, status_queue=None, filename=""
|
||||||
):
|
):
|
||||||
@@ -172,6 +194,22 @@ class TestItemJSON_RPC(TestItemActions):
|
|||||||
This item TBD
|
This item TBD
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
PARAMS = ParamSet(
|
||||||
|
Param("console", kind=BLOCK,
|
||||||
|
doc="Console-transport block: {console_name, …}. Either 'console' "
|
||||||
|
"or 'udp' must be set."),
|
||||||
|
Param("udp", kind=BLOCK,
|
||||||
|
doc="UDP-transport block: {host, port, …}. Either 'console' or "
|
||||||
|
"'udp' must be set."),
|
||||||
|
Param("version", default="1.0",
|
||||||
|
doc="JSON-RPC protocol version ('1.0' or '2.0')."),
|
||||||
|
Param("timeout", required=True,
|
||||||
|
doc="Default seconds to wait for a JSON-RPC response across all "
|
||||||
|
"child query/receive actions."),
|
||||||
|
Param("mute", default=False,
|
||||||
|
doc="If true, don't echo wire traffic to the log."),
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, dict_item: dict, parent: TestItem = None, status_queue=None, filename=""
|
self, dict_item: dict, parent: TestItem = None, status_queue=None, filename=""
|
||||||
):
|
):
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import api.testium as tm
|
|||||||
from interpreter.utils.lua_func_exec import LuaFuncExecEngine
|
from interpreter.utils.lua_func_exec import LuaFuncExecEngine
|
||||||
from interpreter.utils.api_srv import api_request
|
from interpreter.utils.api_srv import api_request
|
||||||
from interpreter.utils.constants import TestItemType as cst
|
from interpreter.utils.constants import TestItemType as cst
|
||||||
|
from interpreter.utils.param_decl import Param, ParamSet, LIST
|
||||||
|
|
||||||
_LUA_FUNC_CONTEXTS_KEY = "_lua_func_contexts"
|
_LUA_FUNC_CONTEXTS_KEY = "_lua_func_contexts"
|
||||||
|
|
||||||
@@ -21,6 +22,21 @@ class TestItemLuaFunc(TestItem):
|
|||||||
Optional: context_id: <id> — share a persistent process with other lua_func items using the same id.
|
Optional: context_id: <id> — share a persistent process with other lua_func items using the same id.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
PARAMS = ParamSet(
|
||||||
|
Param("file", required=True,
|
||||||
|
doc="Path to the .lua file containing the function."),
|
||||||
|
Param("func_name", required=True,
|
||||||
|
doc="Name of the function to call in the file."),
|
||||||
|
Param("param", kind=LIST,
|
||||||
|
doc="Arguments passed to the function. Each entry is expanded "
|
||||||
|
"before the call. Special tokens $(loop_param) / $(loop_index) "
|
||||||
|
"resolve from the surrounding cycle."),
|
||||||
|
Param("context_id", default=None,
|
||||||
|
doc="If set, the lua_func subprocess is kept alive and reused by "
|
||||||
|
"every other lua_func item with the same context_id — enables "
|
||||||
|
"shared in-memory state between successive calls."),
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(self, dict_item, parent=None, status_queue=None, filename=""):
|
def __init__(self, dict_item, parent=None, status_queue=None, filename=""):
|
||||||
self._name = cst.TYPE_LUA_FUNCTION.item_name
|
self._name = cst.TYPE_LUA_FUNCTION.item_name
|
||||||
super().__init__(dict_item, parent, status_queue, filename=filename)
|
super().__init__(dict_item, parent, status_queue, filename=filename)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ from interpreter.test_items.test_item import test_run
|
|||||||
from interpreter.test_items.test_result import TestResult, TestValue
|
from interpreter.test_items.test_result import TestResult, TestValue
|
||||||
from interpreter.utils.constants import TestItemType as cst
|
from interpreter.utils.constants import TestItemType as cst
|
||||||
from interpreter.utils.eval import eval_to_boolean
|
from interpreter.utils.eval import eval_to_boolean
|
||||||
|
from interpreter.utils.param_decl import Param, ParamSet, LIST, BLOCK, Enum
|
||||||
from runtime.tum_except import ETUMSyntaxError
|
from runtime.tum_except import ETUMSyntaxError
|
||||||
from runtime.string_queue import StringQueue
|
from runtime.string_queue import StringQueue
|
||||||
from runtime.stdout_redirect import stdio_redir
|
from runtime.stdout_redirect import stdio_redir
|
||||||
@@ -15,6 +16,12 @@ class TestItemParallelBranch(TestItemContainer):
|
|||||||
"""One branch of a parallel item. Runs its children sequentially,
|
"""One branch of a parallel item. Runs its children sequentially,
|
||||||
optionally waiting for a condition before starting."""
|
optionally waiting for a condition before starting."""
|
||||||
|
|
||||||
|
PARAMS = ParamSet(
|
||||||
|
Param("wait_for", kind=BLOCK,
|
||||||
|
doc="Optional block {condition, timeout} that defers the branch "
|
||||||
|
"start until the condition is truthy (or the timeout elapses)."),
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(self, dict_item, parent=None, status_queue=None, filename=""):
|
def __init__(self, dict_item, parent=None, status_queue=None, filename=""):
|
||||||
super().__init__(cst.TYPE_PARALLEL_BRANCH, dict_item, parent, status_queue, filename=filename)
|
super().__init__(cst.TYPE_PARALLEL_BRANCH, dict_item, parent, status_queue, filename=filename)
|
||||||
self._wait_condition = None
|
self._wait_condition = None
|
||||||
@@ -87,6 +94,15 @@ class TestItemParallel(TestItemContainer):
|
|||||||
- ...
|
- ...
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
PARAMS = ParamSet(
|
||||||
|
Param("branches", kind=LIST, required=True,
|
||||||
|
doc="List of branch blocks (each branch holds its own 'steps' "
|
||||||
|
"and optional 'wait_for')."),
|
||||||
|
Param("sync", kind=Enum("all", "any"), default="all",
|
||||||
|
doc="'all' (default) waits for every branch; 'any' returns as "
|
||||||
|
"soon as the first branch completes."),
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(self, dict_item, parent=None, status_queue=None, filename=""):
|
def __init__(self, dict_item, parent=None, status_queue=None, filename=""):
|
||||||
branches = dict_item.get("branches", [])
|
branches = dict_item.get("branches", [])
|
||||||
if not branches:
|
if not branches:
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import api.testium as tm
|
|||||||
from interpreter.utils.py_func_exec import PyFuncExecEngine
|
from interpreter.utils.py_func_exec import PyFuncExecEngine
|
||||||
from interpreter.utils.api_srv import api_request
|
from interpreter.utils.api_srv import api_request
|
||||||
from interpreter.utils.constants import TestItemType as cst
|
from interpreter.utils.constants import TestItemType as cst
|
||||||
|
from interpreter.utils.param_decl import Param, ParamSet, LIST
|
||||||
|
|
||||||
_PY_FUNC_CONTEXTS_KEY = "_py_func_contexts"
|
_PY_FUNC_CONTEXTS_KEY = "_py_func_contexts"
|
||||||
|
|
||||||
@@ -21,6 +22,21 @@ class TestItemPyFunc(TestItem):
|
|||||||
Optional: context_id: <id> — share a persistent process with other py_func items using the same id.
|
Optional: context_id: <id> — share a persistent process with other py_func items using the same id.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
PARAMS = ParamSet(
|
||||||
|
Param("file", required=True,
|
||||||
|
doc="Path to the .py file containing the function."),
|
||||||
|
Param("func_name", required=True,
|
||||||
|
doc="Name of the function to call in the file."),
|
||||||
|
Param("param", kind=LIST,
|
||||||
|
doc="Arguments passed to the function. Each entry is expanded "
|
||||||
|
"before the call. Special tokens $(loop_param) / $(loop_index) "
|
||||||
|
"resolve from the surrounding cycle."),
|
||||||
|
Param("context_id", default=None,
|
||||||
|
doc="If set, the py_func subprocess is kept alive and reused by "
|
||||||
|
"every other py_func item with the same context_id — enables "
|
||||||
|
"shared in-memory state between successive calls."),
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(self, dict_item, parent=None, status_queue=None, filename=""):
|
def __init__(self, dict_item, parent=None, status_queue=None, filename=""):
|
||||||
self._name = cst.TYPE_PY_FUNCTION.item_name
|
self._name = cst.TYPE_PY_FUNCTION.item_name
|
||||||
super().__init__(dict_item, parent, status_queue, filename=filename)
|
super().__init__(dict_item, parent, status_queue, filename=filename)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ from interpreter.test_items.test_item import test_run
|
|||||||
from interpreter.test_items.test_result import TestValue
|
from interpreter.test_items.test_result import TestValue
|
||||||
from interpreter.test_items.test_item_dialog_base import TestItemDialogBase, _is_text_mode, _is_interactive
|
from interpreter.test_items.test_item_dialog_base import TestItemDialogBase, _is_text_mode, _is_interactive
|
||||||
from interpreter.utils.constants import TestItemType as cst
|
from interpreter.utils.constants import TestItemType as cst
|
||||||
|
from interpreter.utils.param_decl import Param, ParamSet
|
||||||
from runtime.tum_except import item_load_context
|
from runtime.tum_except import item_load_context
|
||||||
|
|
||||||
|
|
||||||
@@ -9,6 +10,14 @@ class TestItemQuestionDialog(TestItemDialogBase):
|
|||||||
"""dialog_question item usage.
|
"""dialog_question item usage.
|
||||||
dialog_question name: Nice question, question: "If OK, press OK, If not, press cancel"
|
dialog_question name: Nice question, question: "If OK, press OK, If not, press cancel"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
PARAMS = ParamSet(
|
||||||
|
Param("question", required=True,
|
||||||
|
doc="Yes/No prompt presented to the user."),
|
||||||
|
Param("auto_result", default=None,
|
||||||
|
doc="Batch-mode answer ('yes'/'no' or truthy/falsy). None ⇒ FAILURE."),
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(self, dict_item, parent=None, status_queue=None, filename=""):
|
def __init__(self, dict_item, parent=None, status_queue=None, filename=""):
|
||||||
self._name = cst.TYPE_QUESTION_DLG.item_name
|
self._name = cst.TYPE_QUESTION_DLG.item_name
|
||||||
super().__init__(dict_item, parent, status_queue, filename=filename)
|
super().__init__(dict_item, parent, status_queue, filename=filename)
|
||||||
|
|||||||
@@ -3,9 +3,17 @@ from interpreter.test_items.test_item import (TestItem, test_run)
|
|||||||
from interpreter.test_items.test_result import (TestValue)
|
from interpreter.test_items.test_result import (TestValue)
|
||||||
from runtime.tum_except import ETUMSyntaxError
|
from runtime.tum_except import ETUMSyntaxError
|
||||||
from interpreter.utils.constants import TestItemType as cst
|
from interpreter.utils.constants import TestItemType as cst
|
||||||
|
from interpreter.utils.param_decl import Param, ParamSet, LIST
|
||||||
from interpreter.test_report.test_report import Export
|
from interpreter.test_report.test_report import Export
|
||||||
|
|
||||||
class TestItemReport(TestItem):
|
class TestItemReport(TestItem):
|
||||||
|
|
||||||
|
PARAMS = ParamSet(
|
||||||
|
Param("export", kind=LIST, required=True,
|
||||||
|
doc="List of exporters to run (junit, sqlite, …). Each entry is a "
|
||||||
|
"mapping describing the exporter type and its parameters."),
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(self, dict_item, parent = None, status_queue=None, filename=""):
|
def __init__(self, dict_item, parent = None, status_queue=None, filename=""):
|
||||||
self._name = cst.TYPE_REPORT.item_name
|
self._name = cst.TYPE_REPORT.item_name
|
||||||
super().__init__(dict_item, parent, status_queue, filename=filename)
|
super().__init__(dict_item, parent, status_queue, filename=filename)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ from interpreter.test_items.test_item import (TestItem, test_run)
|
|||||||
from interpreter.test_items.test_result import (TestValue)
|
from interpreter.test_items.test_result import (TestValue)
|
||||||
import api.testium as tm
|
import api.testium as tm
|
||||||
from interpreter.utils.constants import TestItemType as cst
|
from interpreter.utils.constants import TestItemType as cst
|
||||||
|
from interpreter.utils.param_decl import Param, ParamSet
|
||||||
from runtime.tum_except import ETUMSyntaxError, ETUMRuntimeError, item_load_context
|
from runtime.tum_except import ETUMSyntaxError, ETUMRuntimeError, item_load_context
|
||||||
|
|
||||||
|
|
||||||
@@ -57,6 +58,25 @@ def nowInBetween(start, end):
|
|||||||
|
|
||||||
|
|
||||||
class TestItemRun(TestItem):
|
class TestItemRun(TestItem):
|
||||||
|
|
||||||
|
PARAMS = ParamSet(
|
||||||
|
Param("tum", required=True,
|
||||||
|
doc="Path to the .tum file launched in a fresh testium instance."),
|
||||||
|
Param("param_file", default="",
|
||||||
|
doc="Optional path to a param.yaml passed to the sub-instance."),
|
||||||
|
Param("log_file", default="",
|
||||||
|
doc="Path where the sub-instance writes its log."),
|
||||||
|
Param("report_file", default="",
|
||||||
|
doc="Path where the sub-instance writes its report."),
|
||||||
|
Param("start_time",
|
||||||
|
doc="HH:MM time of day after which the sub-instance may run."),
|
||||||
|
Param("end_time",
|
||||||
|
doc="HH:MM time of day after which the sub-instance no longer runs."),
|
||||||
|
Param("wait_for_exec",
|
||||||
|
doc="If true, block until the time window opens. Requires both "
|
||||||
|
"start_time and end_time."),
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(self, dict_item, parent = None, status_queue=None, filename=""):
|
def __init__(self, dict_item, parent = None, status_queue=None, filename=""):
|
||||||
self._name = cst.TYPE_RUN.item_name
|
self._name = cst.TYPE_RUN.item_name
|
||||||
super().__init__(dict_item, parent, status_queue, filename=filename)
|
super().__init__(dict_item, parent, status_queue, filename=filename)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ from interpreter.test_items.item_actions import TestItemActions
|
|||||||
from interpreter.test_items.item_actions.action import TestItemAction
|
from interpreter.test_items.item_actions.action import TestItemAction
|
||||||
from interpreter.utils.constants import TestItemType as cst
|
from interpreter.utils.constants import TestItemType as cst
|
||||||
from interpreter.utils.eval import evaluate
|
from interpreter.utils.eval import evaluate
|
||||||
|
from interpreter.utils.param_decl import Param, ParamSet, LIST
|
||||||
|
|
||||||
|
|
||||||
class TestItemPlotAction(TestItemAction):
|
class TestItemPlotAction(TestItemAction):
|
||||||
@@ -21,6 +22,12 @@ class TestItemPlotAction(TestItemAction):
|
|||||||
|
|
||||||
|
|
||||||
class TestItemPlotActionOpen(TestItemPlotAction):
|
class TestItemPlotActionOpen(TestItemPlotAction):
|
||||||
|
|
||||||
|
PARAMS = ParamSet(
|
||||||
|
Param("log_path", default=None,
|
||||||
|
doc="Optional file to which the plot data are appended."),
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, action_name, dict_item, parent=None, status_queue=None, filename=""
|
self, action_name, dict_item, parent=None, status_queue=None, filename=""
|
||||||
):
|
):
|
||||||
@@ -57,6 +64,15 @@ class TestItemPlotActionOpen(TestItemPlotAction):
|
|||||||
|
|
||||||
|
|
||||||
class TestItemPlotActionClose(TestItemPlotAction):
|
class TestItemPlotActionClose(TestItemPlotAction):
|
||||||
|
|
||||||
|
PARAMS = ParamSet(
|
||||||
|
Param("wait_dialog_exit", default=False,
|
||||||
|
doc="If true, the close action blocks until the user closes the "
|
||||||
|
"plot window (or timeout)."),
|
||||||
|
Param("timeout", default=-1,
|
||||||
|
doc="Seconds to wait when wait_dialog_exit is true. Negative ⇒ infinite."),
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, action_name, dict_item, parent=None, status_queue=None, filename=""
|
self, action_name, dict_item, parent=None, status_queue=None, filename=""
|
||||||
):
|
):
|
||||||
@@ -96,6 +112,20 @@ class TestItemPlotActionClose(TestItemPlotAction):
|
|||||||
|
|
||||||
|
|
||||||
class TestItemPlotActionPeriodic(TestItemPlotAction):
|
class TestItemPlotActionPeriodic(TestItemPlotAction):
|
||||||
|
|
||||||
|
PARAMS = ParamSet(
|
||||||
|
Param("period", required=True,
|
||||||
|
doc="Seconds between two calls of the periodic function."),
|
||||||
|
Param("file", required=True,
|
||||||
|
doc="Path to the .py file holding the periodic function."),
|
||||||
|
Param("func_name", required=True,
|
||||||
|
doc="Name of the periodic function."),
|
||||||
|
Param("param", kind=LIST,
|
||||||
|
doc="Arguments passed to the periodic function on each call."),
|
||||||
|
Param("eval", default="",
|
||||||
|
doc="Post-evaluation applied to the function's return value."),
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, action_name, dict_item, parent=None, status_queue=None, filename=""
|
self, action_name, dict_item, parent=None, status_queue=None, filename=""
|
||||||
):
|
):
|
||||||
@@ -169,6 +199,13 @@ class TestItemPlotActionAdd(TestItemPlotAction):
|
|||||||
|
|
||||||
|
|
||||||
class TestItemPlotActionLastValues(TestItemPlotAction):
|
class TestItemPlotActionLastValues(TestItemPlotAction):
|
||||||
|
|
||||||
|
PARAMS = ParamSet(
|
||||||
|
Param("name", kind=LIST,
|
||||||
|
doc="List of plot variable names whose last sample is returned. "
|
||||||
|
"Result is stored in $(plv_<plot_name>) as a dict."),
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(self, action_name, dict_item, parent=None, status_queue=None, filename=""):
|
def __init__(self, action_name, dict_item, parent=None, status_queue=None, filename=""):
|
||||||
super().__init__(
|
super().__init__(
|
||||||
action_name, cst.TYPE_GRAPH_ACTION, dict_item, parent, status_queue, filename=filename
|
action_name, cst.TYPE_GRAPH_ACTION, dict_item, parent, status_queue, filename=filename
|
||||||
@@ -219,6 +256,13 @@ class TestItemPlotActionExport(TestItemPlotAction):
|
|||||||
|
|
||||||
|
|
||||||
class TestItemPlot(TestItemActions):
|
class TestItemPlot(TestItemActions):
|
||||||
|
|
||||||
|
PARAMS = ParamSet(
|
||||||
|
Param("plot_name", required=True,
|
||||||
|
doc="Identifier of the plot window — referenced by every nested "
|
||||||
|
"action and by $(plv_<plot_name>) for last-values output."),
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(self, dict_item, parent=None, status_queue=None, filename=""):
|
def __init__(self, dict_item, parent=None, status_queue=None, filename=""):
|
||||||
super().__init__(
|
super().__init__(
|
||||||
cst.TYPE_GRAPH, dict_item, parent, status_queue, filename=filename
|
cst.TYPE_GRAPH, dict_item, parent, status_queue, filename=filename
|
||||||
|
|||||||
@@ -2,11 +2,23 @@ from interpreter.test_items.test_item import test_run
|
|||||||
from interpreter.test_items.test_result import TestValue
|
from interpreter.test_items.test_result import TestValue
|
||||||
from interpreter.test_items.test_item_dialog_base import TestItemDialogBase, _is_text_mode, _is_interactive
|
from interpreter.test_items.test_item_dialog_base import TestItemDialogBase, _is_text_mode, _is_interactive
|
||||||
from interpreter.utils.constants import TestItemType as cst
|
from interpreter.utils.constants import TestItemType as cst
|
||||||
|
from interpreter.utils.param_decl import Param, ParamSet, LIST
|
||||||
from runtime.tum_except import item_load_context
|
from runtime.tum_except import item_load_context
|
||||||
import api.testium as tm
|
import api.testium as tm
|
||||||
|
|
||||||
|
|
||||||
class TestItemTestedRefsDialog(TestItemDialogBase):
|
class TestItemTestedRefsDialog(TestItemDialogBase):
|
||||||
|
|
||||||
|
PARAMS = ParamSet(
|
||||||
|
Param("question", required=True,
|
||||||
|
doc="Prompt asking the operator to enter the tested references."),
|
||||||
|
Param("reference", kind=LIST,
|
||||||
|
doc="Pre-filled list of references shown in the dialog."),
|
||||||
|
Param("auto_result", default=None,
|
||||||
|
doc="Batch-mode outcome: None ⇒ FAILURE, truthy ⇒ SUCCESS with "
|
||||||
|
"the pre-filled references."),
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(self, dict_item, parent=None, status_queue=None, filename=""):
|
def __init__(self, dict_item, parent=None, status_queue=None, filename=""):
|
||||||
self._name = cst.TYPE_REFERENCE_DLG.item_name
|
self._name = cst.TYPE_REFERENCE_DLG.item_name
|
||||||
super().__init__(dict_item, parent, status_queue, filename=filename)
|
super().__init__(dict_item, parent, status_queue, filename=filename)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ from interpreter.test_items.test_item import (TestItem, test_run, LOG_TEST_STOP,
|
|||||||
from interpreter.test_items.test_result import (TestResult, TestValue)
|
from interpreter.test_items.test_result import (TestResult, TestValue)
|
||||||
from interpreter.test_items.test_item import test_data
|
from interpreter.test_items.test_item import test_data
|
||||||
from interpreter.utils.constants import TestItemType as cst
|
from interpreter.utils.constants import TestItemType as cst
|
||||||
|
from interpreter.utils.param_decl import Param, ParamSet, LIST
|
||||||
from runtime.stdout_redirect import stdio_redir
|
from runtime.stdout_redirect import stdio_redir
|
||||||
|
|
||||||
class UnittestResult(TextTestResult):
|
class UnittestResult(TextTestResult):
|
||||||
@@ -95,6 +96,15 @@ class TestItemUnittestElement(TestItem):
|
|||||||
|
|
||||||
|
|
||||||
class TestItemUnittestFile(TestItem):
|
class TestItemUnittestFile(TestItem):
|
||||||
|
|
||||||
|
PARAMS = ParamSet(
|
||||||
|
Param("test_file", required=True,
|
||||||
|
doc="Path to the Python unittest file (TestCase subclass)."),
|
||||||
|
Param("test_method", kind=LIST,
|
||||||
|
doc="Optional list of method names to restrict the run to. "
|
||||||
|
"When empty, every test_* method in the file is run."),
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(self, dict_item, parent = None, status_queue=None, filename=""):
|
def __init__(self, dict_item, parent = None, status_queue=None, filename=""):
|
||||||
self._name = cst.TYPE_UNITTEST.item_name
|
self._name = cst.TYPE_UNITTEST.item_name
|
||||||
super().__init__(dict_item, parent, status_queue, filename=filename)
|
super().__init__(dict_item, parent, status_queue, filename=filename)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ from interpreter.test_items.test_item import test_run
|
|||||||
from interpreter.test_items.test_result import TestValue
|
from interpreter.test_items.test_result import TestValue
|
||||||
from interpreter.test_items.test_item_dialog_base import TestItemDialogBase, _is_text_mode, _is_interactive
|
from interpreter.test_items.test_item_dialog_base import TestItemDialogBase, _is_text_mode, _is_interactive
|
||||||
from interpreter.utils.constants import TestItemType as cst
|
from interpreter.utils.constants import TestItemType as cst
|
||||||
|
from interpreter.utils.param_decl import Param, ParamSet
|
||||||
from runtime.tum_except import item_load_context
|
from runtime.tum_except import item_load_context
|
||||||
import api.testium as tm
|
import api.testium as tm
|
||||||
|
|
||||||
@@ -10,6 +11,19 @@ class TestItemValueDialog(TestItemDialogBase):
|
|||||||
"""dialog_value item usage.
|
"""dialog_value item usage.
|
||||||
dialog_value name: Enter value, question: "Which value did you measure?"
|
dialog_value name: Enter value, question: "Which value did you measure?"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
PARAMS = ParamSet(
|
||||||
|
Param("question", required=True,
|
||||||
|
doc="Prompt shown above the value input field."),
|
||||||
|
Param("default", default="",
|
||||||
|
doc="Pre-filled value of the input field."),
|
||||||
|
Param("auto_result", default=None,
|
||||||
|
doc="Batch-mode outcome: None ⇒ FAILURE, 'cancel' ⇒ cancelled, "
|
||||||
|
"any other truthy ⇒ SUCCESS with auto_value."),
|
||||||
|
Param("auto_value", default=None,
|
||||||
|
doc="Value used in batch mode when auto_result is set."),
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(self, dict_item, parent=None, status_queue=None, filename=""):
|
def __init__(self, dict_item, parent=None, status_queue=None, filename=""):
|
||||||
self._name = cst.TYPE_VALUE_DLG.item_name
|
self._name = cst.TYPE_VALUE_DLG.item_name
|
||||||
super().__init__(dict_item, parent, status_queue, filename=filename)
|
super().__init__(dict_item, parent, status_queue, filename=filename)
|
||||||
|
|||||||
Reference in New Issue
Block a user