From 8b0a23dcc98bdf4f04cfa097132f430459cc1bb4 Mon Sep 17 00:00:00 2001 From: Kurt Biery Date: Thu, 16 Apr 2026 12:12:49 -0500 Subject: [PATCH 1/4] Added an integtest to help insure that the system continues to work fine when an existing configuration that includes TPG (in all its glory) just has TPG in the readout apps turned off. --- integtest/disabled_tpg_test.py | 180 +++++++++++++++++++++++++++++++++ 1 file changed, 180 insertions(+) create mode 100755 integtest/disabled_tpg_test.py diff --git a/integtest/disabled_tpg_test.py b/integtest/disabled_tpg_test.py new file mode 100755 index 0000000..ed4dcf9 --- /dev/null +++ b/integtest/disabled_tpg_test.py @@ -0,0 +1,180 @@ +import pytest +import copy +import os + +import integrationtest.data_file_checks as data_file_checks +import integrationtest.log_file_checks as log_file_checks +import integrationtest.basic_checks as basic_checks +import integrationtest.data_classes as data_classes +import integrationtest.resource_validation as resource_validation +from integrationtest.get_pytest_tmpdir import get_pytest_tmpdir +from integrationtest.verbosity_helper import IntegtestVerbosityLevels + +import functools +print = functools.partial(print, flush=True) # always flush print() output + +pytest_plugins = "integrationtest.integrationtest_drunc" + +# Values that help determine the running conditions +run_duration = 20 # seconds + +# Default values for validation parameters +check_for_logfile_errors = True +expected_event_count = run_duration * (1.0 + 3.0) # 1 from RTCM, 3 from FakeHSI +expected_event_count_tolerance = expected_event_count / 10.0 + +wibeth_frag_params = { + "fragment_type_description": "WIBEth", + "fragment_type": "WIBEth", + "expected_fragment_count": 4, + "min_size_bytes": 7272, + "max_size_bytes": 28872, +} +# sizes: 128 is for one TC with zero TAs inside it (72+56) +# 208 is for one TC with one TA inside it (72+56+80) +# 264 is for two TCs with one TA in one of them (72+56+80+56) +triggercandidate_frag_params = { + "fragment_type_description": "Trigger Candidate", + "fragment_type": "Trigger_Candidate", + "expected_fragment_count": 1, + "min_size_bytes": 128, + "max_size_bytes": 128, + "debug_mask": 0x0, +} +triggerprimitive_frag_params = { + "fragment_type_description": "Trigger Primitive", + "fragment_type": "Trigger_Primitive", + "expected_fragment_count": 0, + "min_size_bytes": 72, + "max_size_bytes": 168, +} +hsi_frag_params = { + "fragment_type_description": "HSI", + "fragment_type": "Hardware_Signal", + "expected_fragment_count": 1, + "min_size_bytes": 72, + "max_size_bytes": 100, + "frag_sizes_by_TC_type": {"kTiming": {"min_size_bytes": 100, "max_size_bytes": 100}, + "default": {"min_size_bytes": 72, "max_size_bytes": 100} } +} +ignored_logfile_problems = { + "-controller": [ + ], + "local-connection-server": [ + "errorlog: -", + ], + # 04-Mar-2026, KAB: added the absl::InitializeLog warning message to the ignored list for + # all DAQ processes, given that we currently don't have a way suppress it at its source. + r".*": [ + r"WARNING: All log messages before absl::InitializeLog\(\) is called are written to STDERR" + ] +} + +# Determine if this computer has enough resources for these tests +resource_validator = resource_validation.ResourceValidator() +resource_validator.cpu_count_needs(30, 60) # 3 for each data source (incl TPG) plus 6 more for everything else +resource_validator.free_memory_needs(15, 24) # 25% more than what we observe being used ('free -h') +actual_output_path = get_pytest_tmpdir() +resource_validator.free_disk_space_needs(actual_output_path, 1) # more than what we observe + +# The arguments to pass to the config generator, excluding the json +# output directory (the test framework handles that) + +common_config_obj = data_classes.drunc_config() +common_config_obj.op_env = "test" +common_config_obj.config_db = ( + os.path.dirname(__file__) + "/../config/daqsystemtest/example-configs.data.xml" +) +common_config_obj.config_substitutions.append( + data_classes.attribute_substitution( + obj_class="TCDataProcessor", # 12-Nov-2025, KAB: turned off the merging of + obj_id="def-tc-processor", # overlapping TCs so that we get more consistent + updates={ # numbers of TriggerRecords in the output files. + "merge_overlapping_tcs": False + },) +) +common_config_obj.config_substitutions.append( + data_classes.attribute_substitution( + obj_class="ReadoutApplication", + obj_id="ru-01", + updates={ + "tp_generation_enabled": 0, + "ta_generation_enabled": 0, + },) +) + +onebyone_local_conf = copy.deepcopy(common_config_obj) +onebyone_local_conf.session = "local-1x1-config" + +confgen_arguments = { + "Local 1x1 Conf": onebyone_local_conf, +} + +# The commands to run in dunerc, as a list +dunerc_command_list = ( + "boot wait 2 conf start --run-number 101 wait 1 enable-triggers wait ".split() + + [str(run_duration)] + + "disable-triggers wait 2 drain-dataflow wait 2 stop-trigger-sources stop scrap terminate".split() +) + +# The tests themselves + + +def test_dunerc_success(run_dunerc, caplog): + # check for run control success, problems during pytest setup, etc. + basic_checks.basic_checks(run_dunerc, caplog, print_test_name=True) + + +def test_log_files(run_dunerc): + session_name = run_dunerc.session_name if run_dunerc.session_name is not None else run_dunerc.session + + # Check that at least some of the expected log files are present + assert any( + f"{session_name}_df-01" in str(logname) + for logname in run_dunerc.log_files + ) + assert any( + f"{session_name}_dfo" in str(logname) for logname in run_dunerc.log_files + ) + assert any( + f"{session_name}_mlt" in str(logname) for logname in run_dunerc.log_files + ) + assert any( + f"{session_name}_ru" in str(logname) for logname in run_dunerc.log_files + ) + + if check_for_logfile_errors: + # Check that there are no warnings or errors in the log files + assert log_file_checks.logs_are_error_free( + run_dunerc.log_files, True, True, ignored_logfile_problems, + verbosity_helper=run_dunerc.verbosity_helper + ) + + +def test_data_files(run_dunerc): + expected_file_count = 1 + + # Run some tests on the output data file + assert len(run_dunerc.data_files) == expected_file_count, f"Unexpected file count: Actual: {len(run_dunerc.data_files)}, Expected: {expected_file_count}" + + fragment_check_list = [triggercandidate_frag_params, hsi_frag_params] + fragment_check_list.append(wibeth_frag_params) + fragment_check_list.append(triggerprimitive_frag_params) + + all_ok = True + for idx in range(len(run_dunerc.data_files)): + data_file = data_file_checks.DataFile(run_dunerc.data_files[idx], run_dunerc.verbosity_helper) + all_ok &= data_file_checks.sanity_check(data_file) + all_ok &= data_file_checks.check_file_attributes(data_file) + all_ok &= data_file_checks.check_event_count( + data_file, expected_event_count, expected_event_count_tolerance + ) + for jdx in range(len(fragment_check_list)): + all_ok &= data_file_checks.check_fragment_count( + data_file, fragment_check_list[jdx] + ) + all_ok &= data_file_checks.check_fragment_sizes( + data_file, fragment_check_list[jdx] + ) + + assert all_ok From d8d47923844321d2dd7520263044e354ea90b75a Mon Sep 17 00:00:00 2001 From: Kurt Biery Date: Fri, 1 May 2026 09:02:35 -0500 Subject: [PATCH 2/4] turned off the execute bit for disabled_tpg_test.py --- integtest/disabled_tpg_test.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 integtest/disabled_tpg_test.py diff --git a/integtest/disabled_tpg_test.py b/integtest/disabled_tpg_test.py old mode 100755 new mode 100644 From d556af3b4791737bd00b0b06b07665a7b00c5cf8 Mon Sep 17 00:00:00 2001 From: Kurt Biery Date: Fri, 1 May 2026 09:36:09 -0500 Subject: [PATCH 3/4] Updated the disabled_tpg_test to take into account recent changes in drunc_config session names --- integtest/disabled_tpg_test.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/integtest/disabled_tpg_test.py b/integtest/disabled_tpg_test.py index ed4dcf9..8d8b60c 100644 --- a/integtest/disabled_tpg_test.py +++ b/integtest/disabled_tpg_test.py @@ -104,7 +104,7 @@ ) onebyone_local_conf = copy.deepcopy(common_config_obj) -onebyone_local_conf.session = "local-1x1-config" +onebyone_local_conf.config_session_name = "local-1x1-config" confgen_arguments = { "Local 1x1 Conf": onebyone_local_conf, @@ -126,21 +126,19 @@ def test_dunerc_success(run_dunerc, caplog): def test_log_files(run_dunerc): - session_name = run_dunerc.session_name if run_dunerc.session_name is not None else run_dunerc.session - # Check that at least some of the expected log files are present assert any( - f"{session_name}_df-01" in str(logname) + f"{run_dunerc.daq_session_name}_df-01" in str(logname) for logname in run_dunerc.log_files ) assert any( - f"{session_name}_dfo" in str(logname) for logname in run_dunerc.log_files + f"{run_dunerc.daq_session_name}_dfo" in str(logname) for logname in run_dunerc.log_files ) assert any( - f"{session_name}_mlt" in str(logname) for logname in run_dunerc.log_files + f"{run_dunerc.daq_session_name}_mlt" in str(logname) for logname in run_dunerc.log_files ) assert any( - f"{session_name}_ru" in str(logname) for logname in run_dunerc.log_files + f"{run_dunerc.daq_session_name}_ru" in str(logname) for logname in run_dunerc.log_files ) if check_for_logfile_errors: From b13459b2e4c977b4c84ea22f47332f53ae7ba1fa Mon Sep 17 00:00:00 2001 From: Kurt Biery Date: Fri, 1 May 2026 10:11:24 -0500 Subject: [PATCH 4/4] Added comments to the top of the disabled_tpg_test.py to help explain its purpose. --- integtest/disabled_tpg_test.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/integtest/disabled_tpg_test.py b/integtest/disabled_tpg_test.py index 8d8b60c..5f4fef2 100644 --- a/integtest/disabled_tpg_test.py +++ b/integtest/disabled_tpg_test.py @@ -1,3 +1,13 @@ +# 01-May-2026, KAB: the goal of this test is to check whether configurations that, A) have +# most/all of the components of the system that are needed for TriggerPrimitive generation +# included and B) have all of the configuration parameters that control TPG set to values +# that enable TPG (except for two), run correctly. The two parameters that are set to values +# that disable TPG are the tp_generation_enabled and ta_generation_enabled flags in the ReadoutApp. +# +# This situation happens in production occasionally (everything enabled for TPG except a couple +# of parameters), and this integtest attempts to verify the correct running of the system in +# situations like that. +# import pytest import copy import os