This commit is contained in:
+45
-36
@@ -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():
|
||||
|
||||
Reference in New Issue
Block a user