6 Definitions of post-exec check steps in Trigger ART tests
15 from TrigValTools.TrigValSteering.Step
import Step, get_step_from_list
16 from TrigValTools.TrigValSteering.ExecStep
import ExecStep
17 from TrigValTools.TrigValSteering.Common
import art_input_eos, art_input_cvmfs, running_in_CI
20 '''Base class for steps comparing a file to a reference'''
23 super(RefComparisonStep, self).
__init__(name)
31 self.misconfig_abort(
'Both options "reference" and "ref_test_name" used. Use at most one of them.')
39 return super(RefComparisonStep, self).
configure(test)
42 return super(RefComparisonStep, self).
configure(test)
44 full_path = subprocess.check_output(
'find_data.py {}'.
format(self.
reference), shell=
True).
decode(
'utf-8').strip()
45 if os.path.isfile(full_path):
46 self.log.
debug(
'%s using reference %s', self.name, full_path)
48 return super(RefComparisonStep, self).
configure(test)
51 '%s failed to find reference %s - wrong path?',
53 return super(RefComparisonStep, self).
configure(test)
56 self.misconfig_abort(
'input_file not specified')
58 branch = os.environ.get(
'AtlasBuildBranch')
60 branch = branch.split(
'--')[0]
62 branch = os.environ.get(
'gitlabTargetBranch')
64 jobName = os.environ.get(
'JOB_NAME')
66 branch = jobName.split(
'_')[0].
split(
'--')[0]
68 msg =
'Cannot determine the branch name, all variables are empty: AtlasBuildBranch, gitlabTargetBranch, JOB_NAME'
70 self.misconfig_abort(msg)
73 branch =
'UNKNOWN_BRANCH'
75 sub_path =
'{}/ref/{}/test_{}/'.
format(
77 ref_eos = art_input_eos + sub_path + self.
input_file
78 ref_cvmfs = art_input_cvmfs + sub_path + self.
input_file
79 if os.path.isfile(ref_eos)
and os.access(ref_eos, os.R_OK):
80 self.log.
debug(
'%s using reference from EOS: %s',
83 elif os.path.isfile(ref_cvmfs)
and os.access(ref_cvmfs, os.R_OK):
84 self.log.
debug(
'%s using reference from CVMFS: %s',
88 self.log.warning(
'%s failed to find reference %s in %s or %s',
90 art_input_eos, art_input_cvmfs)
93 return super(RefComparisonStep, self).
configure(test)
97 '''Base class for steps executed only if the input file exists'''
100 super(InputDependentStep, self).
__init__(name)
103 def run(self, dry_run=False):
105 self.log.
error(
'%s misconfiguration - no input file specified',
108 if self.auto_report_result:
110 return self.
result,
'# (internal) {} -> failed'.
format(self.name)
112 if not dry_run
and not os.path.isfile(self.
input_file):
113 self.log.
debug(
'Skipping %s because %s does not exist',
116 return self.
result,
'# (internal) {} -> skipped'.
format(self.name)
118 return super(InputDependentStep, self).
run(dry_run)
122 '''Merge several log files into one for post-processing'''
125 super(LogMergeStep, self).
__init__(name)
134 for step
in test.exec_steps:
138 self.misconfig_abort(
139 'output log name %s is same as one of the input log names.'
140 ' This will lead to infinite loop, aborting.', self.
merged_name)
141 super(LogMergeStep, self).
configure(test)
145 files = os.listdir(
'.')
147 match_files =
filter(r.match, files)
148 for f
in match_files:
155 if not os.path.isfile(log_name):
157 self.log.warning(
'Cannot open %s', log_name)
159 '### WARNING Missing {} ###\n'.
format(log_name))
161 with open(log_name, encoding=
'utf-8')
as log_file:
162 merged_file.write(
'### {} ###\n'.
format(log_name))
165 if log_name ==
'log.Derivation' or log_name ==
'log.AODtoDAOD':
166 for line
in log_file:
167 merged_file.write(line.replace(
'Selected dynamic Aux',
'Selected Dynamic Aux'))
169 for line
in log_file:
170 merged_file.write(line)
173 self.log.
error(
'%s merging failed due to OSError: %s',
174 self.name, e.strerror)
177 def run(self, dry_run=False):
180 self.
log_files.sort(key=
lambda f : os.path.getmtime(f)
if os.path.isfile(f)
else 0)
181 self.log.
info(
'Running %s merging logs %s into %s',
192 Merge root files with hadd. Parameters are:
193 input_file - file(s) to be merged
194 merged_file - output file name
195 rename_suffix - if merged_file exists, it is renamed by adding this suffix
199 super(RootMergeStep, self).
__init__(name)
207 super(RootMergeStep, self).
configure(test)
209 def run(self, dry_run=False):
215 if new_name
in file_list_to_check:
216 file_list_to_check.remove(new_name)
218 self.log.
debug(
'%s checking if the input files exist: %s', self.name,
str(file_list_to_check))
220 for file_name
in file_list_to_check:
221 if len(glob.glob(file_name)) < 1:
222 self.log.warning(
'%s: file %s requested to be merged but does not exist', self.name, file_name)
225 return super(RootMergeStep, self).
run(dry_run)
229 '''Compress a large log file'''
247 '''Execute CheckLog looking for errors or warnings in a log file'''
250 super(CheckLogStep, self).
__init__(name)
256 self.
args =
'--showexcludestats'
264 if test.package_name ==
'TrigP1Test':
266 elif test.package_name ==
'TrigValTools':
271 if len(test.exec_steps) == 1:
272 self.
log_file = test.exec_steps[0].name+
'.log'
276 self.
args +=
' --errors'
278 self.
args +=
' --warnings'
282 self.
output_stream = Step.OutputStream.FILE_AND_STDOUT
if errors_only
else Step.OutputStream.FILE_ONLY
290 super(CheckLogStep, self).
configure(test)
294 '''Execute RegTest comparing a log file against a reference'''
297 super(RegTestStep, self).
__init__(name)
306 RefComparisonStep.configure(self, test)
308 Step.configure(self, test)
312 if not os.path.isfile(log_file):
313 self.log.
error(
'%s input file %s is missing', self.name, log_file)
315 with open(log_file, encoding=
'utf-8')
as f_in:
316 matches = re.findall(
'({}.*).*$'.
format(self.
regex),
317 f_in.read(), re.MULTILINE)
320 linestr =
str(line[0])
if type(line)
is tuple
else line
321 f_out.write(linestr+
'\n')
327 new_name = os.path.basename(self.
reference) +
'.new'
329 new_name = os.path.basename(self.
input_file) +
'.new'
333 self.log.warning(
'Failed to rename %s to %s',
336 def run(self, dry_run=False):
338 self.log.
error(
'%s failed in prepare_inputs()', self.name)
342 return self.
result,
'# (internal) {} -> failed'.
format(self.name)
344 self.log.
error(
'Missing reference for %s', self.name)
350 return self.
result,
'# (internal) {} -> failed'.
format(self.name)
351 retcode, cmd = super(RegTestStep, self).
run(dry_run)
358 '''Execute RootComp comparing histograms against a reference'''
361 super(RootCompStep, self).
__init__(name)
367 RefComparisonStep.configure(self, test)
370 self.args +=
' --noRoot --noPS'
372 Step.configure(self, test)
374 def run(self, dry_run=False):
378 'Skipping %s because both reference and input are missing',
381 return self.
result,
'# (internal) {} -> skipped'.
format(self.name)
383 self.log.
error(
'Missing reference for %s', self.name)
387 return self.
result,
'# (internal) {} -> failed'.
format(self.name)
388 retcode, cmd = super(RootCompStep, self).
run(dry_run)
393 '''Execute the PerfMon ntuple post-processing'''
396 super(PerfMonStep, self).
__init__(name)
403 num_athenaHLT_steps =
sum([1
for step
in test.exec_steps
if step.type ==
'athenaHLT'])
404 if num_athenaHLT_steps > 0:
405 self.
input_file =
'athenaHLT_workers/athenaHLT-01/ntuple.pmon.gz'
413 '''Copy the last N lines of a log file into a separate file'''
416 super(TailStep, self).
__init__(name)
425 split = os.path.splitext(self.
log_file)
436 '''Execute art.py download to get results from previous days'''
439 super(DownloadRefStep, self).
__init__(name)
454 super(DownloadRefStep, self).
configure(test)
458 '''Execute histSizes.py to count histograms in a ROOT file'''
461 super(HistCountStep, self).
__init__(name)
468 super(HistCountStep, self).
configure(test)
473 Execute chainDump.py to print trigger counts from histograms to text files
477 super(ChainDumpStep, self).
__init__(name)
484 super(ChainDumpStep, self).
configure(test)
489 Execute chainComp.py to compare counts from chainDump.py to a reference
493 super(ChainCompStep, self).
__init__(name)
504 RefComparisonStep.configure(self, test)
509 Step.configure(self, test)
513 '''Execute trig-test-json.py to create extra-results.json file'''
516 super(TrigTestJsonStep, self).
__init__(name)
522 Execute checkFile and checkxAOD for POOL files.
523 executable and input_file can have multiple comma-separated values
527 super(CheckFileStep, self).
__init__(name)
528 self.
input_file =
'AOD.pool.root,ESD.pool.root,RDO_TRIG.pool.root'
535 test_types = [step.type
for step
in test.exec_steps]
536 num_athenaHLT =
sum(1
for tt
in test_types
if tt ==
'athenaHLT')
537 if num_athenaHLT == test_types:
538 self.log.
debug(
'%s will be skipped because all exec steps use athenaHLT')
544 super(CheckFileStep, self).
configure(test)
546 def run(self, dry_run=False):
554 ex_base = ex.split(
'.')[0:-1]
556 ret, cmd = super(CheckFileStep, self).
run(dry_run)
557 ret_codes.append(ret)
562 if len(commands) == 1:
563 merged_cmd = commands[0]
566 if '(internal)' not in cmd:
567 merged_cmd += cmd+
'; '
568 if len(merged_cmd) == 0:
569 merged_cmd = commands[-1]
571 return max(ret_codes), merged_cmd
576 Check if all counts are zero.
577 input_file can have multiple comma-separated values
581 super(ZeroCountsStep, self).
__init__(name)
591 if not os.path.isfile(input_file):
593 'Skipping %s for %s because the file does not exist',
594 self.name, input_file)
597 with open(input_file, encoding=
'utf-8')
as f_in:
598 for line
in f_in.readlines():
599 split_line = line.split()
601 if int(split_line[-1]) != 0:
603 if lines_checked == 0:
604 self.log.
error(
'Failed to read counts from %s', input_file)
607 def run(self, dry_run=False):
615 cmd =
'# (internal) {} -> skipped'.
format(self.name)
618 self.log.
info(
'Running %s step', self.name)
625 '''Count messages printed inside event loop'''
628 super(MessageCountStep, self).
__init__(name)
630 self.
log_regex =
r'(athena\.(?!.*tail).*log$|athenaHLT:.*\.out$|^log\.(.*to.*|Derivation))'
632 self.
start_pattern =
r'(HltEventLoopMgr|AthenaHiveEventLoopMgr).*INFO Starting loop on events'
633 self.
end_pattern =
r'(HltEventLoopMgr.*INFO All events processed|AthenaHiveEventLoopMgr.*INFO.*Loop Finished)'
645 self.args +=
' --saveAll'
647 max_events = test.exec_steps[0].max_events
if isinstance(test.exec_steps[0], ExecStep)
else 0
658 super(MessageCountStep, self).
configure(test)
660 def run(self, dry_run=False):
661 files = os.listdir(
'.')
663 log_files = [f
for f
in filter(r.match, files)
if f
not in self.
skip_logs]
664 if not log_files
and not dry_run:
665 self.log.
error(
'%s found no log files matching the pattern %s', self.name, self.
log_regex)
669 return self.
result,
'# (internal) {} -> failed'.
format(self.name)
670 self.args +=
' ' +
' '.
join(log_files)
673 ret, cmd = super(MessageCountStep, self).
run(dry_run)
676 self.log.
error(
'%s failed', self.name)
682 for log_file
in log_files:
683 json_file =
'MessageCount.{:s}.json'.
format(log_file)
685 all_json_file =
'Messages.{:s}.json'.
format(log_file)
686 if not os.path.isfile(json_file):
687 self.log.warning(
'%s cannot open file %s', self.name, json_file)
688 with open(json_file)
as f:
689 summary = json.load(f)
691 if summary[level] > threshold:
694 '%s Number of %s messages %s in %s is higher than threshold %s',
695 self.name, level, summary[level], log_file, threshold)
697 self.log.
info(
'%s Printing all %s messages from %s', self.name, level, log_file)
698 with open(all_json_file)
as af:
699 all_msg = json.load(af)
700 for msg
in all_msg[level]:
710 Helper function checking whether a Step output_stream value
711 indicates that it will produce a log file
713 return step.output_stream == Step.OutputStream.FILE_ONLY
or \
714 step.output_stream == Step.OutputStream.FILE_AND_STDOUT
719 Create the default list of check steps for a test. The configuration
720 depends on the package name and the type of exec steps (athena or
721 athenaHLT or transforms).
727 if len(test.exec_steps) == 1:
728 exec_step = test.exec_steps[0]
729 if exec_step.type ==
'athenaHLT' and produces_log(exec_step):
731 logmerge.merged_name =
'athena.log'
732 logmerge.log_files = [
'athenaHLT.log']
733 nforks = 1
if exec_step.forks
is None else exec_step.forks
734 for n
in range(1, 1+nforks):
735 logmerge.log_files.append(
'athenaHLT:{:02d}.out'.
format(n))
736 logmerge.log_files.append(
'athenaHLT:{:02d}.err'.
format(n))
737 check_steps.append(logmerge)
740 logmerge.merged_name =
'athena.log'
741 logmerge.log_files = []
742 for exec_step
in test.exec_steps:
745 logmerge.log_files.append(exec_step.get_log_file_name())
746 if exec_step.type ==
'athenaHLT':
747 logmerge.extra_log_regex =
'athenaHLT:.*(.out|.err)'
748 check_steps.append(logmerge)
751 if len(check_steps) > 0
and isinstance(check_steps[-1], LogMergeStep):
752 log_to_check = check_steps[-1].merged_name
753 log_to_zip = check_steps[-1].merged_name
756 reco_tf_steps = [step
for step
in test.exec_steps
if step.type
in [
'Reco_tf',
'Trig_reco_tf',
'Derivation_tf']]
757 if len(reco_tf_steps) > 0:
759 reco_tf_logmerge.warn_if_missing =
False
761 tf_names = [
'HITtoRDO',
'Overlay',
'RDOtoRDOTrigger',
'RAWtoESD',
'ESDtoAOD',
762 'PhysicsValidation',
'RAWtoALL',
763 'BSRDOtoRAW',
'DRAWCOSTtoNTUPCOST',
'AODtoNTUPRATE',
'Derivation',
'AODtoDAOD']
764 reco_tf_logmerge.log_files = [
'log.'+tf_name
for tf_name
in tf_names]
766 for step
in reco_tf_steps:
767 reco_tf_logmerge.log_files.append(step.get_log_file_name())
768 reco_tf_logmerge.merged_name =
'athena.merged.log'
769 log_to_zip = reco_tf_logmerge.merged_name
770 if log_to_check
is not None:
771 reco_tf_logmerge.log_files.append(log_to_check)
772 log_to_check = reco_tf_logmerge.merged_name
773 log_to_check = reco_tf_logmerge.merged_name
774 check_steps.append(reco_tf_logmerge)
777 num_athenaHLT_steps =
sum([1
for step
in test.exec_steps
if step.type ==
'athenaHLT'])
778 if num_athenaHLT_steps > 0:
780 histmerge.merged_file =
'expert-monitoring.root'
781 histmerge.input_file =
'athenaHLT_workers/*/expert-monitoring.root expert-monitoring-mother.root'
782 histmerge.rename_suffix =
'-mother'
783 check_steps.append(histmerge)
787 if log_to_check
is not None:
788 checklog.log_file = log_to_check
789 check_steps.append(checklog)
793 checkwarn.check_errors =
False
794 checkwarn.check_warnings =
True
795 if log_to_check
is not None:
796 checkwarn.log_file = log_to_check
797 check_steps.append(checkwarn)
801 for logmerge
in [step
for step
in check_steps
if isinstance(step, LogMergeStep)]:
802 msgcount.skip_logs.append(logmerge.merged_name)
803 check_steps.append(msgcount)
807 if log_to_check
is not None:
808 tail.log_file = log_to_check
809 check_steps.append(tail)
826 if log_to_zip
is not None:
828 zip_step.zip_input = log_to_zip
829 zip_step.zip_output = log_to_zip+
'.tar.gz'
830 check_steps.append(zip_step)
838 Insert step_to_add into step_list after the last step of type ref_type.
839 If the list has no steps of type ref_type, append step_to_add at the end of the list.
842 for index, step
in enumerate(step_list):
843 if isinstance(step, ref_type):
844 index_to_add = index+1
846 step_list.insert(index_to_add, step_to_add)
848 step_list.append(step_to_add)