1 from __future__
import print_function
6 __author__ =
'Marco Clemencic CERN/PH-LBC' 21 from subprocess
import Popen, PIPE, STDOUT
24 from GaudiKernel
import ROOT6WorkAroundEnabled
33 os.environ[
'LC_ALL'] =
'C' 37 import xml.etree.cElementTree
as ET
39 import xml.etree.ElementTree
as ET
45 return timedelta.days * 86400 + timedelta.seconds + timedelta.microseconds / 1000000
49 from qm.test.classes.command
import ExecTestBase
50 from qm.test.result_stream
import ResultStream
57 if sys.platform ==
"win32":
60 from threading
import *
68 from six.moves
import cPickle
80 Class to changes the environment temporarily. 83 def __init__(self, orig=os.environ, keep_same=False):
85 Create a temporary environment on top of the one specified 86 (it can be another TemporaryEnvironment instance). 95 Set an environment variable recording the previous value. 103 self.
env[key] = value
107 Get an environment variable. 108 Needed to provide the same interface as os.environ. 114 Unset an environment variable. 115 Needed to provide the same interface as os.environ. 117 if key
not in self.
env:
124 Return the list of defined environment variables. 125 Needed to provide the same interface as os.environ. 131 Return the list of (name,value) pairs for the defined environment variables. 132 Needed to provide the same interface as os.environ. 139 Needed to provide the same interface as os.environ. 141 return key
in self.
env 145 Revert all the changes done to the original environment. 151 self.
env[key] = value
156 Revert the changes on destruction. 163 Generate a shell script to reproduce the changes in the environment. 165 shells = [
'csh',
'sh',
'bat']
166 if shell_type
not in shells:
167 raise RuntimeError(
"Shell type '%s' unknown. Available: %s" %
168 (shell_type, shells))
171 if key
not in self.
env:
173 if shell_type ==
'csh':
174 out +=
'unsetenv %s\n' % key
175 elif shell_type ==
'sh':
176 out +=
'unset %s\n' % key
177 elif shell_type ==
'bat':
178 out +=
'set %s=\n' % key
181 if shell_type ==
'csh':
182 out +=
'setenv %s "%s"\n' % (key, self.
env[key])
183 elif shell_type ==
'sh':
184 out +=
'export %s="%s"\n' % (key, self.
env[key])
185 elif shell_type ==
'bat':
186 out +=
'set %s=%s\n' % (key, self.
env[key])
191 """Small class for temporary directories. 192 When instantiated, it creates a temporary directory and the instance 193 behaves as the string containing the directory name. 194 When the instance goes out of scope, it removes all the content of 195 the temporary directory (automatic clean-up). 213 shutil.rmtree(self.
name)
216 return getattr(self.
name, attr)
220 """Small class for temporary files. 221 When instantiated, it creates a temporary directory and the instance 222 behaves as the string containing the directory name. 223 When the instance goes out of scope, it removes all the content of 224 the temporary directory (automatic clean-up). 237 self._fd, self.
name = tempfile.mkstemp(suffix, prefix, dir, text)
238 self.
file = os.fdopen(self._fd,
"r+")
250 return getattr(self.
file, attr)
254 """Small wrapper to call CMT. 264 if type(args)
is str:
266 cmd =
"cmt %s" % command
274 result = os.popen4(cmd)[1].
read()
280 return lambda args=[]: self.
_run_cmt(attr, args)
283 """Returns a dictionary containing the runtime environment produced by CMT. 284 If a dictionary is passed a modified instance of it is returned. 288 for l
in self.setup(
"-csh").splitlines():
290 if l.startswith(
"setenv"):
291 dummy, name, value = l.split(
None, 3)
292 env[name] = value.strip(
'"')
293 elif l.startswith(
"unsetenv"):
294 dummy, name = l.split(
None, 2)
300 r = self.show([
"macro", k])
301 if r.find(
"CMT> Error: symbol not found") >= 0:
304 return self.show([
"macro_value", k]).strip()
312 Locates an executable in the executables path ($PATH) and returns the full 313 path to it. An application is looked for with or without the '.exe' suffix. 314 If the executable cannot be found, None is returned 316 if os.path.isabs(executable):
317 if not os.path.exists(executable):
318 if executable.endswith(
'.exe'):
319 if os.path.exists(executable[:-4]):
320 return executable[:-4]
322 for d
in os.environ.get(
"PATH").split(os.pathsep):
323 fullpath = os.path.join(d, executable)
324 if os.path.exists(fullpath):
326 if executable.endswith(
'.exe'):
327 return which(executable[:-4])
332 np = os.path.normpath(os.path.expandvars(p))
333 if os.path.exists(np):
334 p = os.path.realpath(np)
352 _illegal_xml_chars_RE = re.compile(
353 u'[\x00-\x08\x0b\x0c\x0e-\x1F\uD800-\uDFFF\uFFFE\uFFFF]')
357 "Return the hex string " 358 return "".join(
map(hexConvert, match.group()))
362 return hex(ord(char))
366 return _illegal_xml_chars_RE.sub(hexreplace, val)
370 """Filter out characters that are illegal in XML. 371 Looks for any character in val that is not allowed in XML 372 and replaces it with replacement ('?' by default). 375 return _illegal_xml_chars_RE.sub(replacement, val)
384 """Basic implementation of an option validator for Gaudi tests. 385 This implementation is based on the standard (LCG) validation functions 395 """Validate the output of the program. 397 'stdout' -- A string containing the data written to the standard output 400 'stderr' -- A string containing the data written to the standard error 403 'result' -- A 'Result' object. It may be used to annotate 404 the outcome according to the content of stderr. 406 returns -- A list of strings giving causes of failure.""" 411 causes.append(self.
cause)
417 """Compare 's1' and 's2', ignoring line endings. 423 returns -- True if 's1' and 's2' are the same, ignoring 424 differences in line endings.""" 430 to_ignore = re.compile(
431 r'Warning in <TInterpreter::ReadRootmapFile>: .* is already in .*' 435 return not to_ignore.match(l)
437 return filter(keep_line, s1.splitlines()) == filter(
438 keep_line, s2.splitlines())
440 return s1.splitlines() == s2.splitlines()
444 """ Base class for a callable that takes a file and returns a modified 451 if hasattr(input,
"__iter__"):
455 lines = input.splitlines()
463 output =
'\n'.join(output)
492 if line.find(s) >= 0:
507 if self.
start in line:
510 elif self.
end in line:
520 when = re.compile(when)
524 if isinstance(rhs, RegexpReplacer):
526 res._operations = self.
_operations + rhs._operations
528 res = FilePreprocessor.__add__(self, rhs)
533 if w
is None or w.search(line):
534 line = o.sub(r, line)
541 "[0-2]?[0-9]:[0-5][0-9]:[0-5][0-9] [0-9]{4}[-/][01][0-9][-/][0-3][0-9] *(CES?T)?",
542 "00:00:00 1970-01-01")
544 normalizeEOL.__processLine__ =
lambda line: str(line).rstrip() +
'\n' 548 skipEmptyLines.__processLine__ =
lambda line: (line.strip()
and line)
or None 562 line = line[:(pos + self.
siglen)]
563 lst = line[(pos + self.
siglen):].split()
565 line +=
" ".join(lst)
570 normalizeExamples = maskPointers + normalizeDate
573 (
"TIMER.TIMER",
r"\s+[+-]?[0-9]+[0-9.]*",
" 0"),
574 (
"release all pending",
r"^.*/([^/]*:.*)",
r"\1"),
575 (
"0x########",
r"\[.*/([^/]*.*)\]",
r"[\1]"),
576 (
"^#.*file",
r"file '.*[/\\]([^/\\]*)$",
r"file '\1"),
577 (
"^JobOptionsSvc.*options successfully read in from",
578 r"read in from .*[/\\]([^/\\]*)$",
582 r"[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}(?!-0{12})-[0-9A-Fa-f]{12}",
583 "00000000-0000-0000-0000-000000000000"),
585 (
"ServiceLocatorHelper::",
"ServiceLocatorHelper::(create|locate)Service",
586 "ServiceLocatorHelper::service"),
588 (
None,
r"e([-+])0([0-9][0-9])",
r"e\1\2"),
590 (
None,
r'Service reference count check:',
591 r'Looping over all active services...'),
593 (
None,
r"Property(.*)'ErrorCount':",
r"Property\1'ErrorCounter':"),
600 "JobOptionsSvc INFO # ",
601 "JobOptionsSvc WARNING # ",
604 "This machine has a speed",
607 "ToolSvc.Sequenc... INFO",
608 "DataListenerSvc INFO XML written to file:",
611 "DEBUG No writable file catalog found which contains FID:",
613 "DEBUG Service base class initialized successfully",
614 "DEBUG Incident timing:",
616 "INFO 'CnvServices':[",
620 'EventLoopMgr SUCCESS Event Number = ',
621 'EventLoopMgr SUCCESS ---> Loop Finished',
624 r"^JobOptionsSvc INFO *$",
627 r"(Always|SUCCESS)\s*(Root f|[^ ]* F)ile version:",
629 r"0x[0-9a-fA-F#]+ *Algorithm::sysInitialize\(\) *\[",
631 r"0x[0-9a-fA-F#]* *__gxx_personality_v0 *\[",
632 r"File '.*.xml' does not exist",
633 r"INFO Refer to dataset .* by its file ID:",
634 r"INFO Referring to dataset .* by its file ID:",
635 r"INFO Disconnect from dataset",
636 r"INFO Disconnected from dataset",
637 r"INFO Disconnected data IO:",
638 r"IncidentSvc\s*(DEBUG (Adding|Removing)|VERBOSE Calling)",
640 r"^StatusCodeSvc.*listing all unchecked return codes:",
641 r"^StatusCodeSvc\s*INFO\s*$",
642 r"Num\s*\|\s*Function\s*\|\s*Source Library",
645 r"ERROR Failed to modify file: .* Errno=2 No such file or directory",
647 r"^ +[0-9]+ \|.*ROOT",
648 r"^ +[0-9]+ \|.*\|.*Dict",
650 r"StatusCodeSvc.*all StatusCode instances where checked",
652 r"EventLoopMgr.*---> Loop Finished",
656 r"SUCCESS\s*Booked \d+ Histogram\(s\)",
663 r'Warning in <TInterpreter::ReadRootmapFile>: .* is already in .*',
666 normalizeExamples = (lineSkipper + normalizeExamples + skipEmptyLines +
667 normalizeEOL +
LineSorter(
"Services to release : "))
671 def __init__(self, reffile, cause, result_key, preproc=normalizeExamples):
679 if os.path.isfile(self.
reffile):
680 orig = open(self.
reffile).readlines()
686 new = stdout.splitlines()
690 diffs = difflib.ndiff(orig, new, charjunk=difflib.IS_CHARACTER_JUNK)
691 filterdiffs =
map(
lambda x: x.strip(),
692 filter(
lambda x: x[0] !=
" ", diffs))
695 result[self.
result_key] = result.Quote(
"\n".join(filterdiffs))
699 +) standard output of the test""")
700 causes.append(self.
cause)
718 Given a block of text, tries to find it in the output. 719 The block had to be identified by a signature line. By default, the first 720 line is used as signature, or the line pointed to by signature_offset. If 721 signature_offset points outside the block, a signature line can be passed as 722 signature argument. Note: if 'signature' is None (the default), a negative 723 signature_offset is interpreted as index in a list (e.g. -1 means the last 724 line), otherwise the it is interpreted as the number of lines before the 725 first one of the block the signature must appear. 726 The parameter 'id' allow to distinguish between different calls to this 727 function in the same validation code. 730 reflines = filter(
None,
map(
lambda s: s.rstrip(), reference.splitlines()))
732 raise RuntimeError(
"Empty (or null) reference")
734 outlines = filter(
None,
map(
lambda s: s.rstrip(), stdout.splitlines()))
736 res_field =
"GaudiTest.RefBlock" 738 res_field +=
"_%s" % id
740 if signature
is None:
741 if signature_offset < 0:
742 signature_offset = len(reference) + signature_offset
743 signature = reflines[signature_offset]
746 pos = outlines.index(signature)
747 outlines = outlines[pos - signature_offset:pos + len(reflines) -
749 if reflines != outlines:
750 msg =
"standard output" 752 if not msg
in causes:
754 result[res_field +
".observed"] = result.Quote(
"\n".join(outlines))
756 causes.append(
"missing signature")
757 result[res_field +
".signature"] = result.Quote(signature)
758 if len(reflines) > 1
or signature != reflines[0]:
759 result[res_field +
".expected"] = result.Quote(
"\n".join(reflines))
766 Count the number of messages with required severity (by default ERROR and FATAL) 767 and check if their numbers match the expected ones (0 by default). 768 The dictionary "expected" can be used to tune the number of errors and fatals 769 allowed, or to limit the number of expected warnings etc. 771 stdout = kwargs[
"stdout"]
772 result = kwargs[
"result"]
773 causes = kwargs[
"causes"]
780 outlines = stdout.splitlines()
781 from math
import log10
782 fmt =
"%%%dd - %%s" % (int(log10(len(outlines)) + 1))
788 if len(words) >= 2
and words[1]
in errors:
789 errors[words[1]].append(fmt % (linecount, l.rstrip()))
792 if len(errors[e]) != expected[e]:
793 causes.append(
'%s(%d)' % (e, len(errors[e])))
794 result[
"GaudiTest.lines.%s" % e] = result.Quote(
'\n'.join(
796 result[
"GaudiTest.lines.%s.expected#" % e] = result.Quote(
804 Parse the TTree summary table in lines, starting from pos. 805 Returns a tuple with the dictionary with the digested informations and the 806 position of the first line after the summary. 813 return [f.strip()
for f
in l.strip(
"*\n").split(
':', 2)]
817 cols = splitcols(ll[0])
818 r[
"Name"], r[
"Title"] = cols[1:]
820 cols = splitcols(ll[1])
821 r[
"Entries"] = int(cols[1])
823 sizes = cols[2].split()
824 r[
"Total size"] = int(sizes[2])
825 if sizes[-1] ==
"memory":
828 r[
"File size"] = int(sizes[-1])
830 cols = splitcols(ll[2])
831 sizes = cols[2].split()
832 if cols[0] ==
"Baskets":
833 r[
"Baskets"] = int(cols[1])
834 r[
"Basket size"] = int(sizes[2])
835 r[
"Compression"] = float(sizes[-1])
838 if i < (count - 3)
and lines[i].startswith(
"*Tree"):
839 result = parseblock(lines[i:i + 3])
840 result[
"Branches"] = {}
842 while i < (count - 3)
and lines[i].startswith(
"*Br"):
843 if i < (count - 2)
and lines[i].startswith(
"*Branch "):
847 branch = parseblock(lines[i:i + 3])
848 result[
"Branches"][branch[
"Name"]] = branch
856 Scan stdout to find ROOT TTree summaries and digest them. 858 stars = re.compile(
r"^\*+$")
859 outlines = stdout.splitlines()
860 nlines = len(outlines)
866 while i < nlines
and not stars.match(outlines[i]):
871 trees[tree[
"Name"]] = tree
878 Check that all the keys in reference are in to_check too, with the same value. 879 If the value is a dict, the function is called recursively. to_check can 880 contain more keys than reference, that will not be tested. 881 The function returns at the first difference found. 886 ignore_re = re.compile(ignore)
887 keys = [key
for key
in reference
if not ignore_re.match(key)]
889 keys = reference.keys()
893 if (
type(reference[k])
is dict)
and (
type(to_check[k])
is dict):
895 failed = fail_keys =
cmpTreesDicts(reference[k], to_check[k],
899 failed = to_check[k] != reference[k]
904 fail_keys.insert(0, k)
915 if c
is None or r
is None:
917 return (fail_path, r, c)
921 h_count_re = re.compile(
r"^(.*)SUCCESS\s+Booked (\d+) Histogram\(s\) :\s+(.*)")
926 Extract the histograms infos from the lines starting at pos. 927 Returns the position of the first line after the summary block. 930 h_table_head = re.compile(
931 r'SUCCESS\s+(1D|2D|3D|1D profile|2D profile) histograms in directory\s+"(\w*)"' 933 h_short_summ = re.compile(
r"ID=([^\"]+)\s+\"([^\"]+)\"\s+(.*)")
938 m = h_count_re.search(lines[pos])
939 name = m.group(1).strip()
940 total = int(m.group(2))
942 for k, v
in [x.split(
"=")
for x
in m.group(3).split()]:
945 header[
"Total"] = total
949 m = h_table_head.search(lines[pos])
952 t = t.replace(
" profile",
"Prof")
959 if l.startswith(
" | ID"):
961 titles = [x.strip()
for x
in l.split(
"|")][1:]
963 while pos < nlines
and lines[pos].startswith(
" |"):
965 values = [x.strip()
for x
in l.split(
"|")][1:]
967 for i
in range(len(titles)):
968 hcont[titles[i]] = values[i]
969 cont[hcont[
"ID"]] = hcont
971 elif l.startswith(
" ID="):
972 while pos < nlines
and lines[pos].startswith(
" ID="):
975 for x
in h_short_summ.search(lines[pos]).groups()
977 cont[values[0]] = values
981 "Cannot understand line %d: '%s'" % (pos, l))
985 summ[d][
"header"] = header
990 summ[name] = {
"header": header}
996 Scan stdout to find ROOT TTree summaries and digest them. 998 outlines = stdout.splitlines()
999 nlines = len(outlines) - 1
1007 match = h_count_re.search(outlines[pos])
1008 while pos < nlines
and not match:
1010 match = h_count_re.search(outlines[pos])
1013 summaries.update(summ)
1019 """Create a new 'Filter'. 1021 'input' -- The string containing the input to provide to the 1024 'timeout' -- As for 'TimeoutExecutable.__init__'.""" 1026 super(GaudiFilterExecutable, self).
__init__(input, timeout)
1033 tmpf = tempfile.mkstemp()
1038 """Copied from TimeoutExecutable to allow the re-implementation of 1041 if sys.platform ==
"win32":
1054 """Code copied from both FilterExecutable and TimeoutExecutable. 1057 if self._stdin_pipe:
1058 self._ClosePipeEnd(self._stdin_pipe[0])
1059 if self._stdout_pipe:
1060 self._ClosePipeEnd(self._stdout_pipe[1])
1061 if self._stderr_pipe:
1062 self._ClosePipeEnd(self._stderr_pipe[1])
1070 super(qm.executable.TimeoutExecutable, self).
_HandleChild()
1077 child_pid = self._GetChildPID()
1079 os.setpgid(child_pid, child_pid)
1107 os.setpgid(0, child_pid)
1116 max_fds = os.sysconf(
"SC_OPEN_MAX")
1119 for fd
in range(max_fds):
1130 if sys.platform ==
"linux2":
1133 os.path.join(
"/proc", str(child_pid),
"exe"),
1134 str(child_pid),
"-batch",
"-n",
"-x",
1135 "'%s'" % os.path.join(
1136 os.path.dirname(__file__),
1141 o = os.popen(
" ".join(cmd)).
read()
1146 os.kill(0, signal.SIGKILL)
1149 select.select([], [], [])
1154 elif self.
__timeout >= 0
and sys.platform ==
"win32":
1159 if sys.platform ==
"win32":
1162 """Code copied from FilterExecutable. 1163 Kill the child if the timeout expires. 1165 This function is run in the monitoring thread.""" 1173 result = win32event.WaitForSingleObject(self._GetChildPID(),
1176 if result == win32con.WAIT_TIMEOUT:
1186 """Standard Gaudi test. 1189 qm.fields.TextField(
1193 description=
"""The path to the program. 1195 This field indicates the path to the program. If it is not 1196 an absolute path, the value of the 'PATH' environment 1197 variable will be used to search for the program. 1198 If not specified, $GAUDIEXE or Gaudi.exe are used. 1201 qm.fields.TextField(
1203 title=
"Argument List",
1204 description=
"""The command-line arguments. 1206 If this field is left blank, the program is run without any 1209 Use this field to specify the option files. 1211 An implicit 0th argument (the path to the program) is added 1212 automatically.""")),
1213 qm.fields.TextField(
1216 description=
"""Options to be passed to the application. 1218 This field allows to pass a list of options to the main program 1219 without the need of a separate option file. 1221 The content of the field is written to a temporary file which name 1222 is passed the the application as last argument (appended to the 1223 field "Argument List". 1228 qm.fields.TextField(
1230 title=
"Working Directory",
1231 description=
"""Path to the working directory. 1233 If this field is left blank, the program will be run from the qmtest 1234 directory, otherwise from the directory specified.""",
1236 qm.fields.TextField(
1238 title=
"Reference Output",
1239 description=
"""Path to the file containing the reference output. 1241 If this field is left blank, any standard output will be considered 1244 If the reference file is specified, any output on standard error is 1246 qm.fields.TextField(
1247 name=
"error_reference",
1248 title=
"Reference for standard error",
1250 """Path to the file containing the reference for the standard error. 1252 If this field is left blank, any standard output will be considered 1255 If the reference file is specified, any output on standard error is 1258 qm.fields.TextField(
1259 name=
"unsupported_platforms",
1260 title=
"Unsupported Platforms",
1261 description=
"""Platform on which the test must not be run. 1263 List of regular expressions identifying the platforms on which the 1264 test is not run and the result is set to UNTESTED.""")),
1265 qm.fields.TextField(
1268 description=
"""Function to validate the output of the test. 1270 If defined, the function is used to validate the products of the 1272 The function is called passing as arguments: 1273 self: the test class instance 1274 stdout: the standard output of the executed test 1275 stderr: the standard error of the executed test 1276 result: the Result objects to fill with messages 1277 The function must return a list of causes for the failure. 1278 If specified, overrides standard output, standard error and 1284 qm.fields.BooleanField(
1285 name=
"use_temp_dir",
1286 title=
"Use temporary directory",
1287 description=
"""Use temporary directory. 1289 If set to true, use a temporary directory as working directory. 1291 default_value=
"false"),
1292 qm.fields.IntegerField(
1294 title=
"Expected signal",
1295 description=
"""Expect termination by signal.""",
1296 default_value=
None),
1303 for x
in [str(y).strip()
for y
in self.unsupported_platforms]
if x
1305 for p_re
in unsupported:
1306 if p_re.search(platform):
1307 result.SetOutcome(result.UNTESTED)
1308 result[result.CAUSE] =
'Platform not supported.' 1314 Return the platform Id defined in CMTCONFIG or SCRAM_ARCH. 1318 if "CMTCONFIG" in os.environ:
1319 arch = os.environ[
"CMTCONFIG"]
1320 elif "SCRAM_ARCH" in os.environ:
1321 arch = os.environ[
"SCRAM_ARCH"]
1326 Return True if the current platform is Windows. 1328 This function was needed because of the change in the CMTCONFIG format, 1329 from win32_vc71_dbg to i686-winxp-vc9-dbg. 1332 return "winxp" in platform
or platform.startswith(
"win")
1340 def platformSplit(p):
1341 return set(p.split(
'-' in p
and '-' or '_'))
1343 reference = os.path.normpath(os.path.expandvars(reffile))
1345 spec_ref = reference[:-3] + self.
GetPlatform()[0:3] + reference[-3:]
1346 if os.path.isfile(spec_ref):
1347 reference = spec_ref
1350 dirname, basename = os.path.split(reference)
1353 head = basename +
"." 1354 head_len = len(head)
1356 if 'do0' in platform:
1359 for f
in os.listdir(dirname):
1360 if f.startswith(head):
1361 req_plat = platformSplit(f[head_len:])
1362 if platform.issuperset(req_plat):
1363 candidates.append((len(req_plat), f))
1368 reference = os.path.join(dirname, candidates[-1][1])
1376 ignore=r"Basket|.*size|Compression"):
1378 Compare the TTree summaries in stdout with the ones in trees_dict or in 1379 the reference file. By default ignore the size, compression and basket 1381 The presence of TTree summaries when none is expected is not a failure. 1383 if trees_dict
is None:
1386 if reference
and os.path.isfile(reference):
1391 from pprint
import PrettyPrinter
1392 pp = PrettyPrinter()
1394 result[
"GaudiTest.TTrees.expected"] = result.Quote(
1395 pp.pformat(trees_dict))
1397 result[
"GaudiTest.TTrees.ignore"] = result.Quote(ignore)
1402 causes.append(
"trees summaries")
1405 result[
"GaudiTest.TTrees.failure_on"] = result.Quote(msg)
1406 result[
"GaudiTest.TTrees.found"] = result.Quote(pp.pformat(trees))
1417 Compare the TTree summaries in stdout with the ones in trees_dict or in 1418 the reference file. By default ignore the size, compression and basket 1420 The presence of TTree summaries when none is expected is not a failure. 1425 if reference
and os.path.isfile(reference):
1430 from pprint
import PrettyPrinter
1431 pp = PrettyPrinter()
1433 result[
"GaudiTest.Histos.expected"] = result.Quote(
1436 result[
"GaudiTest.Histos.ignore"] = result.Quote(ignore)
1441 causes.append(
"histos summaries")
1443 result[
"GaudiTest.Histos.failure_on"] = result.Quote(msg)
1444 result[
"GaudiTest.Histos.found"] = result.Quote(pp.pformat(histos))
1455 Default validation action: compare standard output and error to the 1460 preproc = normalizeExamples
1464 if reference
and os.path.isfile(reference):
1465 result[
"GaudiTest.output_reference"] = reference
1469 "GaudiTest.output_diff",
1470 preproc=preproc)(stdout, result)
1478 newref = open(reference +
".new",
"w")
1480 for l
in stdout.splitlines():
1481 newref.write(l.rstrip() +
'\n')
1491 if reference
and os.path.isfile(reference):
1492 result[
"GaudiTest.error_reference"] = reference
1496 "GaudiTest.error_diff",
1497 preproc=preproc)(stderr, result)
1500 newref = open(reference +
".new",
"w")
1502 for l
in stderr.splitlines():
1503 newref.write(l.rstrip() +
'\n')
1507 "ExecTest.expected_stderr")(stderr,
1515 if self.validator.strip() !=
"":
1517 class CallWrapper(object):
1519 Small wrapper class to dynamically bind some default arguments 1523 def __init__(self, callable, extra_args={}):
1527 from inspect
import getargspec
1534 def __call__(self, *args, **kwargs):
1538 kwargs = dict(kwargs)
1542 if a
not in positional
and a
not in kwargs:
1544 return self.
callable(*args, **kwargs)
1547 exported_symbols = {
1558 "findReferenceBlock":
1559 CallWrapper(findReferenceBlock, {
1564 "validateWithReference":
1573 CallWrapper(countErrorLines, {
1578 "checkTTreesSummaries":
1584 "checkHistosSummaries":
1591 exec (self.validator, globals(), exported_symbols)
1599 Add the content of the environment to the result object. 1601 Copied from the QMTest class of COOL. 1603 vars = os.environ.keys()
1605 result[
'GaudiTest.environment'] = \
1607 '\n'.join([
"%s=%s" % (v, os.environ[v])
for v
in vars]))
1609 def Run(self, context, result):
1612 'context' -- A 'Context' giving run-time parameters to the 1615 'result' -- A 'Result' object. The outcome will be 1616 'Result.PASS' when this method is called. The 'result' may be 1617 modified by this method to indicate outcomes other than 1618 'Result.PASS' or to add annotations.""" 1627 elif "GAUDIEXE" in os.environ:
1628 prog = os.environ[
"GAUDIEXE"]
1633 dummy, prog_ext = os.path.splitext(prog)
1634 if prog_ext
not in [
".exe",
".py",
".bat"]
and self.
isWinPlatform():
1638 prog =
which(prog)
or prog
1641 args =
map(rationalizepath, self.args)
1647 if self.options.strip():
1650 r"from\s+Gaudi.Configuration\s+import\s+\*|from\s+Configurables\s+import",
1654 tmpfile.writelines(
"\n".join(self.options.splitlines()))
1656 args.append(tmpfile.name)
1657 result[
"GaudiTest.options"] = result.Quote(self.options)
1660 if prog_ext ==
".py":
1661 args.insert(0, prog)
1663 prog =
which(
"python.exe")
or "python.exe" 1665 prog =
which(
"python")
or "python" 1668 origdir = os.getcwd()
1670 os.chdir(str(os.path.normpath(os.path.expandvars(self.workdir))))
1672 if "QMTEST_TMPDIR" in os.environ:
1673 qmtest_tmpdir = os.environ[
"QMTEST_TMPDIR"]
1674 if not os.path.exists(qmtest_tmpdir):
1675 os.makedirs(qmtest_tmpdir)
1676 os.chdir(qmtest_tmpdir)
1677 elif "qmtest.tmpdir" in context:
1678 os.chdir(context[
"qmtest.tmpdir"])
1680 if "QMTEST_IGNORE_TIMEOUT" not in os.environ:
1688 prog, args, destdir=os.path.join(origdir,
'.eclipse'))
1690 self.
RunProgram(prog, [prog] + args, context, result)
1692 if result.GetOutcome()
not in [result.PASS]:
1699 """Run the 'program'. 1701 'program' -- The path to the program to run. 1703 'arguments' -- A list of the arguments to the program. This 1704 list must contain a first argument corresponding to 'argv[0]'. 1706 'context' -- A 'Context' giving run-time parameters to the 1709 'result' -- A 'Result' object. The outcome will be 1710 'Result.PASS' when this method is called. The 'result' may be 1711 modified by this method to indicate outcomes other than 1712 'Result.PASS' or to add annotations. 1714 @attention: This method has been copied from command.ExecTestBase 1715 (QMTest 2.3.0) and modified to keep stdout and stderr 1716 for tests that have been terminated by a signal. 1717 (Fundamental for debugging in the Application Area) 1721 environment = self.MakeEnvironment(context)
1723 if "slc6" in environment.get(
'CMTCONFIG',
''):
1724 environment[
'TERM'] =
'dumb' 1737 exit_status = e.Run(arguments, environment, path=program)
1739 if e.stack_trace_file
and os.path.exists(e.stack_trace_file):
1740 stack_trace = open(e.stack_trace_file).
read()
1741 os.remove(e.stack_trace_file)
1745 result[
"ExecTest.stack_trace"] = result.Quote(stack_trace)
1748 if (sys.platform ==
"win32" or os.WIFEXITED(exit_status)
1754 if self.exit_code
is None:
1756 elif sys.platform ==
"win32":
1757 exit_code = exit_status
1759 exit_code = os.WEXITSTATUS(exit_status)
1764 result[
"ExecTest.exit_code"] = str(exit_code)
1765 result[
"ExecTest.stdout"] = result.Quote(stdout)
1766 result[
"ExecTest.stderr"] = result.Quote(stderr)
1768 if exit_code != self.exit_code:
1769 causes.append(
"exit_code")
1770 result[
"ExecTest.expected_exit_code"] \
1771 = str(self.exit_code)
1776 result.Fail(
"Unexpected %s." % string.join(causes,
", "))
1777 elif os.WIFSIGNALED(exit_status):
1780 signal_number = str(os.WTERMSIG(exit_status))
1782 result.Fail(
"Program terminated by signal.")
1786 result.Fail(
"Exceeded time limit (%ds), terminated." % timeout)
1787 result[
"ExecTest.signal_number"] = signal_number
1788 result[
"ExecTest.stdout"] = result.Quote(e.stdout)
1789 result[
"ExecTest.stderr"] = result.Quote(e.stderr)
1791 result[
"ExecTest.expected_signal_number"] = str(self.
signal)
1792 elif os.WIFSTOPPED(exit_status):
1795 signal_number = str(os.WSTOPSIG(exit_status))
1797 result.Fail(
"Program stopped by signal.")
1801 result.Fail(
"Exceeded time limit (%ds), stopped." % timeout)
1802 result[
"ExecTest.signal_number"] = signal_number
1803 result[
"ExecTest.stdout"] = result.Quote(e.stdout)
1804 result[
"ExecTest.stderr"] = result.Quote(e.stderr)
1808 result.Fail(
"Program did not terminate normally.")
1814 result[
"ExecTest.stdout"] = result[
"ExecTest.stdout"].replace(
1820 if 'NO_ECLIPSE_LAUNCHERS' in os.environ:
1825 projbasedir = os.path.normpath(destdir)
1826 while not os.path.exists(os.path.join(projbasedir,
".project")):
1827 oldprojdir = projbasedir
1828 projbasedir = os.path.normpath(
1829 os.path.join(projbasedir, os.pardir))
1832 if oldprojdir == projbasedir:
1836 if not os.path.exists(destdir):
1837 os.makedirs(destdir)
1839 from xml.etree
import ElementTree
as ET
1840 t = ET.parse(os.path.join(projbasedir,
".project"))
1841 projectName = t.find(
"name").text
1844 destfile =
"%s.launch" % self._Runnable__id
1846 destfile = os.path.join(destdir, destfile)
1848 if self.options.strip():
1852 tempfile = args.pop()
1853 optsfile = destfile + os.path.splitext(tempfile)[1]
1854 shutil.copyfile(tempfile, optsfile)
1855 args.append(optsfile)
1858 from xml.sax.saxutils
import quoteattr
1862 data[
"environment"] =
"\n".join([
1863 '<mapEntry key=%s value=%s/>' % (quoteattr(k), quoteattr(v))
1864 for k, v
in os.environ.iteritems()
1865 if k
not in (
'MAKEOVERRIDES',
'MAKEFLAGS',
'MAKELEVEL')
1868 data[
"exec"] =
which(prog)
or prog
1869 if os.path.basename(data[
"exec"]).lower().startswith(
"python"):
1871 data[
"stopAtMain"] =
"false" 1873 data[
"stopAtMain"] =
"true" 1875 data[
"args"] =
" ".join(
map(rationalizepath, args))
1877 data[
"args"] =
" ".join(
1878 [
"/debugexe"] +
map(rationalizepath, [data[
"exec"]] + args))
1879 data[
"exec"] =
which(
"vcexpress.exe")
1882 data[
"workdir"] = os.getcwd()
1886 data[
"workdir"] = destdir
1888 data[
"project"] = projectName.strip()
1891 xml_template =
u"""<?xml version="1.0" encoding="UTF-8" standalone="no"?> 1892 <launchConfiguration type="org.eclipse.cdt.launch.applicationLaunchType"> 1893 <booleanAttribute key="org.eclipse.cdt.debug.mi.core.AUTO_SOLIB" value="true"/> 1894 <listAttribute key="org.eclipse.cdt.debug.mi.core.AUTO_SOLIB_LIST"/> 1895 <stringAttribute key="org.eclipse.cdt.debug.mi.core.DEBUG_NAME" value="gdb"/> 1896 <stringAttribute key="org.eclipse.cdt.debug.mi.core.GDB_INIT" value=".gdbinit"/> 1897 <listAttribute key="org.eclipse.cdt.debug.mi.core.SOLIB_PATH"/> 1898 <booleanAttribute key="org.eclipse.cdt.debug.mi.core.STOP_ON_SOLIB_EVENTS" value="false"/> 1899 <booleanAttribute key="org.eclipse.cdt.debug.mi.core.breakpointsFullPath" value="false"/> 1900 <stringAttribute key="org.eclipse.cdt.debug.mi.core.commandFactory" value="org.eclipse.cdt.debug.mi.core.standardCommandFactory"/> 1901 <stringAttribute key="org.eclipse.cdt.debug.mi.core.protocol" value="mi"/> 1902 <booleanAttribute key="org.eclipse.cdt.debug.mi.core.verboseMode" value="false"/> 1903 <intAttribute key="org.eclipse.cdt.launch.ATTR_BUILD_BEFORE_LAUNCH_ATTR" value="0"/> 1904 <stringAttribute key="org.eclipse.cdt.launch.COREFILE_PATH" value=""/> 1905 <stringAttribute key="org.eclipse.cdt.launch.DEBUGGER_ID" value="org.eclipse.cdt.debug.mi.core.CDebuggerNew"/> 1906 <stringAttribute key="org.eclipse.cdt.launch.DEBUGGER_REGISTER_GROUPS" value=""/> 1907 <stringAttribute key="org.eclipse.cdt.launch.DEBUGGER_START_MODE" value="run"/> 1908 <booleanAttribute key="org.eclipse.cdt.launch.DEBUGGER_STOP_AT_MAIN" value="%(stopAtMain)s"/> 1909 <stringAttribute key="org.eclipse.cdt.launch.DEBUGGER_STOP_AT_MAIN_SYMBOL" value="main"/> 1910 <booleanAttribute key="org.eclipse.cdt.launch.ENABLE_REGISTER_BOOKKEEPING" value="false"/> 1911 <booleanAttribute key="org.eclipse.cdt.launch.ENABLE_VARIABLE_BOOKKEEPING" value="false"/> 1912 <stringAttribute key="org.eclipse.cdt.launch.FORMAT" value="<?xml version="1.0" encoding="UTF-8" standalone="no"?><contentList/>"/> 1913 <stringAttribute key="org.eclipse.cdt.launch.GLOBAL_VARIABLES" value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <globalVariableList/> "/> 1914 <stringAttribute key="org.eclipse.cdt.launch.MEMORY_BLOCKS" value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <memoryBlockExpressionList/> "/> 1915 <stringAttribute key="org.eclipse.cdt.launch.PROGRAM_ARGUMENTS" value="%(args)s"/> 1916 <stringAttribute key="org.eclipse.cdt.launch.PROGRAM_NAME" value="%(exec)s"/> 1917 <stringAttribute key="org.eclipse.cdt.launch.PROJECT_ATTR" value="%(project)s"/> 1918 <stringAttribute key="org.eclipse.cdt.launch.PROJECT_BUILD_CONFIG_ID_ATTR" value=""/> 1919 <stringAttribute key="org.eclipse.cdt.launch.WORKING_DIRECTORY" value="%(workdir)s"/> 1920 <booleanAttribute key="org.eclipse.cdt.launch.ui.ApplicationCDebuggerTab.DEFAULTS_SET" value="true"/> 1921 <booleanAttribute key="org.eclipse.cdt.launch.use_terminal" value="true"/> 1922 <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS"> 1923 <listEntry value="/%(project)s"/> 1925 <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES"> 1926 <listEntry value="4"/> 1928 <booleanAttribute key="org.eclipse.debug.core.appendEnvironmentVariables" value="false"/> 1929 <mapAttribute key="org.eclipse.debug.core.environmentVariables"> 1932 <mapAttribute key="org.eclipse.debug.core.preferred_launchers"> 1933 <mapEntry key="[debug]" value="org.eclipse.cdt.cdi.launch.localCLaunch"/> 1935 <listAttribute key="org.eclipse.debug.ui.favoriteGroups"> 1936 <listEntry value="org.eclipse.debug.ui.launchGroup.debug"/> 1938 </launchConfiguration> 1943 data[k] = codecs.decode(data[k],
'utf-8')
1944 xml = xml_template % data
1947 codecs.open(destfile,
"w", encoding=
'utf-8').write(xml)
1949 print(
'WARNING: problem generating Eclipse launcher')
1956 import simplejson
as json
1960 """An 'HTMLResultStream' writes its output to a set of HTML files. 1962 The argument 'dir' is used to select the destination directory for the HTML 1964 The destination directory may already contain the report from a previous run 1965 (for example of a different package), in which case it will be extended to 1966 include the new data. 1969 qm.fields.TextField(
1971 title=
"Destination Directory",
1972 description=
"""The name of the directory. 1974 All results will be written to the directory indicated.""",
1980 """Prepare the destination directory. 1982 Creates the destination directory and store in it some preliminary 1983 annotations and the static files found in the template directory 1986 ResultStream.__init__(self, arguments, **args)
1991 templateDir = os.path.join(os.path.dirname(__file__),
"html_report")
1992 if not os.path.isdir(self.dir):
1993 os.makedirs(self.dir)
1995 for f
in os.listdir(templateDir):
1996 src = os.path.join(templateDir, f)
1997 dst = os.path.join(self.dir, f)
1998 if not os.path.isdir(src)
and not os.path.exists(dst):
1999 shutil.copy(src, dst)
2001 if "CMTCONFIG" in os.environ:
2007 """Helper function to extend the global summary file in the destination 2014 ids = set([i[
"id"]
for i
in self.
_summary])
2015 newSummary = [i
for i
in oldSummary
if i[
"id"]
not in ids]
2017 json.dump(newSummary, open(self.
_summaryFile,
"w"), sort_keys=
True)
2020 """Writes the annotation to the annotation file. 2021 If the key is already present with a different value, the value becomes 2022 a list and the new value is appended to it, except for start_time and 2031 key, value =
map(str, [key, value])
2032 if key ==
"qmtest.run.start_time":
2037 if key
not in annotations:
2038 annotations[key] = value
2039 if "qmtest.run.end_time" in annotations:
2040 del annotations[
"qmtest.run.end_time"]
2043 if key
in annotations:
2044 old = annotations[key]
2045 if type(old)
is list:
2046 if value
not in old:
2047 annotations[key].append(value)
2049 annotations[key] = [old, value]
2051 annotations[key] = value
2057 """Prepare the test result directory in the destination directory storing 2058 into it the result fields. 2059 A summary of the test result is stored both in a file in the test directory 2060 and in the global summary file. 2063 summary[
"id"] = result.GetId()
2064 summary[
"outcome"] = result.GetOutcome()
2065 summary[
"cause"] = result.GetCause()
2066 summary[
"fields"] = result.keys()
2067 summary[
"fields"].sort()
2070 for f
in [
"id",
"outcome",
"cause"]:
2071 summary[f] = str(summary[f])
2072 summary[
"fields"] =
map(str, summary[
"fields"])
2080 testOutDir = os.path.join(self.dir, summary[
"id"])
2081 if not os.path.isdir(testOutDir):
2082 os.makedirs(testOutDir)
2085 open(os.path.join(testOutDir,
"summary.json"),
"w"),
2087 for f
in summary[
"fields"]:
2088 open(os.path.join(testOutDir, f),
"w").write(result[f])
2097 class XMLResultStream(ResultStream):
2098 """An 'XMLResultStream' writes its output to a Ctest XML file. 2100 The argument 'dir' is used to select the destination file for the XML 2102 The destination directory may already contain the report from a previous run 2103 (for example of a different package), in which case it will be overrided to 2107 qm.fields.TextField(
2109 title=
"Destination Directory",
2110 description=
"""The name of the directory. 2112 All results will be written to the directory indicated.""",
2115 qm.fields.TextField(
2117 title=
"Output File Prefix",
2118 description=
"""The output file name will be the specified prefix 2119 followed by 'Test.xml' (CTest convention).""",
2125 """Prepare the destination directory. 2127 Creates the destination directory and store in it some preliminary 2130 ResultStream.__init__(self, arguments, **args)
2132 self.
_xmlFile = os.path.join(self.dir, self.prefix +
'Test.xml')
2138 if not os.path.isfile(self.
_xmlFile):
2140 if not os.path.exists(os.path.dirname(self.
_xmlFile)):
2141 os.makedirs(os.path.dirname(self.
_xmlFile))
2143 newdataset = ET.Element(
"newdataset")
2149 newdataset = self.
_tree.getroot()
2156 for site
in newdataset.getiterator():
2158 if site.get(
"OSPlatform") == os.uname()[4]:
2167 import multiprocessing
2169 "BuildName": os.getenv(
"CMTCONFIG"),
2170 "Name": os.uname()[1],
2171 "Generator":
"QMTest " + qm.version,
2172 "OSName": os.uname()[0],
2173 "Hostname": socket.gethostname(),
2174 "OSRelease": os.uname()[2],
2175 "OSVersion": os.uname()[3],
2176 "OSPlatform": os.uname()[4],
2177 "Is64Bits":
"unknown",
2178 "VendorString":
"unknown",
2179 "VendorID":
"unknown",
2180 "FamilyID":
"unknown",
2181 "ModelID":
"unknown",
2182 "ProcessorCacheSize":
"unknown",
2183 "NumberOfLogicalCPU": str(multiprocessing.cpu_count()),
2184 "NumberOfPhysicalCPU":
"0",
2185 "TotalVirtualMemory":
"0",
2186 "TotalPhysicalMemory":
"0",
2187 "LogicalProcessorsPerPhysical":
"0",
2188 "ProcessorClockFrequency":
"0",
2190 self.
_site = ET.SubElement(newdataset,
"Site", attrib)
2217 # Add some non-QMTest attributes 2218 if "CMTCONFIG" in os.environ: 2219 self.WriteAnnotation("cmt.cmtconfig", os.environ["CMTCONFIG"]) 2221 self.WriteAnnotation("hostname", socket.gethostname()) 2225 if key ==
"qmtest.run.start_time":
2226 if self.
_site.
get(
"qmtest.run.start_time")
is not None:
2228 self.
_site.set(str(key), str(value))
2231 """Prepare the test result directory in the destination directory storing 2232 into it the result fields. 2233 A summary of the test result is stored both in a file in the test directory 2234 and in the global summary file. 2237 summary[
"id"] = result.GetId()
2238 summary[
"outcome"] = result.GetOutcome()
2239 summary[
"cause"] = result.GetCause()
2240 summary[
"fields"] = result.keys()
2241 summary[
"fields"].sort()
2244 for f
in [
"id",
"outcome",
"cause"]:
2245 summary[f] = str(summary[f])
2246 summary[
"fields"] =
map(str, summary[
"fields"])
2251 if "qmtest.start_time" in summary[
"fields"]:
2252 haveStartDate =
True 2254 haveStartDate =
False 2255 if "qmtest.end_time" in summary[
"fields"]:
2263 time.strptime(result[
"qmtest.start_time"],
2264 "%Y-%m-%dT%H:%M:%SZ"))
2267 "%b %d %H:%M %Z", time.localtime(self.
_startTime))
2269 self.
_site.set(
"BuildStamp", result[
"qmtest.start_time"])
2274 time.strptime(result[
"qmtest.end_time"],
"%Y-%m-%dT%H:%M:%SZ"))
2277 tl = ET.Element(
"Test")
2278 tl.text = summary[
"id"]
2282 Test = ET.Element(
"Test")
2283 if summary[
"outcome"] ==
"PASS":
2284 Test.set(
"Status",
"passed")
2285 elif summary[
"outcome"] ==
"FAIL":
2286 Test.set(
"Status",
"failed")
2287 elif summary[
"outcome"] ==
"SKIPPED" or summary[
2288 "outcome"] ==
"UNTESTED":
2289 Test.set(
"Status",
"skipped")
2290 elif summary[
"outcome"] ==
"ERROR":
2291 Test.set(
"Status",
"failed")
2292 Name = ET.SubElement(
2296 Name.text = summary[
"id"]
2297 Results = ET.SubElement(Test,
"Results")
2302 if haveStartDate
and haveEndDate:
2305 testduration = str(delta)
2306 Testduration = ET.SubElement(Results,
"NamedMeasurement")
2307 Testduration.set(
"name",
"Execution Time")
2308 Testduration.set(
"type",
"numeric/float")
2309 value = ET.SubElement(Testduration,
"Value")
2310 value.text = testduration
2313 for n
in (
"qmtest.end_time",
"qmtest.start_time",
"qmtest.cause",
2315 if n
in summary[
"fields"]:
2316 summary[
"fields"].remove(n)
2320 if "ExecTest.exit_code" in summary[
"fields"]:
2321 summary[
"fields"].remove(
"ExecTest.exit_code")
2322 ExitCode = ET.SubElement(Results,
"NamedMeasurement")
2323 ExitCode.set(
"name",
"exit_code")
2324 ExitCode.set(
"type",
"numeric/integer")
2325 value = ET.SubElement(ExitCode,
"Value")
2327 result[
"ExecTest.exit_code"])
2329 TestStartTime = ET.SubElement(Results,
"NamedMeasurement")
2330 TestStartTime.set(
"name",
"Start_Time")
2331 TestStartTime.set(
"type",
"String")
2332 value = ET.SubElement(TestStartTime,
"Value")
2335 time.strftime(
"%b %d %H:%M %Z %Y",
2340 TestEndTime = ET.SubElement(Results,
"NamedMeasurement")
2341 TestEndTime.set(
"name",
"End_Time")
2342 TestEndTime.set(
"type",
"String")
2343 value = ET.SubElement(TestEndTime,
"Value")
2346 time.strftime(
"%b %d %H:%M %Z %Y",
2351 if summary[
"cause"]:
2352 FailureCause = ET.SubElement(Results,
"NamedMeasurement")
2353 FailureCause.set(
"name",
"Cause")
2354 FailureCause.set(
"type",
"String")
2355 value = ET.SubElement(FailureCause,
"Value")
2360 for field
in summary[
"fields"]:
2361 fields[field] = ET.SubElement(Results,
"NamedMeasurement")
2362 fields[field].set(
"type",
"String")
2363 fields[field].set(
"name", field)
2364 value = ET.SubElement(fields[field],
"Value")
2366 if "<pre>" in result[field][0:6]:
2371 if "ExecTest.stdout" in result:
2372 Measurement = ET.SubElement(Results,
"Measurement")
2373 value = ET.SubElement(Measurement,
"Value")
2374 if "<pre>" in result[
"ExecTest.stdout"][0:6]:
2376 result[
"ExecTest.stdout"][5:-6])
2379 result[
"ExecTest.stdout"])
2389 self.
_EndDateTime.text = time.strftime(
"%b %d %H:%M %Z",
def __init__(self, suffix='', prefix='tmp', dir=None, text=False, keep=False)
def __init__(self, ref, cause, result_key)
def __init__(self, orig, repl="", when=None)
def __init__(self, strings=[], regexps=[])
def __init__(self, keep=False, chdir=False)
def parseHistosSummary(lines, pos)
def __init__(self, input, timeout=-1)
def CheckHistosSummaries(self, stdout, result, causes, dict=None, ignore=None)
def countErrorLines(expected={ 'ERROR':0, 'FATAL':0}, **kwargs)
def __init__(self, signature)
def __init__(self, arguments=None, **args)
def PlatformIsNotSupported(self, context, result)
def __init__(self, reffile, cause, result_key, preproc=normalizeExamples)
def __processLine__(self, line)
def DumpEnvironment(self, result)
def __delitem__(self, key)
def _HandleChild(self)
Needs to replace the ones from RedirectedExecutable and TimeoutExecutable.
def __init__(self, members=[])
def __contains__(self, key)
def read(f, regex='.*', skipevents=0)
def runtime_env(self, env=None)
def _expandReferenceFileName(self, reffile)
def escape_xml_illegal_chars(val, replacement='?')
MsgStream & hex(MsgStream &log)
auto get(const Handle &handle, const Algo &, const EventContext &) -> decltype(details::deref(handle.get()))
EventIDBase max(const EventIDBase &lhs, const EventIDBase &rhs)
def WriteAnnotation(self, key, value)
def __setitem__(self, key, value)
def cmpTreesDicts(reference, to_check, ignore=None)
def RunProgram(self, program, arguments, context, result)
def __processLine__(self, line)
__monitor_thread
This is the interesting part: dump the stack trace to a file.
def __UseSeparateProcessGroupForChild(self)
def CheckTTreesSummaries(self, stdout, result, causes, trees_dict=None, ignore=r"Basket|.*size|Compression")
def WriteResult(self, result)
struct GAUDI_API map
Parametrisation class for map-like implementation.
def convert_xml_illegal_chars(val)
def _parseTTreeSummary(lines, pos)
def __call__(self, stdout, result)
def gen_script(self, shell_type)
def getCmpFailingValues(reference, to_check, fail_path)
def Run(self, context, result)
def _CreateEclipseLaunch(self, prog, args, destdir=None)
def __processLine__(self, line)
Output Validation Classes.
def __processLine__(self, line)
def total_seconds_replacement(timedelta)
def _run_cmt(self, command, args)
def WriteAnnotation(self, key, value)
def __call__(self, input)
def __init__(self, arguments=None, **args)
def __getattr__(self, attr)
def findHistosSummaries(stdout)
def ValidateOutput(self, stdout, stderr, result)
constexpr struct ranges::Gaudi::Functional::details::insert_t insert
def __getitem__(self, key)
def findReferenceBlock(reference, stdout, result, causes, signature_offset=0, signature=None, id=None)
def __processLine__(self, line)
def findTTreeSummaries(stdout)
def __init__(self, path=None)
def __getattr__(self, attr)
def __init__(self, start, end)
decltype(auto) range(Args &&... args)
Zips multiple containers together to form a single range.
def __call__(self, out, result)
def __getattr__(self, attr)
def __call__(self, input)
def WriteResult(self, result)
def ROOT6WorkAroundEnabled(id=None)
def ValidateWithReference(self, stdout, stderr, result, causes, preproc=None)
def __CompareText(self, s1, s2)
def __init__(self, orig=os.environ, keep_same=False)