ATLAS Offline Software
Loading...
Searching...
No Matches
CheckSteps.py
Go to the documentation of this file.
2# Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3#
4
5'''
6Definitions of post-exec check steps in Trigger ART tests
7'''
8
9import os
10import re
11import subprocess
12import json
13import glob
14
15from TrigValTools.TrigValSteering.Step import Step, get_step_from_list
16from TrigValTools.TrigValSteering.ExecStep import ExecStep
17from TrigValTools.TrigValSteering.Common import art_input_eos, art_input_cvmfs, running_in_CI
18
20 '''Base class for steps comparing a file to a reference'''
21
22 def __init__(self, name):
23 super(RefComparisonStep, self).__init__(name)
24 self.reference = None
25 self.ref_test_name = None
26 self.input_file = None
27 self.explicit_reference = False # True if reference doesn't exist at configuration time
28
29 def configure(self, test):
30 if self.reference and self.ref_test_name:
31 self.misconfig_abort('Both options "reference" and "ref_test_name" used. Use at most one of them.')
32
33 if not self.reference and not self.ref_test_name:
34 self.ref_test_name = test.name
35
36 if self.reference is not None:
37 # Do nothing if the reference will be produced later
38 if self.explicit_reference:
39 return super(RefComparisonStep, self).configure(test)
40 # Do nothing if the reference exists
41 if os.path.isfile(self.reference):
42 return super(RefComparisonStep, self).configure(test)
43 # Try to find the file in DATAPATH
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)
47 self.reference = full_path
48 return super(RefComparisonStep, self).configure(test)
49 else:
50 self.log.warning(
51 '%s failed to find reference %s - wrong path?',
52 self.name, self.reference)
53 return super(RefComparisonStep, self).configure(test)
54
55 if self.input_file is None:
56 self.misconfig_abort('input_file not specified')
57
58 branch = os.environ.get('AtlasBuildBranch') # Available after asetup
59 if branch:
60 branch = branch.split('--')[0] # experimental nightlies, e.g. main--mainGAUDI
61 if not branch:
62 branch = os.environ.get('gitlabTargetBranch') # Available in CI
63 if not branch:
64 jobName = os.environ.get('JOB_NAME') # Available in nightly build system (ATR-21836)
65 if jobName:
66 branch = jobName.split('_')[0].split('--')[0]
67 if not branch:
68 msg = 'Cannot determine the branch name, all variables are empty: AtlasBuildBranch, gitlabTargetBranch, JOB_NAME'
69 if self.required:
70 self.misconfig_abort(msg)
71 else:
72 self.log.warning(msg)
73 branch = 'UNKNOWN_BRANCH'
74
75 sub_path = '{}/ref/{}/test_{}/'.format(
76 test.package_name, branch, self.ref_test_name)
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',
81 self.name, ref_eos)
82 self.reference = ref_eos
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',
85 self.name, ref_cvmfs)
86 self.reference = ref_cvmfs
87 else:
88 self.log.warning('%s failed to find reference %s in %s or %s',
89 self.name, sub_path + self.input_file,
90 art_input_eos, art_input_cvmfs)
91 self.reference = None
92
93 return super(RefComparisonStep, self).configure(test)
94
95
97 '''Base class for steps executed only if the input file exists'''
98
99 def __init__(self, name=None):
100 super(InputDependentStep, self).__init__(name)
101 self.input_file = None
102
103 def run(self, dry_run=False):
104 if self.input_file is None:
105 self.log.error('%s misconfiguration - no input file specified',
106 self.name)
107 self.result = 1
109 self.report_result()
110 return self.result, '# (internal) {} -> failed'.format(self.name)
111
112 if not dry_run and not os.path.isfile(self.input_file):
113 self.log.debug('Skipping %s because %s does not exist',
114 self.name, self.input_file)
115 self.result = 0
116 return self.result, '# (internal) {} -> skipped'.format(self.name)
117
118 return super(InputDependentStep, self).run(dry_run)
119
120
121class LogMergeStep(Step):
122 '''Merge several log files into one for post-processing'''
123
124 def __init__(self, name='LogMerge'):
125 super(LogMergeStep, self).__init__(name)
126 self.log_files = None
127 self.extra_log_regex = None
128 self.merged_name = 'athena.merged.log'
129 self.warn_if_missing = True
130
131 def configure(self, test):
132 if self.log_files is None:
133 self.log_files = []
134 for step in test.exec_steps:
135 self.log_files.append(step.name)
136 # Protect against infinite loop
137 if self.merged_name in self.log_files:
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)
142
144 if self.extra_log_regex:
145 files = os.listdir('.')
146 r = re.compile(self.extra_log_regex)
147 match_files = filter(r.match, files)
148 for f in match_files:
149 self.log_files.append(f)
150
151 def merge_logs(self):
152 try:
153 with open(self.merged_name, 'w', encoding='utf-8') as merged_file:
154 for log_name in self.log_files:
155 if not os.path.isfile(log_name):
156 if self.warn_if_missing:
157 self.log.warning('Cannot open %s', log_name)
158 merged_file.write(
159 '### WARNING Missing {} ###\n'.format(log_name))
160 continue
161 with open(log_name, encoding='utf-8') as log_file:
162 merged_file.write('### {} ###\n'.format(log_name))
163 # temporary workaround to ignore false positives in AOD->DAOD log parsing
164 if "Derivation" in log_name:
165 for line in log_file:
166 merged_file.write(line.replace('Selected dynamic Aux', 'Selected Dynamic Aux'))
167 else:
168 for line in log_file:
169 merged_file.write(line)
170 return 0
171 except OSError as e:
172 self.log.error('%s merging failed due to OSError: %s',
173 self.name, e.strerror)
174 return 1
175
176 def run(self, dry_run=False):
178 # Sort log files by modification time
179 self.log_files.sort(key=lambda f : os.path.getmtime(f) if os.path.isfile(f) else 0)
180 self.log.info('Running %s merging logs %s into %s',
181 self.name, self.log_files, self.merged_name)
182 if dry_run:
183 self.result = 0
184 else:
185 self.result = self.merge_logs()
186 return self.result, '# (internal) {} in={} out={}'.format(self.name, self.log_files, self.merged_name)
187
188
189class RootMergeStep(Step):
190 '''
191 Merge root files with hadd. Parameters are:
192 input_file - file(s) to be merged
193 merged_file - output file name
194 rename_suffix - if merged_file exists, it is renamed by adding this suffix
195 '''
196
197 def __init__(self, name='RootMerge'):
198 super(RootMergeStep, self).__init__(name)
199 self.input_file = None
200 self.merged_file = None
201 self.rename_suffix = None
202 self.executable = 'hadd'
203
204 def configure(self, test=None):
205 self.args += ' ' + self.merged_file + ' ' + self.input_file
206 super(RootMergeStep, self).configure(test)
207
208 def run(self, dry_run=False):
209 file_list_to_check = self.input_file.split()
210 if os.path.isfile(self.merged_file) and self.rename_suffix:
211 old_name = os.path.splitext(self.merged_file)
212 new_name = old_name[0] + self.rename_suffix + old_name[1]
213 self.executable = 'mv {} {}; {}'.format(self.merged_file, new_name, self.executable)
214 if new_name in file_list_to_check:
215 file_list_to_check.remove(new_name)
216 file_list_to_check.append(self.merged_file)
217 self.log.debug('%s checking if the input files exist: %s', self.name, str(file_list_to_check))
218 if not dry_run:
219 for file_name in file_list_to_check:
220 if len(glob.glob(file_name)) < 1:
221 self.log.warning('%s: file %s requested to be merged but does not exist', self.name, file_name)
222 self.result = 1
223 return self.result, '# (internal) {} in={} out={} -> failed'.format(self.name, self.input_file, self.merged_file)
224 return super(RootMergeStep, self).run(dry_run)
225
226
227class ZipStep(Step):
228 '''Compress a large log file'''
229
230 def __init__(self, name='Zip'):
231 super(ZipStep, self).__init__(name)
232 self.zip_output = None
233 self.zip_input = None
234 self.executable = 'tar'
235 self.args = '-czf'
236 self.output_stream = Step.OutputStream.STDOUT_ONLY
237
238 def configure(self, test=None):
239 self.args += ' '+self.zip_output+' '+self.zip_input
240 # Remove the file after zipping
241 self.args += ' && rm ' + self.zip_input
242 super(ZipStep, self).configure(test)
243
244
245class CheckLogStep(Step):
246 '''Execute CheckLog looking for errors or warnings in a log file'''
247
248 def __init__(self, name):
249 super(CheckLogStep, self).__init__(name)
250 self.executable = 'check_log.py'
251 self.log_file = None
252 self.check_errors = True
253 self.check_warnings = False
254 self.config_file = None
255 self.args = '--showexcludestats'
256 # The following three are updated in configure() if not set
257 self.required = None
259 self.output_stream = None
260
261 def configure(self, test):
262 if self.config_file is None:
263 if test.package_name == 'TrigP1Test':
264 self.config_file = 'checklogTrigP1Test.conf'
265 elif test.package_name == 'TrigValTools':
266 self.config_file = 'checklogTrigValTools.conf'
267 else:
268 self.config_file = 'checklogTriggerTest.conf'
269 if self.log_file is None:
270 if len(test.exec_steps) == 1:
271 self.log_file = test.exec_steps[0].name+'.log'
272 else:
273 self.log_file = 'athena.log'
274 if self.check_errors:
275 self.args += ' --errors'
276 if self.check_warnings:
277 self.args += ' --warnings'
278
279 errors_only = self.check_errors and not self.check_warnings
280 if self.output_stream is None:
281 self.output_stream = Step.OutputStream.FILE_AND_STDOUT if errors_only else Step.OutputStream.FILE_ONLY
282 if self.auto_report_result is None:
283 self.auto_report_result = errors_only
284 if self.required is None:
285 self.required = errors_only
286
287 self.args += ' --config {} {}'.format(self.config_file, self.log_file)
288
289 super(CheckLogStep, self).configure(test)
290
291
293 '''Execute RegTest comparing a log file against a reference'''
294
295 def __init__(self, name='RegTest'):
296 super(RegTestStep, self).__init__(name)
297 self.regex = 'REGTEST'
298 self.executable = 'diff'
299 self.input_base_name = 'athena'
301 self.output_stream = Step.OutputStream.FILE_AND_STDOUT
302
303 def configure(self, test):
304 self.input_file = self.input_base_name+'.regtest'
305 RefComparisonStep.configure(self, test)
306 self.args += ' -U 2 -b {} {}'.format(self.input_file, self.reference)
307 Step.configure(self, test)
308
309 def prepare_inputs(self):
310 log_file = self.input_base_name+'.log'
311 if not os.path.isfile(log_file):
312 self.log.error('%s input file %s is missing', self.name, log_file)
313 return False
314 with open(log_file, encoding='utf-8') as f_in:
315 matches = re.findall('({}.*).*$'.format(self.regex),
316 f_in.read(), re.MULTILINE)
317 with open(self.input_file, 'w', encoding='utf-8') as f_out:
318 for line in matches:
319 linestr = str(line[0]) if type(line) is tuple else line
320 f_out.write(linestr+'\n')
321 return True
322
323 def rename_ref(self):
324 try:
325 if self.reference:
326 new_name = os.path.basename(self.reference) + '.new'
327 else:
328 new_name = os.path.basename(self.input_file) + '.new'
329 os.rename(self.input_file, new_name)
330 self.log.debug('Renamed %s to %s', self.input_file, new_name)
331 except OSError:
332 self.log.warning('Failed to rename %s to %s',
333 self.input_file, new_name)
334
335 def run(self, dry_run=False):
336 if not dry_run and not self.prepare_inputs():
337 self.log.error('%s failed in prepare_inputs()', self.name)
338 self.result = 1
339 if self.auto_report_result:
340 self.report_result()
341 return self.result, '# (internal) {} -> failed'.format(self.name)
342 if self.reference is None:
343 self.log.error('Missing reference for %s', self.name)
344 if not dry_run:
345 self.rename_ref()
346 self.result = 999
347 if self.auto_report_result:
348 self.report_result()
349 return self.result, '# (internal) {} -> failed'.format(self.name)
350 retcode, cmd = super(RegTestStep, self).run(dry_run)
351 if not dry_run:
352 self.rename_ref()
353 return retcode, cmd
354
355
357 '''Execute RootComp comparing histograms against a reference'''
358
359 def __init__(self, name='RootComp'):
360 super(RootCompStep, self).__init__(name)
361 self.input_file = 'expert-monitoring.root'
362 self.executable = 'rootcomp.py'
364
365 def configure(self, test):
366 RefComparisonStep.configure(self, test)
367 if running_in_CI():
368 # drawing the diff output may be slow and is not needed for CI
369 self.args += ' --noRoot --noPS'
370 self.args += ' {} {}'.format(self.reference, self.input_file)
371 Step.configure(self, test)
372
373 def run(self, dry_run=False):
374 if self.reference is None:
375 if not os.path.isfile(self.input_file):
376 self.log.debug(
377 'Skipping %s because both reference and input are missing',
378 self.name)
379 self.result = 0
380 return self.result, '# (internal) {} -> skipped'.format(self.name)
381 else: # input exists but reference not
382 self.log.error('Missing reference for %s', self.name)
383 self.result = 999
384 if self.auto_report_result:
385 self.report_result()
386 return self.result, '# (internal) {} -> failed'.format(self.name)
387 retcode, cmd = super(RootCompStep, self).run(dry_run)
388 return retcode, cmd
389
390
391class TailStep(Step):
392 '''Copy the last N lines of a log file into a separate file'''
393
394 def __init__(self, name='Tail'):
395 super(TailStep, self).__init__(name)
396 self.log_file = 'athena.log'
397 self.output_name = None
398 self.executable = 'tail'
399 self.num_lines = 5000
400 self.output_stream = Step.OutputStream.STDOUT_ONLY
401
402 def configure(self, test):
403 if self.output_name is None:
404 split = os.path.splitext(self.log_file)
405 self.output_name = split[0]+'.tail'
406 if len(split) > 1:
407 self.output_name += split[1]
408 self.args += ' -n {:d}'.format(self.num_lines)
409 self.args += ' '+self.log_file
410 self.args += ' >'+self.output_name
411 super(TailStep, self).configure(test)
412
413
414class DownloadRefStep(Step):
415 '''Execute art.py download to get results from previous days'''
416
417 def __init__(self, name='DownloadRef'):
418 super(DownloadRefStep, self).__init__(name)
419 self.executable = 'art.py'
420 self.args = 'download'
421 self.artpackage = None
422 self.artjobname = None
423 self.timeout = 20*60
424 self.required = True
426
427 def configure(self, test):
428 if not self.artpackage:
429 self.artpackage = test.package_name
430 if not self.artjobname:
431 self.artjobname = 'test_'+test.name+'.py'
432 self.args += ' '+self.artpackage+' '+self.artjobname
433 super(DownloadRefStep, self).configure(test)
434
435
437 '''Execute histSizes.py to count histograms in a ROOT file'''
438
439 def __init__(self, name='HistCount'):
440 super(HistCountStep, self).__init__(name)
441 self.input_file = 'expert-monitoring.root'
442 self.executable = 'histSizes.py'
443 self.args = '-t'
444
445 def configure(self, test):
446 self.args += ' '+self.input_file
447 super(HistCountStep, self).configure(test)
448
449
451 '''
452 Execute chainDump.py to print trigger counts from histograms to text files
453 '''
454
455 def __init__(self, name='ChainDump'):
456 super(ChainDumpStep, self).__init__(name)
457 self.input_file = 'expert-monitoring.root'
458 self.executable = 'chainDump.py'
459 self.args = '--json --yaml'
460
461 def configure(self, test):
462 self.args += ' -f '+self.input_file
463 super(ChainDumpStep, self).configure(test)
464
465
467 '''
468 Execute chainComp.py to compare counts from chainDump.py to a reference
469 '''
470
471 def __init__(self, name='ChainComp'):
472 super(ChainCompStep, self).__init__(name)
473 self.input_file = 'chainDump.yml'
475 self.executable = 'chainComp.py'
476 self.args = ''
478 self.output_stream = Step.OutputStream.FILE_AND_STDOUT
479 self.depends_on_exec = True # skip if ExecSteps failed
480
481 def configure(self, test):
482 if not self.reference_from_release:
483 RefComparisonStep.configure(self, test)
484 if self.reference:
485 self.args += ' -r ' + self.reference
486 # else chainComp.py finds the reference in DATAPATH on its own
487 self.args += ' ' + self.input_file
488 Step.configure(self, test)
489
490
492 '''Execute trig-test-json.py to create extra-results.json file'''
493
494 def __init__(self, name='TrigTestJson'):
495 super(TrigTestJsonStep, self).__init__(name)
496 self.executable = 'trig-test-json.py'
497
498
500 '''
501 Execute checkFile and checkxAOD for POOL files.
502 executable and input_file can have multiple comma-separated values
503 '''
504
505 def __init__(self,name='CheckFile',input_file='AOD.pool.root'):
506 super(CheckFileStep, self).__init__(name)
507 self.input_file = input_file
508 self.executable = 'checkFile.py,checkxAOD.py'
509 self.__executables__ = None
510 self.__input_files__ = None
511
512 def configure(self, test):
513 # Skip the check if all test steps are athenaEF (no POOL files)
514 test_types = [step.type for step in test.exec_steps]
515 if all(tt == 'athenaEF' for tt in test_types):
516 self.log.debug('%s will be skipped because all exec steps use athenaEF')
517 self.__executables__ = []
518 self.__input_files__ = []
519 return
520 self.__executables__ = self.executable.split(',')
521 self.__input_files__ = set(self.input_file.split(','))
522 super(CheckFileStep, self).configure(test)
523
524 def run(self, dry_run=False):
525 ret_codes = []
526 commands = []
527 for f in self.__input_files__:
528 for ex in self.__executables__:
529 self.executable = ex
530 self.input_file = f
531 self.args = f
532 ex_base = ex.split('.')[0:-1]
533 self.log_file_name = f + '.' + ''.join(ex_base)
534 ret, cmd = super(CheckFileStep, self).run(dry_run)
535 ret_codes.append(ret)
536 commands.append(cmd)
537
538 # Merge executed commands for logging
539 merged_cmd = ''
540 for cmd in commands:
541 if '(internal)' not in cmd:
542 merged_cmd += cmd+'; '
543 if len(merged_cmd) == 0: # can happen if all exec steps are type athenaEF
544 merged_cmd = '# (internal) {} -> skipped'.format(self.name)
545 ret_codes.append(0)
546
547 return max(ret_codes), merged_cmd
548
549
550class ZeroCountsStep(Step):
551 '''
552 Check if all counts are zero.
553 input_file can have multiple comma-separated values
554 '''
555
556 def __init__(self, name='ZeroCounts'):
557 super(ZeroCountsStep, self).__init__(name)
558 self.input_file = 'HLTChain.txt,HLTTE.txt,L1AV.txt'
560 self.required = True
561 self.__input_files__ = None
562
563 def configure(self, test=None):
564 self.__input_files__ = self.input_file.split(',')
565
566 def check_zero_counts(self, input_file):
567 if not os.path.isfile(input_file):
568 self.log.debug(
569 'Skipping %s for %s because the file does not exist',
570 self.name, input_file)
571 return -1
572 lines_checked = 0
573 with open(input_file, encoding='utf-8') as f_in:
574 for line in f_in.readlines():
575 split_line = line.split()
576 lines_checked += 1
577 if int(split_line[-1]) != 0:
578 return 0 # at least one non-zero count
579 if lines_checked == 0:
580 self.log.error('Failed to read counts from %s', input_file)
581 return 1 # all counts are zero
582
583 def run(self, dry_run=False):
584 results = []
585 for input_file in self.__input_files__:
586 results.append(self.check_zero_counts(input_file))
587
588 self.result = max(results)
589 cmd = '# (internal) {} for {}'.format(self.name, self.__input_files__)
590 if self.result < 0:
591 cmd = '# (internal) {} -> skipped'.format(self.name)
592 self.result = 0
593 return self.result, cmd
594 self.log.info('Running %s step', self.name)
595 if self.auto_report_result:
596 self.report_result()
597 return self.result, cmd
598
599
601 '''Count messages printed inside event loop'''
602
603 def __init__(self, name='MessageCount'):
604 super(MessageCountStep, self).__init__(name)
605 self.executable = 'messageCounter.py'
606 self.log_regex = r'(athena\.(?!.*tail).*log$|athenaEF\..*log$|^log\.(.*to.*|Derivation))'
607 self.skip_logs = []
608 self.start_pattern = r'(HltEventLoopMgr|AthenaHiveEventLoopMgr).*INFO Starting loop on events'
609 self.end_pattern = r'(HltEventLoopMgr.*INFO All events processed|AthenaHiveEventLoopMgr.*INFO.*Loop Finished)'
610 self.print_on_fail = None
611 self.thresholds = {}
613 self.depends_on_exec = True # skip if ExecSteps failed
614
615 def configure(self, test):
616 self.args += ' -s "{:s}"'.format(self.start_pattern)
617 self.args += ' -e "{:s}"'.format(self.end_pattern)
618 if self.print_on_fail is None:
619 self.print_on_fail = self.required
620 if self.print_on_fail:
621 self.args += ' --saveAll'
622
623 max_events = test.exec_steps[0].max_events if isinstance(test.exec_steps[0], ExecStep) else 0
624 if 'WARNING' not in self.thresholds:
625 self.thresholds['WARNING'] = 0
626 if 'INFO' not in self.thresholds:
627 self.thresholds['INFO'] = max_events
628 if 'DEBUG' not in self.thresholds:
629 self.thresholds['DEBUG'] = 0
630 if 'VERBOSE' not in self.thresholds:
631 self.thresholds['VERBOSE'] = 0
632 if 'other' not in self.thresholds:
633 self.thresholds['other'] = max_events
634 super(MessageCountStep, self).configure(test)
635
636 def run(self, dry_run=False):
637 files = os.listdir('.')
638 r = re.compile(self.log_regex)
639 log_files = [f for f in filter(r.match, files) if f not in self.skip_logs]
640 if not log_files and not dry_run:
641 self.log.error('%s found no log files matching the pattern %s', self.name, self.log_regex)
642 self.result = 1
643 if self.auto_report_result:
644 self.report_result()
645 return self.result, '# (internal) {} -> failed'.format(self.name)
646 self.args += ' ' + ' '.join(log_files)
647 auto_report = self.auto_report_result
648 self.auto_report_result = False
649 ret, cmd = super(MessageCountStep, self).run(dry_run)
650 self.auto_report_result = auto_report
651 if ret != 0:
652 self.log.error('%s failed', self.name)
653 self.result = 1
654 if self.auto_report_result:
655 self.report_result()
656 return self.result, cmd
657
658 for log_file in log_files:
659 json_file = 'MessageCount.{:s}.json'.format(log_file)
660 if self.print_on_fail:
661 all_json_file = 'Messages.{:s}.json'.format(log_file)
662 if not os.path.isfile(json_file):
663 self.log.warning('%s cannot open file %s', self.name, json_file)
664 with open(json_file) as f:
665 summary = json.load(f)
666 for level, threshold in self.thresholds.items():
667 if summary[level] > threshold:
668 self.result += 1
669 self.log.info(
670 '%s Number of %s messages %s in %s is higher than threshold %s',
671 self.name, level, summary[level], log_file, threshold)
672 if self.print_on_fail:
673 self.log.info('%s Printing all %s messages from %s', self.name, level, log_file)
674 with open(all_json_file) as af:
675 all_msg = json.load(af)
676 for msg in all_msg[level]:
677 print(msg.strip()) # noqa: ATL901
678
679 if self.auto_report_result:
680 self.report_result()
681 return self.result, cmd
682
683
684def produces_log(step):
685 '''
686 Helper function checking whether a Step output_stream value
687 indicates that it will produce a log file
688 '''
689 return step.output_stream == Step.OutputStream.FILE_ONLY or \
690 step.output_stream == Step.OutputStream.FILE_AND_STDOUT
691
692
693def default_check_steps(test, checkfile_input='AOD.pool.root,ESD.pool.root,RDO_TRIG.pool.root,DAOD_PHYS.DAOD.pool.root'):
694 '''
695 Create the default list of check steps for a test. The configuration
696 depends on the package name and the type of exec steps.
697 '''
698
699 check_steps = []
700 log_to_check = None
701 log_to_zip = None
702
703 # Log merging
704 if len(test.exec_steps) == 1:
705 exec_step = test.exec_steps[0]
706 if exec_step.type == 'athenaEF' and produces_log(exec_step):
707 log_to_check = exec_step.get_log_file_name()
708 else:
709 logmerge = LogMergeStep()
710 logmerge.merged_name = 'athena.log'
711 logmerge.log_files = []
712 for exec_step in test.exec_steps:
713 if not produces_log(exec_step):
714 continue
715 logmerge.log_files.append(exec_step.get_log_file_name())
716 check_steps.append(logmerge)
717
718 if len(check_steps) > 0 and isinstance(check_steps[-1], LogMergeStep):
719 log_to_check = check_steps[-1].merged_name
720 log_to_zip = check_steps[-1].merged_name
721
722 # Reco_tf log merging
723 reco_tf_steps = [step for step in test.exec_steps if step.type in ['Reco_tf', 'Trig_reco_tf', 'Derivation_tf']]
724 if len(reco_tf_steps) > 0:
725 reco_tf_logmerge = LogMergeStep('LogMerge_Reco_tf')
726 reco_tf_logmerge.warn_if_missing = False
727 # FIXME: drop AODtoDAOD once test_trigAna_AODtoDAOD_run2_build.py is migrated to Derivation_tf
728 tf_names = ['HITtoRDO', 'Overlay', 'RDOtoRDOTrigger', 'RAWtoESD', 'ESDtoAOD',
729 'PhysicsValidation', 'RAWtoALL',
730 'BSRDOtoRAW', 'DRAWCOSTtoNTUPCOST', 'AODtoNTUPRATE', 'Derivation', 'AODtoDAOD']
731 reco_tf_logmerge.log_files = ['log.'+tf_name for tf_name in tf_names]
732 if not get_step_from_list('LogMerge', check_steps):
733 for step in reco_tf_steps:
734 reco_tf_logmerge.log_files.append(step.get_log_file_name())
735 reco_tf_logmerge.merged_name = 'athena.merged.log'
736 log_to_zip = reco_tf_logmerge.merged_name
737 if log_to_check is not None:
738 reco_tf_logmerge.log_files.append(log_to_check)
739 log_to_check = reco_tf_logmerge.merged_name
740 log_to_check = reco_tf_logmerge.merged_name
741 check_steps.append(reco_tf_logmerge)
742
743 # Histogram merging for athenaEF
744 if any(step.type == 'athenaEF' for step in test.exec_steps):
745 histmerge = RootMergeStep('HistMerge')
746 histmerge.merged_file = 'expert-monitoring.root'
747 histmerge.input_file = 'athenaHLT_workers/*/expert-monitoring.root expert-monitoring-mother.root'
748 histmerge.rename_suffix = '-mother'
749 check_steps.append(histmerge)
750
751 # CheckLog for errors
752 checklog = CheckLogStep('CheckLog')
753 if log_to_check is not None:
754 checklog.log_file = log_to_check
755 check_steps.append(checklog)
756
757 # CheckLog for warnings
758 checkwarn = CheckLogStep('Warnings')
759 checkwarn.check_errors = False
760 checkwarn.check_warnings = True
761 if log_to_check is not None:
762 checkwarn.log_file = log_to_check
763 check_steps.append(checkwarn)
764
765 # MessageCount
766 msgcount = MessageCountStep('MessageCount')
767 for logmerge in [step for step in check_steps if isinstance(step, LogMergeStep)]:
768 msgcount.skip_logs.append(logmerge.merged_name)
769 check_steps.append(msgcount)
770
771 # Tail (probably not so useful these days)
772 tail = TailStep()
773 if log_to_check is not None:
774 tail.log_file = log_to_check
775 check_steps.append(tail)
776
777 # Histogram-based steps
778 check_steps.append(RootCompStep())
779 check_steps.append(ChainDumpStep())
780 check_steps.append(HistCountStep())
781
782 # ZeroCounts
783 check_steps.append(ZeroCountsStep())
784
785 # Extra JSON
786 check_steps.append(TrigTestJsonStep())
787
788 # CheckFile
789 check_steps.append(CheckFileStep(input_file=checkfile_input))
790
791 # Zip the merged log (can be large and duplicates information)
792 if log_to_zip is not None:
793 zip_step = ZipStep()
794 zip_step.zip_input = log_to_zip
795 zip_step.zip_output = log_to_zip+'.tar.gz'
796 check_steps.append(zip_step)
797
798 # return the steps
799 return check_steps
800
801
802def add_step_after_type(step_list, ref_type, step_to_add):
803 '''
804 Insert step_to_add into step_list after the last step of type ref_type.
805 If the list has no steps of type ref_type, append step_to_add at the end of the list.
806 '''
807 index_to_add = -1
808 for index, step in enumerate(step_list):
809 if isinstance(step, ref_type):
810 index_to_add = index+1
811 if index_to_add > 0:
812 step_list.insert(index_to_add, step_to_add)
813 else:
814 step_list.append(step_to_add)
const bool debug
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
void print(char *figname, TCanvas *c1)
#define max(a, b)
Definition cfImp.cxx:41
__init__(self, name='CheckFile', input_file='AOD.pool.root')
STL class.
std::vector< std::string > split(const std::string &s, const std::string &t=":")
Definition hcg.cxx:179
default_check_steps(test, checkfile_input='AOD.pool.root, ESD.pool.root, RDO_TRIG.pool.root, DAOD_PHYS.DAOD.pool.root')
add_step_after_type(step_list, ref_type, step_to_add)