From 00e9ee9bccc8b0142ca2644a8ef1c77c62ea8c85 Mon Sep 17 00:00:00 2001 From: tligui_y Date: Fri, 8 Aug 2025 12:55:23 +0200 Subject: [PATCH] Update tests/test_utils_opmsg.py --- tests/test_utils_opmsg.py | 81 ++++++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 36 deletions(-) diff --git a/tests/test_utils_opmsg.py b/tests/test_utils_opmsg.py index 750911e5a..3f4e58ebf 100644 --- a/tests/test_utils_opmsg.py +++ b/tests/test_utils_opmsg.py @@ -6,86 +6,95 @@ from morbidissimo import MorIOC from slic.utils.opmsg import * -# IOC simulation def ioc(): """ Start MorIOC servers for ALL PVs used by: - OperationMessageStatus (STATUS, STATUS-DATE) - OperationMessageEntry (OP-DATEi, OP-MSGi) - OperationMessage (OP-MSG-tmp) - - OperationMessages (same prefixes as OperationMessage for each ID) - MachineStatus (CATEGORY, DOWNTIME) One MorIOC per prefix: - - For each ID in IDS: "SF-OP:{ID}-MSG" - - For each beamline in BEAMLINES: "SF-STATUS-{beamline}" + - For each ID in IDS: 'SF-OP:{ID}-MSG' + - For each beamline in BEAMLINES: 'SF-STATUS-{beamline}' """ - STATUS_ENUMS = ["OFFLINE", "PREPARATION", "REMOTE", "ATTENDED"] - CATEGORY_ENUMS = ["USER", "MD", "SD", "ACCESS", "DOWN"] + # Use TUPLES for enums so enum_strs is populated properly + STATUS_ENUMS = ("OFFLINE", "PREPARATION", "REMOTE", "ATTENDED") + CATEGORY_ENUMS = ("USER", "MD", "SD", "ACCESS", "DOWN") - def run_op_prefix(prefix: str): + def run_op_prefix(prefix: string): """ - IOC for OP message space (shared by OperationMessage, OperationMessageEntry, OperationMessageStatus): + OP message space: - STATUS (enum), STATUS-DATE (str) - OP-DATE0..N_MSG_HISTORY-1 (str), OP-MSG0..N_MSG_HISTORY-1 (str) - - OP-MSG-tmp (str) + - OP-MSG-tmp (str) AND OP-MSG-TMP (str) (both variants, kept in sync) """ with MorIOC(prefix) as mor: host_kwargs = { - "STATUS": STATUS_ENUMS, + "STATUS": STATUS_ENUMS, # true enum (tuple) **{"STATUS-DATE": str}, **{f"OP-DATE{i}": str for i in range(N_MSG_HISTORY)}, **{f"OP-MSG{i}": str for i in range(N_MSG_HISTORY)}, + # host BOTH tmp variants to avoid case-sensitivity issues **{"OP-MSG-tmp": str}, + **{"OP-MSG-TMP": str}, } mor.host(**host_kwargs) - # Deterministic initial values for all tests - status_val = "OFFLINE" - status_date_val = "2024-01-01 00:00:00" - dates = {f"OP-DATE{i}": f"2024-01-01 00:00:0{i}" for i in range(N_MSG_HISTORY)} - msgs = {f"OP-MSG{i}": f"Initial message {i}" for i in range(N_MSG_HISTORY)} - tmp_msg = "" + # Seed ONCE, then stop clobbering + initial = { + "STATUS": "OFFLINE", + "STATUS-DATE": "2024-01-01 00:00:00", + **{f"OP-DATE{i}": f"2024-01-01 00:00:0{i}" for i in range(N_MSG_HISTORY)}, + **{f"OP-MSG{i}": f"Initial message {i}" for i in range(N_MSG_HISTORY)}, + "OP-MSG-tmp": "", + "OP-MSG-TMP": "", + } + mor.serve(**initial) + # Loop WITHOUT serving values again (so client puts persist) while True: - mor.serve( - STATUS=status_val, - **{"STATUS-DATE": status_date_val}, - **dates, - **msgs, - **{"OP-MSG-tmp": tmp_msg}, - ) - time.sleep(0.01) + time.sleep(0.02) def run_status_prefix(beamline: str): - """IOC for MachineStatus: CATEGORY (enum), DOWNTIME (str).""" + """MachineStatus space: CATEGORY (enum), DOWNTIME (str).""" with MorIOC(f"SF-STATUS-{beamline}") as mor: - mor.host(CATEGORY=CATEGORY_ENUMS, DOWNTIME=str) - category_val = "USER" - downtime_val = "00:00:00" + mor.host( + CATEGORY=CATEGORY_ENUMS, # true enum (tuple) + DOWNTIME=str, + ) + # Seed ONCE + mor.serve(CATEGORY="USER", DOWNTIME="00:00:00") + + # Then do nothing; client updates must persist while True: - mor.serve(CATEGORY=category_val, DOWNTIME=downtime_val) - time.sleep(0.01) + time.sleep(0.02) - threads: list[threading.Thread] = [] + threads = [] - # All operation-message prefixes (OperationMessage*, OperationMessageStatus) for ID in IDS.values(): prefix = f"SF-OP:{ID}-MSG" t = threading.Thread(target=run_op_prefix, args=(prefix,), daemon=True) + t.start() threads.append(t) - # All machine-status prefixes for beamlines for bl in BEAMLINES: t = threading.Thread(target=run_status_prefix, args=(bl,), daemon=True) + t.start() threads.append(t) - for t in threads: - t.start() - return threads +@pytest.fixture(scope="module", autouse=True) +def run_all_iocs(): + threads = ioc() + # Short boot delay to ensure IOCs are listening + time.sleep(0.3) + yield + # Daemon threads exit with pytest + + # Autouse fixture to start IOC once per module @pytest.fixture(scope="module", autouse=True) def run_all_iocs():