merged developer
Some checks failed
Build on RHEL9 / build (push) Successful in 2m51s
Build on RHEL8 / build (push) Failing after 4m48s

This commit is contained in:
mazzol_a 2025-05-15 17:20:52 +02:00
commit 9343e3c667
6 changed files with 133 additions and 274 deletions

View File

@ -65,6 +65,9 @@ configure_file( scripts/test_virtual.py
${CMAKE_BINARY_DIR}/test_virtual.py ${CMAKE_BINARY_DIR}/test_virtual.py
) )
configure_file(scripts/frameSynchronizerPullSocket.py
${CMAKE_BINARY_DIR}/bin/frameSynchronizerPullSocket.py COPYONLY)
configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/../VERSION configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/../VERSION
${CMAKE_BINARY_DIR}/bin/slsdet/VERSION ${CMAKE_BINARY_DIR}/bin/slsdet/VERSION
) )

View File

@ -104,11 +104,11 @@ void zmq_free(void *data, void *hint) { delete[] static_cast<char *>(data); }
void print_frames(const PortFrameMap &frame_port_map) { void print_frames(const PortFrameMap &frame_port_map) {
LOG(sls::logDEBUG) << "Printing frames"; LOG(sls::logDEBUG) << "Printing frames";
for (const auto &it : frame_port_map) { for (const auto &it : frame_port_map) {
uint16_t udpPort = it.first; const uint16_t udpPort = it.first;
const auto &frame_map = it.second; const auto &frame_map = it.second;
LOG(sls::logDEBUG) << "UDP port: " << udpPort; LOG(sls::logDEBUG) << "UDP port: " << udpPort;
for (const auto &frame : frame_map) { for (const auto &frame : frame_map) {
uint64_t fnum = frame.first; const uint64_t fnum = frame.first;
const auto &msg_list = frame.second; const auto &msg_list = frame.second;
LOG(sls::logDEBUG) LOG(sls::logDEBUG)
<< " acq index: " << fnum << '[' << msg_list.size() << ']'; << " acq index: " << fnum << '[' << msg_list.size() << ']';
@ -127,30 +127,26 @@ std::set<uint64_t> get_valid_fnums(const PortFrameMap &port_frame_map) {
// collect all unique frame numbers from all ports // collect all unique frame numbers from all ports
std::set<uint64_t> unique_fnums; std::set<uint64_t> unique_fnums;
for (auto it = port_frame_map.begin(); it != port_frame_map.begin(); ++it) { for (const auto &it : port_frame_map) {
const FrameMap &frame_map = it->second; const FrameMap &frame_map = it.second;
for (auto frame = frame_map.begin(); frame != frame_map.end(); for (const auto &frame : frame_map) {
++frame) { unique_fnums.insert(frame.first);
unique_fnums.insert(frame->first);
} }
} }
// collect valid frame numbers // collect valid frame numbers
for (auto &fnum : unique_fnums) { for (auto &fnum : unique_fnums) {
bool is_valid = true; bool is_valid = true;
for (auto it = port_frame_map.begin(); it != port_frame_map.end(); for (const auto &it : port_frame_map) {
++it) { const uint16_t port = it.first;
uint16_t port = it->first; const FrameMap &frame_map = it.second;
const FrameMap &frame_map = it->second;
auto frame = frame_map.find(fnum); auto frame = frame_map.find(fnum);
// invalid: fnum missing in one port // invalid: fnum missing in one port
if (frame == frame_map.end()) { if (frame == frame_map.end()) {
LOG(sls::logDEBUG) LOG(sls::logDEBUG)
<< "Fnum " << fnum << " is missing in port " << port; << "Fnum " << fnum << " is missing in port " << port;
// invalid: fnum greater than all in that port auto upper_frame = frame_map.upper_bound(fnum);
auto last_frame = std::prev(frame_map.end()); if (upper_frame == frame_map.end()) {
auto last_fnum = last_frame->first;
if (fnum > last_fnum) {
LOG(sls::logDEBUG) << "And no larger fnum found. Fnum " LOG(sls::logDEBUG) << "And no larger fnum found. Fnum "
<< fnum << " is invalid.\n"; << fnum << " is invalid.\n";
is_valid = false; is_valid = false;
@ -220,18 +216,26 @@ void Correlate(FrameStatus *stat) {
// sending all valid fnum data packets // sending all valid fnum data packets
for (const auto &fnum : valid_fnums) { for (const auto &fnum : valid_fnums) {
ZmqMsgList msg_list; ZmqMsgList msg_list;
PortFrameMap &port_frame_map = stat->frames; for (const auto &it : stat->frames) {
for (auto it = port_frame_map.begin(); const uint16_t port = it.first;
it != port_frame_map.end(); ++it) { const FrameMap &frame_map = it.second;
uint16_t port = it->first;
const FrameMap &frame_map = it->second;
auto frame = frame_map.find(fnum); auto frame = frame_map.find(fnum);
if (frame != frame_map.end()) { if (frame != frame_map.end()) {
msg_list.insert(msg_list.end(), msg_list.insert(msg_list.end(),
stat->frames[port][fnum].begin(), stat->frames[port][fnum].begin(),
stat->frames[port][fnum].end()); stat->frames[port][fnum].end());
// clean up }
for (zmq_msg_t *msg : stat->frames[port][fnum]) { }
LOG(printHeadersLevel)
<< "Sending data packets for fnum " << fnum;
zmq_send_multipart(socket, msg_list);
// clean up
for (const auto &it : stat->frames) {
const uint16_t port = it.first;
const FrameMap &frame_map = it.second;
auto frame = frame_map.find(fnum);
if (frame != frame_map.end()) {
for (zmq_msg_t *msg : frame->second) {
if (msg) { if (msg) {
zmq_msg_close(msg); zmq_msg_close(msg);
delete msg; delete msg;
@ -240,9 +244,6 @@ void Correlate(FrameStatus *stat) {
stat->frames[port].erase(fnum); stat->frames[port].erase(fnum);
} }
} }
LOG(printHeadersLevel)
<< "Sending data packets for fnum " << fnum;
zmq_send_multipart(socket, msg_list);
} }
} }
// sending all end packets // sending all end packets
@ -256,6 +257,21 @@ void Correlate(FrameStatus *stat) {
} }
} }
stat->ends.clear(); stat->ends.clear();
// clean up old frames
for (auto &it : stat->frames) {
FrameMap &frame_map = it.second;
for (auto &frame : frame_map) {
for (zmq_msg_t *msg : frame.second) {
if (msg) {
zmq_msg_close(msg);
delete msg;
}
}
frame.second.clear();
}
frame_map.clear();
}
stat->frames.clear();
} }
} }
} }

View File

@ -60,3 +60,5 @@ include(Catch)
catch_discover_tests(tests) catch_discover_tests(tests)
configure_file(scripts/test_simulators.py ${CMAKE_BINARY_DIR}/bin/test_simulators.py COPYONLY) configure_file(scripts/test_simulators.py ${CMAKE_BINARY_DIR}/bin/test_simulators.py COPYONLY)
configure_file(scripts/test_frame_synchronizer.py ${CMAKE_BINARY_DIR}/bin/test_frame_synchronizer.py COPYONLY)
configure_file(scripts/utils_for_test.py ${CMAKE_BINARY_DIR}/bin/utils_for_test.py COPYONLY)

View File

@ -44,14 +44,16 @@ def startFrameSynchronizer(num_mods, fp):
time.sleep(1) time.sleep(1)
def acquire(fp, det): def acquire(fp):
Log(LogLevel.INFO, 'Acquiring') Log(LogLevel.INFO, 'Acquiring')
Log(LogLevel.INFO, 'Acquiring', fp) Log(LogLevel.INFO, 'Acquiring', fp)
det.acquire() d = Detector()
d.acquire()
def testFramesCaught(name, det, num_frames): def testFramesCaught(name, num_frames):
fnum = det.rx_framescaught[0] d = Detector()
fnum = d.rx_framescaught[0]
if fnum != num_frames: if fnum != num_frames:
raise RuntimeException(f"{name} caught only {fnum}. Expected {num_frames}") raise RuntimeException(f"{name} caught only {fnum}. Expected {num_frames}")
@ -59,7 +61,7 @@ def testFramesCaught(name, det, num_frames):
Log(LogLevel.INFOGREEN, f'Frames caught test passed for {name}', fp) Log(LogLevel.INFOGREEN, f'Frames caught test passed for {name}', fp)
def testZmqHeadetTypeCount(name, det, num_mods, num_frames, fp): def testZmqHeadetTypeCount(name, num_mods, num_frames, fp):
Log(LogLevel.INFO, f"Testing Zmq Header type count for {name}") Log(LogLevel.INFO, f"Testing Zmq Header type count for {name}")
Log(LogLevel.INFO, f"Testing Zmq Header type count for {name}", fp) Log(LogLevel.INFO, f"Testing Zmq Header type count for {name}", fp)
@ -86,7 +88,8 @@ def testZmqHeadetTypeCount(name, det, num_mods, num_frames, fp):
continue continue
# test if file contents matches expected counts # test if file contents matches expected counts
num_ports_per_module = 1 if name == "gotthard2" else det.numinterfaces d = Detector()
num_ports_per_module = 1 if name == "gotthard2" else d.numinterfaces
total_num_frame_parts = num_ports_per_module * num_mods * num_frames total_num_frame_parts = num_ports_per_module * num_mods * num_frames
for htype, expected_count in [("header", num_mods), ("series_end", num_mods), ("module", total_num_frame_parts)]: for htype, expected_count in [("header", num_mods), ("series_end", num_mods), ("module", total_num_frame_parts)]:
if htype_counts[htype] != expected_count: if htype_counts[htype] != expected_count:
@ -108,13 +111,10 @@ def startTestsForAll(args, fp):
startDetectorVirtualServer(server, args.num_mods, fp) startDetectorVirtualServer(server, args.num_mods, fp)
startFrameSynchronizerPullSocket(server, fp) startFrameSynchronizerPullSocket(server, fp)
startFrameSynchronizer(args.num_mods, fp) startFrameSynchronizer(args.num_mods, fp)
d = loadConfig(name=server, rx_hostname=args.rx_hostname, settingsdir=args.settingspath, fp=fp, num_mods=args.num_mods, num_frames=args.num_frames) loadConfig(name=server, rx_hostname=args.rx_hostname, settingsdir=args.settingspath, fp=fp, num_mods=args.num_mods, num_frames=args.num_frames)
print("mac source adress: ", d.udp_srcmac) acquire(fp)
print("source ip: ", d.udp_srcip) testFramesCaught(server, args.num_frames)
print("detector type: ", d.type) testZmqHeadetTypeCount(server, args.num_mods, args.num_frames, fp)
acquire(fp, d)
testFramesCaught(server, d, args.num_frames)
testZmqHeadetTypeCount(server, d, args.num_mods, args.num_frames, fp)
Log(LogLevel.INFO, '\n') Log(LogLevel.INFO, '\n')
except Exception as e: except Exception as e:
raise RuntimeException(f'Synchronizer Tests failed') from e raise RuntimeException(f'Synchronizer Tests failed') from e

View File

@ -4,244 +4,86 @@
This file is used to start up simulators, receivers and run all the tests on them and finally kill the simulators and receivers. This file is used to start up simulators, receivers and run all the tests on them and finally kill the simulators and receivers.
''' '''
import argparse import argparse
import os, sys, subprocess, time, colorama import sys, subprocess, time, traceback
from colorama import Fore, Style from slsdet import Detector
from slsdet import Detector, detectorType, detectorSettings from slsdet.defines import DEFAULT_TCP_RX_PORTNO
from slsdet.defines import DEFAULT_TCP_CNTRL_PORTNO, DEFAULT_TCP_RX_PORTNO, DEFAULT_UDP_DST_PORTNO
HALFMOD2_TCP_CNTRL_PORTNO=1955
HALFMOD2_TCP_RX_PORTNO=1957
colorama.init(autoreset=True) from utils_for_test import (
Log,
def Log(color, message): LogLevel,
print(f"{color}{message}{Style.RESET_ALL}", flush=True) RuntimeException,
checkIfProcessRunning,
class RuntimeException (Exception): killProcess,
def __init__ (self, message): cleanup,
super().__init__(Log(Fore.RED, message)) cleanSharedmemory,
startProcessInBackground,
def checkIfProcessRunning(processName): runProcessWithLogFile,
cmd = f"pgrep -f {processName}" startDetectorVirtualServer,
res = subprocess.getoutput(cmd) loadConfig,
return res.strip().splitlines() ParseArguments
)
def killProcess(name): LOG_PREFIX_FNAME = '/tmp/slsDetectorPackage_virtual_test'
pids = checkIfProcessRunning(name) MAIN_LOG_FNAME = LOG_PREFIX_FNAME + '_log.txt'
if pids: GENERAL_TESTS_LOG_FNAME = LOG_PREFIX_FNAME + '_results_general.txt'
Log(Fore.GREEN, f"Killing '{name}' processes with PIDs: {', '.join(pids)}") CMD_TEST_LOG_PREFIX_FNAME = LOG_PREFIX_FNAME + '_results_cmd_'
for pid in pids:
try:
p = subprocess.run(['kill', pid])
if p.returncode != 0 and bool(checkIfProcessRunning(name)):
raise RuntimeException(f"Could not kill {name} with pid {pid}")
except Exception as e:
Log(Fore.RED, f"Failed to kill process {name} pid:{pid}. Exception occured: [code:{e}, msg:{e.stderr}]")
raise
#else:
# Log(Fore.WHITE, 'process not running : ' + name)
def cleanup(fp): def startReceiver(num_mods, fp):
''' if num_mods == 1:
kill both servers, receivers and clean shared memory cmd = ['slsReceiver']
''' else:
Log(Fore.GREEN, 'Cleaning up...') cmd = ['slsMultiReceiver', str(DEFAULT_TCP_RX_PORTNO), str(num_mods)]
killProcess('DetectorServer_virtual') # in 10.0.0
killProcess('slsReceiver') #cmd = ['slsMultiReceiver', '-p', str(DEFAULT_TCP_RX_PORTNO), '-n', str(num_mods)]
killProcess('slsMultiReceiver') startProcessInBackground(cmd, fp)
cleanSharedmemory(fp) time.sleep(1)
def cleanSharedmemory(fp): def startGeneralTests(fp):
Log(Fore.GREEN, 'Cleaning up shared memory...') fname = GENERAL_TESTS_LOG_FNAME
cmd = ['tests', '--abort', '-s']
try: try:
p = subprocess.run(['sls_detector_get', 'free'], stdout=fp, stderr=fp)
except:
Log(Fore.RED, 'Could not free shared memory')
raise
def startProcessInBackground(name):
try:
# in background and dont print output
p = subprocess.Popen(name.split(), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, restore_signals=False)
Log(Fore.GREEN, 'Starting up ' + name + ' ...')
except Exception as e:
Log(Fore.RED, f'Could not start {name}:{e}')
raise
def startServer(name):
startProcessInBackground(name + 'DetectorServer_virtual')
# second half
if name == 'eiger':
startProcessInBackground(name + 'DetectorServer_virtual -p' + str(HALFMOD2_TCP_CNTRL_PORTNO))
tStartup = 6
Log(Fore.WHITE, 'Takes ' + str(tStartup) + ' seconds... Please be patient')
time.sleep(tStartup)
def startReceiver(name):
startProcessInBackground('slsReceiver')
# second half
if name == 'eiger':
startProcessInBackground('slsReceiver -t' + str(HALFMOD2_TCP_RX_PORTNO))
time.sleep(2)
def loadConfig(name, rx_hostname, settingsdir):
Log(Fore.GREEN, 'Loading config')
try:
d = Detector()
if name == 'eiger':
d.hostname = 'localhost:' + str(DEFAULT_TCP_CNTRL_PORTNO) + '+localhost:' + str(HALFMOD2_TCP_CNTRL_PORTNO)
#d.udp_dstport = {2: 50003}
# will set up for every module
d.udp_dstport = DEFAULT_UDP_DST_PORTNO
d.udp_dstport2 = DEFAULT_UDP_DST_PORTNO + 1
d.rx_hostname = rx_hostname + ':' + str(DEFAULT_TCP_RX_PORTNO) + '+' + rx_hostname + ':' + str(HALFMOD2_TCP_RX_PORTNO)
d.udp_dstip = 'auto'
d.trimen = [4500, 5400, 6400]
d.settingspath = settingsdir + '/eiger/'
d.setThresholdEnergy(4500, detectorSettings.STANDARD)
else:
d.hostname = 'localhost'
d.rx_hostname = rx_hostname
d.udp_dstip = 'auto'
d.udp_srcip = 'auto'
if d.type == detectorType.JUNGFRAU or d.type == detectorType.MOENCH or d.type == detectorType.XILINX_CHIPTESTBOARD:
d.powerchip = 1
if d.type == detectorType.XILINX_CHIPTESTBOARD:
d.configureTransceiver()
except:
Log(Fore.RED, 'Could not load config for ' + name)
raise
def startCmdTests(name, fp, fname):
Log(Fore.GREEN, 'Cmd Tests for ' + name)
cmd = 'tests --abort [.cmdcall] -s -o ' + fname
try:
subprocess.run(cmd.split(), stdout=fp, stderr=fp, check=True, text=True)
except subprocess.CalledProcessError as e:
pass
with open (fname, 'r') as f:
for line in f:
if "FAILED" in line:
msg = 'Cmd tests failed for ' + name + '!!!'
sys.stdout = original_stdout
Log(Fore.RED, msg)
Log(Fore.RED, line)
sys.stdout = fp
raise Exception(msg)
Log(Fore.GREEN, 'Cmd Tests successful for ' + name)
def startGeneralTests(fp, fname):
Log(Fore.GREEN, 'General Tests')
cmd = 'tests --abort -s -o ' + fname
try:
subprocess.run(cmd.split(), stdout=fp, stderr=fp, check=True, text=True)
except subprocess.CalledProcessError as e:
pass
with open (fname, 'r') as f:
for line in f:
if "FAILED" in line:
msg = 'General tests failed !!!'
sys.stdout = original_stdout
Log(Fore.RED, msg + '\n' + line)
sys.stdout = fp
raise Exception(msg)
Log(Fore.GREEN, 'General Tests successful')
# parse cmd line for rx_hostname and settingspath using the argparse library
parser = argparse.ArgumentParser(description = 'automated tests with the virtual detector servers')
parser.add_argument('rx_hostname', nargs='?', default='localhost', help = 'hostname/ip of the current machine')
parser.add_argument('settingspath', nargs='?', default='../../settingsdir', help = 'Relative or absolut path to the settingspath')
parser.add_argument('-s', '--servers', help='Detector servers to run', nargs='*')
args = parser.parse_args()
if args.servers is None:
servers = [
'eiger',
'jungfrau',
'mythen3',
'gotthard2',
'ctb',
'moench',
'xilinx_ctb'
]
else:
servers = args.servers
Log(Fore.WHITE, 'Arguments:\nrx_hostname: ' + args.rx_hostname + '\nsettingspath: \'' + args.settingspath + '\nservers: \'' + ' '.join(servers) + '\'')
# redirect to file
prefix_fname = '/tmp/slsDetectorPackage_virtual_test'
original_stdout = sys.stdout
original_stderr = sys.stderr
fname = prefix_fname + '_log.txt'
Log(Fore.BLUE, '\nLog File: ' + fname)
with open(fname, 'w') as fp:
# general tests
file_results = prefix_fname + '_results_general.txt'
Log(Fore.BLUE, 'General tests (results: ' + file_results + ')')
sys.stdout = fp
sys.stderr = fp
Log(Fore.BLUE, 'General tests (results: ' + file_results + ')')
try:
startGeneralTests(fp, file_results)
cleanup(fp) cleanup(fp)
runProcessWithLogFile('General Tests', cmd, fp, fname)
testError = False
for server in servers:
try:
# print to terminal for progress
sys.stdout = original_stdout
sys.stderr = original_stderr
file_results = prefix_fname + '_results_cmd_' + server + '.txt'
Log(Fore.BLUE, 'Cmd tests for ' + server + ' (results: ' + file_results + ')')
sys.stdout = fp
sys.stderr = fp
Log(Fore.BLUE, 'Cmd tests for ' + server + ' (results: ' + file_results + ')')
# cmd tests for det
cleanup(fp)
startServer(server)
startReceiver(server)
loadConfig(server, args.rx_hostname, args.settingspath)
startCmdTests(server, fp, file_results)
cleanup(fp)
except Exception as e:
# redirect to terminal
sys.stdout = original_stdout
sys.stderr = original_stderr
Log(Fore.RED, f'Exception caught while testing {server}. Cleaning up...')
testError = True
break
# redirect to terminal
sys.stdout = original_stdout
sys.stderr = original_stderr
if not testError:
Log(Fore.GREEN, 'Passed all tests for virtual detectors \n' + str(servers))
except Exception as e: except Exception as e:
# redirect to terminal raise RuntimeException(f'General tests failed.') from e
sys.stdout = original_stdout
sys.stderr = original_stderr
Log(Fore.RED, f'Exception caught with general testing. Cleaning up...')
cleanSharedmemory(sys.stdout)
def startCmdTestsForAll(args, fp):
for server in args.servers:
try:
num_mods = 2 if server == 'eiger' else 1
fname = CMD_TEST_LOG_PREFIX_FNAME + server + '.txt'
cmd = ['tests', '--abort', '[.cmdcall]', '-s']
Log(LogLevel.INFOBLUE, f'Starting Cmd Tests for {server}')
cleanup(fp)
startDetectorVirtualServer(name=server, num_mods=num_mods, fp=fp)
startReceiver(num_mods, fp)
loadConfig(name=server, rx_hostname=args.rx_hostname, settingsdir=args.settingspath, fp=fp, num_mods=num_mods)
runProcessWithLogFile('Cmd Tests for ' + server, cmd, fp, fname)
except Exception as e:
raise RuntimeException(f'Cmd Tests failed for {server}.') from e
Log(LogLevel.INFOGREEN, 'Passed all tests for all detectors \n' + str(args.servers))
if __name__ == '__main__':
args = ParseArguments('Automated tests with the virtual detector servers')
if args.num_mods > 1:
raise RuntimeException(f'Cannot support multiple modules at the moment (except Eiger).')
Log(LogLevel.INFOBLUE, '\nLog File: ' + MAIN_LOG_FNAME + '\n')
with open(MAIN_LOG_FNAME, 'w') as fp:
try:
startGeneralTests(fp)
startCmdTestsForAll(args, fp)
cleanup(fp)
except Exception as e:
with open(MAIN_LOG_FNAME, 'a') as fp_error:
traceback.print_exc(file=fp_error)
cleanup(fp)
Log(LogLevel.ERROR, f'Tests Failed.')

View File

@ -138,11 +138,9 @@ def runProcessWithLogFile(name, cmd, fp, log_file_name):
def startDetectorVirtualServer(name :str, num_mods, fp): def startDetectorVirtualServer(name :str, num_mods, fp):
for i in range(num_mods): for i in range(num_mods):
subprocess.run(["which", name + "DetectorServer_virtual"])
port_no = SERVER_START_PORTNO + (i * 2) port_no = SERVER_START_PORTNO + (i * 2)
cmd = [name + 'DetectorServer_virtual', '-p', str(port_no)] cmd = [name + 'DetectorServer_virtual', '-p', str(port_no)]
startProcessInBackgroundWithLogFile(cmd, fp, "/tmp/virtual_det_" + name + str(i) + ".txt") startProcessInBackground(cmd, fp)
match name: match name:
case 'jungfrau': case 'jungfrau':
time.sleep(7) time.sleep(7)
@ -158,7 +156,7 @@ def connectToVirtualServers(name, num_mods):
except Exception as e: except Exception as e:
raise RuntimeException(f'Could not create Detector object for {name}. Error: {str(e)}') from e raise RuntimeException(f'Could not create Detector object for {name}. Error: {str(e)}') from e
counts_sec = 100 counts_sec = 5
while (counts_sec != 0): while (counts_sec != 0):
try: try:
d.virtual = [num_mods, SERVER_START_PORTNO] d.virtual = [num_mods, SERVER_START_PORTNO]
@ -203,8 +201,6 @@ def loadConfig(name, rx_hostname, settingsdir, fp, num_mods = 1, num_frames = 1)
d.frames = num_frames d.frames = num_frames
except Exception as e: except Exception as e:
raise RuntimeException(f'Could not load config for {name}. Error: {str(e)}') from e raise RuntimeException(f'Could not load config for {name}. Error: {str(e)}') from e
return d
def ParseArguments(description, default_num_mods=1): def ParseArguments(description, default_num_mods=1):