Files
testium/src/testium/interpreter/utils/constants.py
francois 1b2d427ced Add parallel test item with thread-aware stdout routing
The parallel item runs branches concurrently with sync:all or sync:any
policy and optional per-branch wait_for synchronization. Each branch
runs in its own daemon thread and produces a clean per-item entry in
the SQLite report; the live output is prefixed [<branch_name>] so
concurrent branches stay readable.

Supporting changes:
- StdoutProxy (lib/stdout_redirect.py): thread-aware sys.stdout/stderr
  with per-thread capture buffers and per-branch live-output prefix.
  Adds writeln() for Python 3.14 unittest compatibility.
- TestItemContainer: shared base extracted from Group/Cycle for the
  sequential children execution pattern.
- TestItemSleep: interruptible loop polling _is_stopped so sync:any
  can cancel slow branches quickly.
- TestReport: thread-safe SQLite (check_same_thread=False + lock).

Also drops the unused -m/--terminal mode and its module.

Validation: 11 scenarios in test/validation/items/parallel covering
sync:all/any, no_fail, wait_for + timeout, conditions, multi-branch,
nested parallel, parallel inside loop, real branch failure.

Documentation: new parallel_test_item.rst added to the manual.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 23:23:31 +02:00

137 lines
4.1 KiB
Python

from enum import Enum
class TestItemEnum():
def __init__(self, cmd, name, item_class=None) -> None:
self.name = name
self.cmd = cmd
self.item_class = item_class
class TestItemType(Enum):
TYPE_UNITTEST = TestItemEnum("unittest", "unittest")
TYPE_UNITTEST_STEP = TestItemEnum("unittest_step", "unittest step")
TYPE_CONSOLE = TestItemEnum("console", "Console")
TYPE_CONSOLE_ACTION = TestItemEnum("console_action", "Console action")
TYPE_CYCLE = TestItemEnum("loop", "Cycle")
TYPE_PY_FUNCTION = TestItemEnum("py_func", "python Function")
TYPE_LUA_FUNCTION = TestItemEnum("lua_func", "lua Function")
TYPE_REPORT = TestItemEnum("report", "Report")
TYPE_GIT = TestItemEnum("git", "git repository")
TYPE_GRAPH = TestItemEnum("plot", "Runtime plot")
TYPE_GRAPH_ACTION = TestItemEnum("plot_action", "Runtime plot action")
TYPE_GROUP = TestItemEnum("group", "Group")
TYPE_IMAGE_DLG = TestItemEnum("dialog_image", "Image Dialog")
TYPE_MESSAGE_DLG = TestItemEnum("dialog_message", "Message Dialog")
TYPE_LET = TestItemEnum("let", "Let")
TYPE_CHECK = TestItemEnum("check", "Check value")
TYPE_NOTE_DLG = TestItemEnum("dialog_note", "Note Dialog")
TYPE_QUESTION_DLG = TestItemEnum("dialog_question", "Question Dialog")
TYPE_SLEEP = TestItemEnum("sleep", "Sleep")
TYPE_REFERENCE_DLG = TestItemEnum("dialog_references", "References Dialog")
TYPE_VALUE_DLG = TestItemEnum("dialog_value", "Value Dialog")
TYPE_CHOICES_DLG = TestItemEnum("dialog_choices", "Choices Dialog")
TYPE_RUN = TestItemEnum("run", "Run tum")
TYPE_JSON_RPC = TestItemEnum("json_rpc", "JSON-RPC")
TYPE_JSON_RPC_ACTION = TestItemEnum("json_rpc_action", "JSON-RPC action")
TYPE_PARALLEL = TestItemEnum("parallel", "Parallel")
TYPE_PARALLEL_BRANCH = TestItemEnum("parallel_branch", "Parallel branch")
TYPE_ROOT = TestItemEnum("default", "default")
@staticmethod
def list():
return list(map(lambda c: c.value, TestItemType))
@property
def item_name(self):
return self.value.name
@property
def item_cmd(self):
return self.value.cmd
@property
def item_class(self):
return self.value.item_class
@item_class.setter
def item_class(self, c):
self.value.item_class = c
def __str__(self):
return self.value.name
TEST_TYPE_LIST = [e for e in TestItemType]
REP_TYPE_SQLITE = "sqlite"
REP_TYPE_JUNIT = "junit"
REP_TYPE_JSON = "json"
REP_TYPE_HTML = "html"
REP_TYPE_TEXT = "text"
REP_TYPES = [
REP_TYPE_SQLITE,
REP_TYPE_JUNIT,
REP_TYPE_JSON,
REP_TYPE_HTML,
REP_TYPE_TEXT,
]
# Report related constants
DB_REPORT_VERSION = "report_version"
DB_TEST_FILE = "test_file"
DB_TEST_SET_NAME = "test_name"
DB_TEST_SET_RESULT = "test_result"
DB_TEST_REVISION = "test_revision"
DB_SEQUENCER_VERSION = "testium_version"
DB_TESTRUN_DATE = "testrun_date"
DB_TESTRUN_TIME = "testrun_time"
DB_TEST_SET_DURATION = "test_duration"
DB_HEADER_FIELDS = [
DB_REPORT_VERSION,
DB_TEST_FILE,
DB_TEST_SET_NAME,
DB_TEST_SET_RESULT,
DB_TEST_REVISION,
DB_SEQUENCER_VERSION,
DB_TESTRUN_DATE,
DB_TESTRUN_TIME,
DB_TEST_SET_DURATION,
]
DB_TEST_TIMESTAMP_START = "timestamp_start"
DB_TEST_ID = "test_id"
DB_TEST_PARENT_ID = "parent_id"
DB_TEST_NAME = "test_name"
DB_TEST_TYPE = "test_type"
DB_TEST_KEY = "report_key"
DB_TEST_RESULT = "result"
DB_TEST_MESSAGE = "message"
DB_TEST_DURATION = "duration"
DB_TEST_DATA = "data"
DB_TEST_LEVEL = "level"
DB_TEST_LOG = "log"
DB_TEST_FIELDS = [
DB_TEST_TIMESTAMP_START,
DB_TEST_ID,
DB_TEST_PARENT_ID,
DB_TEST_NAME,
DB_TEST_TYPE,
DB_TEST_KEY,
DB_TEST_RESULT,
DB_TEST_MESSAGE,
DB_TEST_DURATION,
DB_TEST_DATA,
DB_TEST_LEVEL,
DB_TEST_LOG,
]
ICON_THEMES_PREFIX = [
":/color",
":/black",
":/white",
]
FOLDED_CHAR = "."