11 from __future__
import print_function
16 __author__ =
'Marco Clemencic CERN/PH-LBC' 31 from subprocess
import Popen, PIPE, STDOUT
34 from GaudiKernel
import ROOT6WorkAroundEnabled
43 os.environ[
'LC_ALL'] =
'C' 47 import xml.etree.cElementTree
as ET
49 import xml.etree.ElementTree
as ET
55 return timedelta.days * 86400 + timedelta.seconds + timedelta.microseconds / 1000000
59 from qm.test.classes.command
import ExecTestBase
60 from qm.test.result_stream
import ResultStream
67 if sys.platform ==
"win32":
70 from threading
import *
78 from six.moves
import cPickle
90 Class to changes the environment temporarily. 93 def __init__(self, orig=os.environ, keep_same=False):
95 Create a temporary environment on top of the one specified 96 (it can be another TemporaryEnvironment instance). 105 Set an environment variable recording the previous value. 113 self.
env[key] = value
117 Get an environment variable. 118 Needed to provide the same interface as os.environ. 124 Unset an environment variable. 125 Needed to provide the same interface as os.environ. 127 if key
not in self.
env:
134 Return the list of defined environment variables. 135 Needed to provide the same interface as os.environ. 141 Return the list of (name,value) pairs for the defined environment variables. 142 Needed to provide the same interface as os.environ. 149 Needed to provide the same interface as os.environ. 151 return key
in self.
env 155 Revert all the changes done to the original environment. 161 self.
env[key] = value
166 Revert the changes on destruction. 173 Generate a shell script to reproduce the changes in the environment. 175 shells = [
'csh',
'sh',
'bat']
176 if shell_type
not in shells:
177 raise RuntimeError(
"Shell type '%s' unknown. Available: %s" %
178 (shell_type, shells))
181 if key
not in self.
env:
183 if shell_type ==
'csh':
184 out +=
'unsetenv %s\n' % key
185 elif shell_type ==
'sh':
186 out +=
'unset %s\n' % key
187 elif shell_type ==
'bat':
188 out +=
'set %s=\n' % key
191 if shell_type ==
'csh':
192 out +=
'setenv %s "%s"\n' % (key, self.
env[key])
193 elif shell_type ==
'sh':
194 out +=
'export %s="%s"\n' % (key, self.
env[key])
195 elif shell_type ==
'bat':
196 out +=
'set %s=%s\n' % (key, self.
env[key])
201 """Small class for temporary directories. 202 When instantiated, it creates a temporary directory and the instance 203 behaves as the string containing the directory name. 204 When the instance goes out of scope, it removes all the content of 205 the temporary directory (automatic clean-up). 223 shutil.rmtree(self.
name)
226 return getattr(self.
name, attr)
230 """Small class for temporary files. 231 When instantiated, it creates a temporary directory and the instance 232 behaves as the string containing the directory name. 233 When the instance goes out of scope, it removes all the content of 234 the temporary directory (automatic clean-up). 247 self._fd, self.
name = tempfile.mkstemp(suffix, prefix, dir, text)
248 self.
file = os.fdopen(self._fd,
"r+")
260 return getattr(self.
file, attr)
264 """Small wrapper to call CMT. 274 if type(args)
is str:
276 cmd =
"cmt %s" % command
284 result = os.popen4(cmd)[1].
read()
290 return lambda args=[]: self.
_run_cmt(attr, args)
293 """Returns a dictionary containing the runtime environment produced by CMT. 294 If a dictionary is passed a modified instance of it is returned. 298 for l
in self.setup(
"-csh").splitlines():
300 if l.startswith(
"setenv"):
301 dummy, name, value = l.split(
None, 3)
302 env[name] = value.strip(
'"')
303 elif l.startswith(
"unsetenv"):
304 dummy, name = l.split(
None, 2)
310 r = self.show([
"macro", k])
311 if r.find(
"CMT> Error: symbol not found") >= 0:
314 return self.show([
"macro_value", k]).strip()
322 Locates an executable in the executables path ($PATH) and returns the full 323 path to it. An application is looked for with or without the '.exe' suffix. 324 If the executable cannot be found, None is returned 326 if os.path.isabs(executable):
327 if not os.path.exists(executable):
328 if executable.endswith(
'.exe'):
329 if os.path.exists(executable[:-4]):
330 return executable[:-4]
332 for d
in os.environ.get(
"PATH").split(os.pathsep):
333 fullpath = os.path.join(d, executable)
334 if os.path.exists(fullpath):
336 if executable.endswith(
'.exe'):
337 return which(executable[:-4])
342 np = os.path.normpath(os.path.expandvars(p))
343 if os.path.exists(np):
344 p = os.path.realpath(np)
362 _illegal_xml_chars_RE = re.compile(
363 u'[\x00-\x08\x0b\x0c\x0e-\x1F\uD800-\uDFFF\uFFFE\uFFFF]')
367 "Return the hex string " 368 return "".join(
map(hexConvert, match.group()))
372 return hex(ord(char))
376 return _illegal_xml_chars_RE.sub(hexreplace, val)
380 """Filter out characters that are illegal in XML. 381 Looks for any character in val that is not allowed in XML 382 and replaces it with replacement ('?' by default). 385 return _illegal_xml_chars_RE.sub(replacement, val)
394 """Basic implementation of an option validator for Gaudi tests. 395 This implementation is based on the standard (LCG) validation functions 405 """Validate the output of the program. 407 'stdout' -- A string containing the data written to the standard output 410 'stderr' -- A string containing the data written to the standard error 413 'result' -- A 'Result' object. It may be used to annotate 414 the outcome according to the content of stderr. 416 returns -- A list of strings giving causes of failure.""" 421 causes.append(self.
cause)
427 """Compare 's1' and 's2', ignoring line endings. 433 returns -- True if 's1' and 's2' are the same, ignoring 434 differences in line endings.""" 440 to_ignore = re.compile(
441 r'Warning in <TInterpreter::ReadRootmapFile>: .* is already in .*' 445 return not to_ignore.match(l)
447 return filter(keep_line, s1.splitlines()) == filter(
448 keep_line, s2.splitlines())
450 return s1.splitlines() == s2.splitlines()
454 """ Base class for a callable that takes a file and returns a modified 461 if hasattr(input,
"__iter__"):
465 lines = input.splitlines()
473 output =
'\n'.join(output)
502 if line.find(s) >= 0:
517 if self.
start in line:
520 elif self.
end in line:
530 when = re.compile(when)
534 if isinstance(rhs, RegexpReplacer):
536 res._operations = self.
_operations + rhs._operations
538 res = FilePreprocessor.__add__(self, rhs)
543 if w
is None or w.search(line):
544 line = o.sub(r, line)
551 "[0-2]?[0-9]:[0-5][0-9]:[0-5][0-9] [0-9]{4}[-/][01][0-9][-/][0-3][0-9] *(CES?T)?",
552 "00:00:00 1970-01-01")
554 normalizeEOL.__processLine__ =
lambda line: str(line).rstrip() +
'\n' 558 skipEmptyLines.__processLine__ =
lambda line: (line.strip()
and line)
or None 572 line = line[:(pos + self.
siglen)]
573 lst = line[(pos + self.
siglen):].split()
575 line +=
" ".join(lst)
580 normalizeExamples = maskPointers + normalizeDate
583 (
"TIMER.TIMER",
r"\s+[+-]?[0-9]+[0-9.]*",
" 0"),
584 (
"release all pending",
r"^.*/([^/]*:.*)",
r"\1"),
585 (
"0x########",
r"\[.*/([^/]*.*)\]",
r"[\1]"),
586 (
"^#.*file",
r"file '.*[/\\]([^/\\]*)$",
r"file '\1"),
587 (
"^JobOptionsSvc.*options successfully read in from",
588 r"read in from .*[/\\]([^/\\]*)$",
592 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}",
593 "00000000-0000-0000-0000-000000000000"),
595 (
"ServiceLocatorHelper::",
"ServiceLocatorHelper::(create|locate)Service",
596 "ServiceLocatorHelper::service"),
598 (
None,
r"e([-+])0([0-9][0-9])",
r"e\1\2"),
600 (
None,
r'Service reference count check:',
601 r'Looping over all active services...'),
603 (
None,
r"Property(.*)'ErrorCount':",
r"Property\1'ErrorCounter':"),
610 "JobOptionsSvc INFO # ",
611 "JobOptionsSvc WARNING # ",
614 "This machine has a speed",
617 "ToolSvc.Sequenc... INFO",
618 "DataListenerSvc INFO XML written to file:",
621 "DEBUG No writable file catalog found which contains FID:",
623 "DEBUG Service base class initialized successfully",
624 "DEBUG Incident timing:",
626 "INFO 'CnvServices':[",
630 'EventLoopMgr SUCCESS Event Number = ',
631 'EventLoopMgr SUCCESS ---> Loop Finished',
634 r"^JobOptionsSvc INFO *$",
637 r"(Always|SUCCESS)\s*(Root f|[^ ]* F)ile version:",
639 r"0x[0-9a-fA-F#]+ *Algorithm::sysInitialize\(\) *\[",
641 r"0x[0-9a-fA-F#]* *__gxx_personality_v0 *\[",
642 r"File '.*.xml' does not exist",
643 r"INFO Refer to dataset .* by its file ID:",
644 r"INFO Referring to dataset .* by its file ID:",
645 r"INFO Disconnect from dataset",
646 r"INFO Disconnected from dataset",
647 r"INFO Disconnected data IO:",
648 r"IncidentSvc\s*(DEBUG (Adding|Removing)|VERBOSE Calling)",
650 r"^StatusCodeSvc.*listing all unchecked return codes:",
651 r"^StatusCodeSvc\s*INFO\s*$",
652 r"Num\s*\|\s*Function\s*\|\s*Source Library",
655 r"ERROR Failed to modify file: .* Errno=2 No such file or directory",
657 r"^ +[0-9]+ \|.*ROOT",
658 r"^ +[0-9]+ \|.*\|.*Dict",
660 r"StatusCodeSvc.*all StatusCode instances where checked",
662 r"EventLoopMgr.*---> Loop Finished",
666 r"SUCCESS\s*Booked \d+ Histogram\(s\)",
673 r'Warning in <TInterpreter::ReadRootmapFile>: .* is already in .*',
676 normalizeExamples = (lineSkipper + normalizeExamples + skipEmptyLines +
677 normalizeEOL +
LineSorter(
"Services to release : "))
681 def __init__(self, reffile, cause, result_key, preproc=normalizeExamples):
689 if os.path.isfile(self.
reffile):
690 orig = open(self.
reffile).readlines()
696 new = stdout.splitlines()
700 diffs = difflib.ndiff(orig, new, charjunk=difflib.IS_CHARACTER_JUNK)
701 filterdiffs =
map(
lambda x: x.strip(),
702 filter(
lambda x: x[0] !=
" ", diffs))
705 result[self.
result_key] = result.Quote(
"\n".join(filterdiffs))
709 +) standard output of the test""")
710 causes.append(self.
cause)
728 Given a block of text, tries to find it in the output. 729 The block had to be identified by a signature line. By default, the first 730 line is used as signature, or the line pointed to by signature_offset. If 731 signature_offset points outside the block, a signature line can be passed as 732 signature argument. Note: if 'signature' is None (the default), a negative 733 signature_offset is interpreted as index in a list (e.g. -1 means the last 734 line), otherwise the it is interpreted as the number of lines before the 735 first one of the block the signature must appear. 736 The parameter 'id' allow to distinguish between different calls to this 737 function in the same validation code. 740 reflines = filter(
None,
map(
lambda s: s.rstrip(), reference.splitlines()))
742 raise RuntimeError(
"Empty (or null) reference")
744 outlines = filter(
None,
map(
lambda s: s.rstrip(), stdout.splitlines()))
746 res_field =
"GaudiTest.RefBlock" 748 res_field +=
"_%s" % id
750 if signature
is None:
751 if signature_offset < 0:
752 signature_offset = len(reference) + signature_offset
753 signature = reflines[signature_offset]
756 pos = outlines.index(signature)
757 outlines = outlines[pos - signature_offset:pos + len(reflines) -
759 if reflines != outlines:
760 msg =
"standard output" 762 if not msg
in causes:
764 result[res_field +
".observed"] = result.Quote(
"\n".join(outlines))
766 causes.append(
"missing signature")
767 result[res_field +
".signature"] = result.Quote(signature)
768 if len(reflines) > 1
or signature != reflines[0]:
769 result[res_field +
".expected"] = result.Quote(
"\n".join(reflines))
776 Count the number of messages with required severity (by default ERROR and FATAL) 777 and check if their numbers match the expected ones (0 by default). 778 The dictionary "expected" can be used to tune the number of errors and fatals 779 allowed, or to limit the number of expected warnings etc. 781 stdout = kwargs[
"stdout"]
782 result = kwargs[
"result"]
783 causes = kwargs[
"causes"]
790 outlines = stdout.splitlines()
791 from math
import log10
792 fmt =
"%%%dd - %%s" % (int(log10(len(outlines)) + 1))
798 if len(words) >= 2
and words[1]
in errors:
799 errors[words[1]].append(fmt % (linecount, l.rstrip()))
802 if len(errors[e]) != expected[e]:
803 causes.append(
'%s(%d)' % (e, len(errors[e])))
804 result[
"GaudiTest.lines.%s" % e] = result.Quote(
'\n'.join(
806 result[
"GaudiTest.lines.%s.expected#" % e] = result.Quote(
814 Parse the TTree summary table in lines, starting from pos. 815 Returns a tuple with the dictionary with the digested informations and the 816 position of the first line after the summary. 823 return [f.strip()
for f
in l.strip(
"*\n").split(
':', 2)]
827 cols = splitcols(ll[0])
828 r[
"Name"], r[
"Title"] = cols[1:]
830 cols = splitcols(ll[1])
831 r[
"Entries"] = int(cols[1])
833 sizes = cols[2].split()
834 r[
"Total size"] = int(sizes[2])
835 if sizes[-1] ==
"memory":
838 r[
"File size"] = int(sizes[-1])
840 cols = splitcols(ll[2])
841 sizes = cols[2].split()
842 if cols[0] ==
"Baskets":
843 r[
"Baskets"] = int(cols[1])
844 r[
"Basket size"] = int(sizes[2])
845 r[
"Compression"] = float(sizes[-1])
848 if i < (count - 3)
and lines[i].startswith(
"*Tree"):
849 result = parseblock(lines[i:i + 3])
850 result[
"Branches"] = {}
852 while i < (count - 3)
and lines[i].startswith(
"*Br"):
853 if i < (count - 2)
and lines[i].startswith(
"*Branch "):
857 branch = parseblock(lines[i:i + 3])
858 result[
"Branches"][branch[
"Name"]] = branch
866 Scan stdout to find ROOT TTree summaries and digest them. 868 stars = re.compile(
r"^\*+$")
869 outlines = stdout.splitlines()
870 nlines = len(outlines)
876 while i < nlines
and not stars.match(outlines[i]):
881 trees[tree[
"Name"]] = tree
888 Check that all the keys in reference are in to_check too, with the same value. 889 If the value is a dict, the function is called recursively. to_check can 890 contain more keys than reference, that will not be tested. 891 The function returns at the first difference found. 896 ignore_re = re.compile(ignore)
897 keys = [key
for key
in reference
if not ignore_re.match(key)]
899 keys = reference.keys()
903 if (
type(reference[k])
is dict)
and (
type(to_check[k])
is dict):
905 failed = fail_keys =
cmpTreesDicts(reference[k], to_check[k],
909 failed = to_check[k] != reference[k]
914 fail_keys.insert(0, k)
925 if c
is None or r
is None:
927 return (fail_path, r, c)
931 h_count_re = re.compile(
r"^(.*)SUCCESS\s+Booked (\d+) Histogram\(s\) :\s+(.*)")
936 Extract the histograms infos from the lines starting at pos. 937 Returns the position of the first line after the summary block. 940 h_table_head = re.compile(
941 r'SUCCESS\s+(1D|2D|3D|1D profile|2D profile) histograms in directory\s+"(\w*)"' 943 h_short_summ = re.compile(
r"ID=([^\"]+)\s+\"([^\"]+)\"\s+(.*)")
948 m = h_count_re.search(lines[pos])
949 name = m.group(1).strip()
950 total = int(m.group(2))
952 for k, v
in [x.split(
"=")
for x
in m.group(3).split()]:
955 header[
"Total"] = total
959 m = h_table_head.search(lines[pos])
962 t = t.replace(
" profile",
"Prof")
969 if l.startswith(
" | ID"):
971 titles = [x.strip()
for x
in l.split(
"|")][1:]
973 while pos < nlines
and lines[pos].startswith(
" |"):
975 values = [x.strip()
for x
in l.split(
"|")][1:]
977 for i
in range(len(titles)):
978 hcont[titles[i]] = values[i]
979 cont[hcont[
"ID"]] = hcont
981 elif l.startswith(
" ID="):
982 while pos < nlines
and lines[pos].startswith(
" ID="):
985 for x
in h_short_summ.search(lines[pos]).groups()
987 cont[values[0]] = values
991 "Cannot understand line %d: '%s'" % (pos, l))
995 summ[d][
"header"] = header
1000 summ[name] = {
"header": header}
1006 Scan stdout to find ROOT TTree summaries and digest them. 1008 outlines = stdout.splitlines()
1009 nlines = len(outlines) - 1
1017 match = h_count_re.search(outlines[pos])
1018 while pos < nlines
and not match:
1020 match = h_count_re.search(outlines[pos])
1023 summaries.update(summ)
1029 """Create a new 'Filter'. 1031 'input' -- The string containing the input to provide to the 1034 'timeout' -- As for 'TimeoutExecutable.__init__'.""" 1036 super(GaudiFilterExecutable, self).
__init__(input, timeout)
1043 tmpf = tempfile.mkstemp()
1048 """Copied from TimeoutExecutable to allow the re-implementation of 1051 if sys.platform ==
"win32":
1064 """Code copied from both FilterExecutable and TimeoutExecutable. 1067 if self._stdin_pipe:
1068 self._ClosePipeEnd(self._stdin_pipe[0])
1069 if self._stdout_pipe:
1070 self._ClosePipeEnd(self._stdout_pipe[1])
1071 if self._stderr_pipe:
1072 self._ClosePipeEnd(self._stderr_pipe[1])
1080 super(qm.executable.TimeoutExecutable, self).
_HandleChild()
1087 child_pid = self._GetChildPID()
1089 os.setpgid(child_pid, child_pid)
1117 os.setpgid(0, child_pid)
1126 max_fds = os.sysconf(
"SC_OPEN_MAX")
1129 for fd
in range(max_fds):
1140 if sys.platform ==
"linux2":
1143 os.path.join(
"/proc", str(child_pid),
"exe"),
1144 str(child_pid),
"-batch",
"-n",
"-x",
1145 "'%s'" % os.path.join(
1146 os.path.dirname(__file__),
1151 o = os.popen(
" ".join(cmd)).
read()
1156 os.kill(0, signal.SIGKILL)
1159 select.select([], [], [])
1164 elif self.
__timeout >= 0
and sys.platform ==
"win32":
1169 if sys.platform ==
"win32":
1172 """Code copied from FilterExecutable. 1173 Kill the child if the timeout expires. 1175 This function is run in the monitoring thread.""" 1183 result = win32event.WaitForSingleObject(self._GetChildPID(),
1186 if result == win32con.WAIT_TIMEOUT:
1196 """Standard Gaudi test. 1199 qm.fields.TextField(
1203 description=
"""The path to the program. 1205 This field indicates the path to the program. If it is not 1206 an absolute path, the value of the 'PATH' environment 1207 variable will be used to search for the program. 1208 If not specified, $GAUDIEXE or Gaudi.exe are used. 1211 qm.fields.TextField(
1213 title=
"Argument List",
1214 description=
"""The command-line arguments. 1216 If this field is left blank, the program is run without any 1219 Use this field to specify the option files. 1221 An implicit 0th argument (the path to the program) is added 1222 automatically.""")),
1223 qm.fields.TextField(
1226 description=
"""Options to be passed to the application. 1228 This field allows to pass a list of options to the main program 1229 without the need of a separate option file. 1231 The content of the field is written to a temporary file which name 1232 is passed the the application as last argument (appended to the 1233 field "Argument List". 1238 qm.fields.TextField(
1240 title=
"Working Directory",
1241 description=
"""Path to the working directory. 1243 If this field is left blank, the program will be run from the qmtest 1244 directory, otherwise from the directory specified.""",
1246 qm.fields.TextField(
1248 title=
"Reference Output",
1249 description=
"""Path to the file containing the reference output. 1251 If this field is left blank, any standard output will be considered 1254 If the reference file is specified, any output on standard error is 1256 qm.fields.TextField(
1257 name=
"error_reference",
1258 title=
"Reference for standard error",
1260 """Path to the file containing the reference for the standard error. 1262 If this field is left blank, any standard output will be considered 1265 If the reference file is specified, any output on standard error is 1268 qm.fields.TextField(
1269 name=
"unsupported_platforms",
1270 title=
"Unsupported Platforms",
1271 description=
"""Platform on which the test must not be run. 1273 List of regular expressions identifying the platforms on which the 1274 test is not run and the result is set to UNTESTED.""")),
1275 qm.fields.TextField(
1278 description=
"""Function to validate the output of the test. 1280 If defined, the function is used to validate the products of the 1282 The function is called passing as arguments: 1283 self: the test class instance 1284 stdout: the standard output of the executed test 1285 stderr: the standard error of the executed test 1286 result: the Result objects to fill with messages 1287 The function must return a list of causes for the failure. 1288 If specified, overrides standard output, standard error and 1294 qm.fields.BooleanField(
1295 name=
"use_temp_dir",
1296 title=
"Use temporary directory",
1297 description=
"""Use temporary directory. 1299 If set to true, use a temporary directory as working directory. 1301 default_value=
"false"),
1302 qm.fields.IntegerField(
1304 title=
"Expected signal",
1305 description=
"""Expect termination by signal.""",
1306 default_value=
None),
1313 for x
in [str(y).strip()
for y
in self.unsupported_platforms]
if x
1315 for p_re
in unsupported:
1316 if p_re.search(platform):
1317 result.SetOutcome(result.UNTESTED)
1318 result[result.CAUSE] =
'Platform not supported.' 1324 Return the platform Id defined in CMTCONFIG or SCRAM_ARCH. 1328 if "CMTCONFIG" in os.environ:
1329 arch = os.environ[
"CMTCONFIG"]
1330 elif "SCRAM_ARCH" in os.environ:
1331 arch = os.environ[
"SCRAM_ARCH"]
1336 Return True if the current platform is Windows. 1338 This function was needed because of the change in the CMTCONFIG format, 1339 from win32_vc71_dbg to i686-winxp-vc9-dbg. 1342 return "winxp" in platform
or platform.startswith(
"win")
1350 def platformSplit(p):
1351 return set(p.split(
'-' in p
and '-' or '_'))
1353 reference = os.path.normpath(os.path.expandvars(reffile))
1355 spec_ref = reference[:-3] + self.
GetPlatform()[0:3] + reference[-3:]
1356 if os.path.isfile(spec_ref):
1357 reference = spec_ref
1360 dirname, basename = os.path.split(reference)
1363 head = basename +
"." 1364 head_len = len(head)
1366 if 'do0' in platform:
1369 for f
in os.listdir(dirname):
1370 if f.startswith(head):
1371 req_plat = platformSplit(f[head_len:])
1372 if platform.issuperset(req_plat):
1373 candidates.append((len(req_plat), f))
1378 reference = os.path.join(dirname, candidates[-1][1])
1386 ignore=r"Basket|.*size|Compression"):
1388 Compare the TTree summaries in stdout with the ones in trees_dict or in 1389 the reference file. By default ignore the size, compression and basket 1391 The presence of TTree summaries when none is expected is not a failure. 1393 if trees_dict
is None:
1396 if reference
and os.path.isfile(reference):
1401 from pprint
import PrettyPrinter
1402 pp = PrettyPrinter()
1404 result[
"GaudiTest.TTrees.expected"] = result.Quote(
1405 pp.pformat(trees_dict))
1407 result[
"GaudiTest.TTrees.ignore"] = result.Quote(ignore)
1412 causes.append(
"trees summaries")
1415 result[
"GaudiTest.TTrees.failure_on"] = result.Quote(msg)
1416 result[
"GaudiTest.TTrees.found"] = result.Quote(pp.pformat(trees))
1427 Compare the TTree summaries in stdout with the ones in trees_dict or in 1428 the reference file. By default ignore the size, compression and basket 1430 The presence of TTree summaries when none is expected is not a failure. 1435 if reference
and os.path.isfile(reference):
1440 from pprint
import PrettyPrinter
1441 pp = PrettyPrinter()
1443 result[
"GaudiTest.Histos.expected"] = result.Quote(
1446 result[
"GaudiTest.Histos.ignore"] = result.Quote(ignore)
1451 causes.append(
"histos summaries")
1453 result[
"GaudiTest.Histos.failure_on"] = result.Quote(msg)
1454 result[
"GaudiTest.Histos.found"] = result.Quote(pp.pformat(histos))
1465 Default validation action: compare standard output and error to the 1470 preproc = normalizeExamples
1474 if reference
and os.path.isfile(reference):
1475 result[
"GaudiTest.output_reference"] = reference
1479 "GaudiTest.output_diff",
1480 preproc=preproc)(stdout, result)
1488 newref = open(reference +
".new",
"w")
1490 for l
in stdout.splitlines():
1491 newref.write(l.rstrip() +
'\n')
1501 if reference
and os.path.isfile(reference):
1502 result[
"GaudiTest.error_reference"] = reference
1506 "GaudiTest.error_diff",
1507 preproc=preproc)(stderr, result)
1510 newref = open(reference +
".new",
"w")
1512 for l
in stderr.splitlines():
1513 newref.write(l.rstrip() +
'\n')
1517 "ExecTest.expected_stderr")(stderr,
1525 if self.validator.strip() !=
"":
1527 class CallWrapper(object):
1529 Small wrapper class to dynamically bind some default arguments 1533 def __init__(self, callable, extra_args={}):
1537 from inspect
import getargspec
1544 def __call__(self, *args, **kwargs):
1548 kwargs = dict(kwargs)
1552 if a
not in positional
and a
not in kwargs:
1554 return self.
callable(*args, **kwargs)
1557 exported_symbols = {
1568 "findReferenceBlock":
1569 CallWrapper(findReferenceBlock, {
1574 "validateWithReference":
1583 CallWrapper(countErrorLines, {
1588 "checkTTreesSummaries":
1594 "checkHistosSummaries":
1601 exec (self.validator, globals(), exported_symbols)
1609 Add the content of the environment to the result object. 1611 Copied from the QMTest class of COOL. 1613 vars = os.environ.keys()
1615 result[
'GaudiTest.environment'] = \
1617 '\n'.join([
"%s=%s" % (v, os.environ[v])
for v
in vars]))
1619 def Run(self, context, result):
1622 'context' -- A 'Context' giving run-time parameters to the 1625 'result' -- A 'Result' object. The outcome will be 1626 'Result.PASS' when this method is called. The 'result' may be 1627 modified by this method to indicate outcomes other than 1628 'Result.PASS' or to add annotations.""" 1637 elif "GAUDIEXE" in os.environ:
1638 prog = os.environ[
"GAUDIEXE"]
1643 dummy, prog_ext = os.path.splitext(prog)
1644 if prog_ext
not in [
".exe",
".py",
".bat"]
and self.
isWinPlatform():
1648 prog =
which(prog)
or prog
1651 args =
map(rationalizepath, self.args)
1657 if self.options.strip():
1660 r"from\s+Gaudi.Configuration\s+import\s+\*|from\s+Configurables\s+import",
1664 tmpfile.writelines(
"\n".join(self.options.splitlines()))
1666 args.append(tmpfile.name)
1667 result[
"GaudiTest.options"] = result.Quote(self.options)
1670 if prog_ext ==
".py":
1671 args.insert(0, prog)
1673 prog =
which(
"python.exe")
or "python.exe" 1675 prog =
which(
"python")
or "python" 1678 origdir = os.getcwd()
1680 os.chdir(str(os.path.normpath(os.path.expandvars(self.workdir))))
1682 if "QMTEST_TMPDIR" in os.environ:
1683 qmtest_tmpdir = os.environ[
"QMTEST_TMPDIR"]
1684 if not os.path.exists(qmtest_tmpdir):
1685 os.makedirs(qmtest_tmpdir)
1686 os.chdir(qmtest_tmpdir)
1687 elif "qmtest.tmpdir" in context:
1688 os.chdir(context[
"qmtest.tmpdir"])
1690 if "QMTEST_IGNORE_TIMEOUT" not in os.environ:
1698 prog, args, destdir=os.path.join(origdir,
'.eclipse'))
1700 self.
RunProgram(prog, [prog] + args, context, result)
1702 if result.GetOutcome()
not in [result.PASS]:
1709 """Run the 'program'. 1711 'program' -- The path to the program to run. 1713 'arguments' -- A list of the arguments to the program. This 1714 list must contain a first argument corresponding to 'argv[0]'. 1716 'context' -- A 'Context' giving run-time parameters to the 1719 'result' -- A 'Result' object. The outcome will be 1720 'Result.PASS' when this method is called. The 'result' may be 1721 modified by this method to indicate outcomes other than 1722 'Result.PASS' or to add annotations. 1724 @attention: This method has been copied from command.ExecTestBase 1725 (QMTest 2.3.0) and modified to keep stdout and stderr 1726 for tests that have been terminated by a signal. 1727 (Fundamental for debugging in the Application Area) 1731 environment = self.MakeEnvironment(context)
1733 if "slc6" in environment.get(
'CMTCONFIG',
''):
1734 environment[
'TERM'] =
'dumb' 1747 exit_status = e.Run(arguments, environment, path=program)
1749 if e.stack_trace_file
and os.path.exists(e.stack_trace_file):
1750 stack_trace = open(e.stack_trace_file).
read()
1751 os.remove(e.stack_trace_file)
1755 result[
"ExecTest.stack_trace"] = result.Quote(stack_trace)
1758 if (sys.platform ==
"win32" or os.WIFEXITED(exit_status)
1764 if self.exit_code
is None:
1766 elif sys.platform ==
"win32":
1767 exit_code = exit_status
1769 exit_code = os.WEXITSTATUS(exit_status)
1774 result[
"ExecTest.exit_code"] = str(exit_code)
1775 result[
"ExecTest.stdout"] = result.Quote(stdout)
1776 result[
"ExecTest.stderr"] = result.Quote(stderr)
1778 if exit_code != self.exit_code:
1779 causes.append(
"exit_code")
1780 result[
"ExecTest.expected_exit_code"] \
1781 = str(self.exit_code)
1786 result.Fail(
"Unexpected %s." % string.join(causes,
", "))
1787 elif os.WIFSIGNALED(exit_status):
1790 signal_number = str(os.WTERMSIG(exit_status))
1792 result.Fail(
"Program terminated by signal.")
1796 result.Fail(
"Exceeded time limit (%ds), terminated." % timeout)
1797 result[
"ExecTest.signal_number"] = signal_number
1798 result[
"ExecTest.stdout"] = result.Quote(e.stdout)
1799 result[
"ExecTest.stderr"] = result.Quote(e.stderr)
1801 result[
"ExecTest.expected_signal_number"] = str(self.
signal)
1802 elif os.WIFSTOPPED(exit_status):
1805 signal_number = str(os.WSTOPSIG(exit_status))
1807 result.Fail(
"Program stopped by signal.")
1811 result.Fail(
"Exceeded time limit (%ds), stopped." % timeout)
1812 result[
"ExecTest.signal_number"] = signal_number
1813 result[
"ExecTest.stdout"] = result.Quote(e.stdout)
1814 result[
"ExecTest.stderr"] = result.Quote(e.stderr)
1818 result.Fail(
"Program did not terminate normally.")
1824 result[
"ExecTest.stdout"] = result[
"ExecTest.stdout"].replace(
1830 if 'NO_ECLIPSE_LAUNCHERS' in os.environ:
1835 projbasedir = os.path.normpath(destdir)
1836 while not os.path.exists(os.path.join(projbasedir,
".project")):
1837 oldprojdir = projbasedir
1838 projbasedir = os.path.normpath(
1839 os.path.join(projbasedir, os.pardir))
1842 if oldprojdir == projbasedir:
1846 if not os.path.exists(destdir):
1847 os.makedirs(destdir)
1849 from xml.etree
import ElementTree
as ET
1850 t = ET.parse(os.path.join(projbasedir,
".project"))
1851 projectName = t.find(
"name").text
1854 destfile =
"%s.launch" % self._Runnable__id
1856 destfile = os.path.join(destdir, destfile)
1858 if self.options.strip():
1862 tempfile = args.pop()
1863 optsfile = destfile + os.path.splitext(tempfile)[1]
1864 shutil.copyfile(tempfile, optsfile)
1865 args.append(optsfile)
1868 from xml.sax.saxutils
import quoteattr
1872 data[
"environment"] =
"\n".join([
1873 '<mapEntry key=%s value=%s/>' % (quoteattr(k), quoteattr(v))
1874 for k, v
in os.environ.iteritems()
1875 if k
not in (
'MAKEOVERRIDES',
'MAKEFLAGS',
'MAKELEVEL')
1878 data[
"exec"] =
which(prog)
or prog
1879 if os.path.basename(data[
"exec"]).lower().startswith(
"python"):
1881 data[
"stopAtMain"] =
"false" 1883 data[
"stopAtMain"] =
"true" 1885 data[
"args"] =
" ".join(
map(rationalizepath, args))
1887 data[
"args"] =
" ".join(
1888 [
"/debugexe"] +
map(rationalizepath, [data[
"exec"]] + args))
1889 data[
"exec"] =
which(
"vcexpress.exe")
1892 data[
"workdir"] = os.getcwd()
1896 data[
"workdir"] = destdir
1898 data[
"project"] = projectName.strip()
1901 xml_template =
u"""<?xml version="1.0" encoding="UTF-8" standalone="no"?> 1902 <launchConfiguration type="org.eclipse.cdt.launch.applicationLaunchType"> 1903 <booleanAttribute key="org.eclipse.cdt.debug.mi.core.AUTO_SOLIB" value="true"/> 1904 <listAttribute key="org.eclipse.cdt.debug.mi.core.AUTO_SOLIB_LIST"/> 1905 <stringAttribute key="org.eclipse.cdt.debug.mi.core.DEBUG_NAME" value="gdb"/> 1906 <stringAttribute key="org.eclipse.cdt.debug.mi.core.GDB_INIT" value=".gdbinit"/> 1907 <listAttribute key="org.eclipse.cdt.debug.mi.core.SOLIB_PATH"/> 1908 <booleanAttribute key="org.eclipse.cdt.debug.mi.core.STOP_ON_SOLIB_EVENTS" value="false"/> 1909 <booleanAttribute key="org.eclipse.cdt.debug.mi.core.breakpointsFullPath" value="false"/> 1910 <stringAttribute key="org.eclipse.cdt.debug.mi.core.commandFactory" value="org.eclipse.cdt.debug.mi.core.standardCommandFactory"/> 1911 <stringAttribute key="org.eclipse.cdt.debug.mi.core.protocol" value="mi"/> 1912 <booleanAttribute key="org.eclipse.cdt.debug.mi.core.verboseMode" value="false"/> 1913 <intAttribute key="org.eclipse.cdt.launch.ATTR_BUILD_BEFORE_LAUNCH_ATTR" value="0"/> 1914 <stringAttribute key="org.eclipse.cdt.launch.COREFILE_PATH" value=""/> 1915 <stringAttribute key="org.eclipse.cdt.launch.DEBUGGER_ID" value="org.eclipse.cdt.debug.mi.core.CDebuggerNew"/> 1916 <stringAttribute key="org.eclipse.cdt.launch.DEBUGGER_REGISTER_GROUPS" value=""/> 1917 <stringAttribute key="org.eclipse.cdt.launch.DEBUGGER_START_MODE" value="run"/> 1918 <booleanAttribute key="org.eclipse.cdt.launch.DEBUGGER_STOP_AT_MAIN" value="%(stopAtMain)s"/> 1919 <stringAttribute key="org.eclipse.cdt.launch.DEBUGGER_STOP_AT_MAIN_SYMBOL" value="main"/> 1920 <booleanAttribute key="org.eclipse.cdt.launch.ENABLE_REGISTER_BOOKKEEPING" value="false"/> 1921 <booleanAttribute key="org.eclipse.cdt.launch.ENABLE_VARIABLE_BOOKKEEPING" value="false"/> 1922 <stringAttribute key="org.eclipse.cdt.launch.FORMAT" value="<?xml version="1.0" encoding="UTF-8" standalone="no"?><contentList/>"/> 1923 <stringAttribute key="org.eclipse.cdt.launch.GLOBAL_VARIABLES" value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <globalVariableList/> "/> 1924 <stringAttribute key="org.eclipse.cdt.launch.MEMORY_BLOCKS" value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <memoryBlockExpressionList/> "/> 1925 <stringAttribute key="org.eclipse.cdt.launch.PROGRAM_ARGUMENTS" value="%(args)s"/> 1926 <stringAttribute key="org.eclipse.cdt.launch.PROGRAM_NAME" value="%(exec)s"/> 1927 <stringAttribute key="org.eclipse.cdt.launch.PROJECT_ATTR" value="%(project)s"/> 1928 <stringAttribute key="org.eclipse.cdt.launch.PROJECT_BUILD_CONFIG_ID_ATTR" value=""/> 1929 <stringAttribute key="org.eclipse.cdt.launch.WORKING_DIRECTORY" value="%(workdir)s"/> 1930 <booleanAttribute key="org.eclipse.cdt.launch.ui.ApplicationCDebuggerTab.DEFAULTS_SET" value="true"/> 1931 <booleanAttribute key="org.eclipse.cdt.launch.use_terminal" value="true"/> 1932 <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS"> 1933 <listEntry value="/%(project)s"/> 1935 <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES"> 1936 <listEntry value="4"/> 1938 <booleanAttribute key="org.eclipse.debug.core.appendEnvironmentVariables" value="false"/> 1939 <mapAttribute key="org.eclipse.debug.core.environmentVariables"> 1942 <mapAttribute key="org.eclipse.debug.core.preferred_launchers"> 1943 <mapEntry key="[debug]" value="org.eclipse.cdt.cdi.launch.localCLaunch"/> 1945 <listAttribute key="org.eclipse.debug.ui.favoriteGroups"> 1946 <listEntry value="org.eclipse.debug.ui.launchGroup.debug"/> 1948 </launchConfiguration> 1953 data[k] = codecs.decode(data[k],
'utf-8')
1954 xml = xml_template % data
1957 codecs.open(destfile,
"w", encoding=
'utf-8').write(xml)
1959 print(
'WARNING: problem generating Eclipse launcher')
1966 import simplejson
as json
1970 """An 'HTMLResultStream' writes its output to a set of HTML files. 1972 The argument 'dir' is used to select the destination directory for the HTML 1974 The destination directory may already contain the report from a previous run 1975 (for example of a different package), in which case it will be extended to 1976 include the new data. 1979 qm.fields.TextField(
1981 title=
"Destination Directory",
1982 description=
"""The name of the directory. 1984 All results will be written to the directory indicated.""",
1990 """Prepare the destination directory. 1992 Creates the destination directory and store in it some preliminary 1993 annotations and the static files found in the template directory 1996 ResultStream.__init__(self, arguments, **args)
2001 templateDir = os.path.join(os.path.dirname(__file__),
"html_report")
2002 if not os.path.isdir(self.dir):
2003 os.makedirs(self.dir)
2005 for f
in os.listdir(templateDir):
2006 src = os.path.join(templateDir, f)
2007 dst = os.path.join(self.dir, f)
2008 if not os.path.isdir(src)
and not os.path.exists(dst):
2009 shutil.copy(src, dst)
2011 if "CMTCONFIG" in os.environ:
2017 """Helper function to extend the global summary file in the destination 2024 ids = set([i[
"id"]
for i
in self.
_summary])
2025 newSummary = [i
for i
in oldSummary
if i[
"id"]
not in ids]
2027 json.dump(newSummary, open(self.
_summaryFile,
"w"), sort_keys=
True)
2030 """Writes the annotation to the annotation file. 2031 If the key is already present with a different value, the value becomes 2032 a list and the new value is appended to it, except for start_time and 2041 key, value =
map(str, [key, value])
2042 if key ==
"qmtest.run.start_time":
2047 if key
not in annotations:
2048 annotations[key] = value
2049 if "qmtest.run.end_time" in annotations:
2050 del annotations[
"qmtest.run.end_time"]
2053 if key
in annotations:
2054 old = annotations[key]
2055 if type(old)
is list:
2056 if value
not in old:
2057 annotations[key].append(value)
2059 annotations[key] = [old, value]
2061 annotations[key] = value
2067 """Prepare the test result directory in the destination directory storing 2068 into it the result fields. 2069 A summary of the test result is stored both in a file in the test directory 2070 and in the global summary file. 2073 summary[
"id"] = result.GetId()
2074 summary[
"outcome"] = result.GetOutcome()
2075 summary[
"cause"] = result.GetCause()
2076 summary[
"fields"] = result.keys()
2077 summary[
"fields"].sort()
2080 for f
in [
"id",
"outcome",
"cause"]:
2081 summary[f] = str(summary[f])
2082 summary[
"fields"] =
map(str, summary[
"fields"])
2090 testOutDir = os.path.join(self.dir, summary[
"id"])
2091 if not os.path.isdir(testOutDir):
2092 os.makedirs(testOutDir)
2095 open(os.path.join(testOutDir,
"summary.json"),
"w"),
2097 for f
in summary[
"fields"]:
2098 open(os.path.join(testOutDir, f),
"w").write(result[f])
2107 class XMLResultStream(ResultStream):
2108 """An 'XMLResultStream' writes its output to a Ctest XML file. 2110 The argument 'dir' is used to select the destination file for the XML 2112 The destination directory may already contain the report from a previous run 2113 (for example of a different package), in which case it will be overrided to 2117 qm.fields.TextField(
2119 title=
"Destination Directory",
2120 description=
"""The name of the directory. 2122 All results will be written to the directory indicated.""",
2125 qm.fields.TextField(
2127 title=
"Output File Prefix",
2128 description=
"""The output file name will be the specified prefix 2129 followed by 'Test.xml' (CTest convention).""",
2135 """Prepare the destination directory. 2137 Creates the destination directory and store in it some preliminary 2140 ResultStream.__init__(self, arguments, **args)
2142 self.
_xmlFile = os.path.join(self.dir, self.prefix +
'Test.xml')
2148 if not os.path.isfile(self.
_xmlFile):
2150 if not os.path.exists(os.path.dirname(self.
_xmlFile)):
2151 os.makedirs(os.path.dirname(self.
_xmlFile))
2153 newdataset = ET.Element(
"newdataset")
2159 newdataset = self.
_tree.getroot()
2166 for site
in newdataset.getiterator():
2168 if site.get(
"OSPlatform") == os.uname()[4]:
2177 import multiprocessing
2179 "BuildName": os.getenv(
"CMTCONFIG"),
2180 "Name": os.uname()[1],
2181 "Generator":
"QMTest " + qm.version,
2182 "OSName": os.uname()[0],
2183 "Hostname": socket.gethostname(),
2184 "OSRelease": os.uname()[2],
2185 "OSVersion": os.uname()[3],
2186 "OSPlatform": os.uname()[4],
2187 "Is64Bits":
"unknown",
2188 "VendorString":
"unknown",
2189 "VendorID":
"unknown",
2190 "FamilyID":
"unknown",
2191 "ModelID":
"unknown",
2192 "ProcessorCacheSize":
"unknown",
2193 "NumberOfLogicalCPU": str(multiprocessing.cpu_count()),
2194 "NumberOfPhysicalCPU":
"0",
2195 "TotalVirtualMemory":
"0",
2196 "TotalPhysicalMemory":
"0",
2197 "LogicalProcessorsPerPhysical":
"0",
2198 "ProcessorClockFrequency":
"0",
2200 self.
_site = ET.SubElement(newdataset,
"Site", attrib)
2227 # Add some non-QMTest attributes 2228 if "CMTCONFIG" in os.environ: 2229 self.WriteAnnotation("cmt.cmtconfig", os.environ["CMTCONFIG"]) 2231 self.WriteAnnotation("hostname", socket.gethostname()) 2235 if key ==
"qmtest.run.start_time":
2236 if self.
_site.
get(
"qmtest.run.start_time")
is not None:
2238 self.
_site.set(str(key), str(value))
2241 """Prepare the test result directory in the destination directory storing 2242 into it the result fields. 2243 A summary of the test result is stored both in a file in the test directory 2244 and in the global summary file. 2247 summary[
"id"] = result.GetId()
2248 summary[
"outcome"] = result.GetOutcome()
2249 summary[
"cause"] = result.GetCause()
2250 summary[
"fields"] = result.keys()
2251 summary[
"fields"].sort()
2254 for f
in [
"id",
"outcome",
"cause"]:
2255 summary[f] = str(summary[f])
2256 summary[
"fields"] =
map(str, summary[
"fields"])
2261 if "qmtest.start_time" in summary[
"fields"]:
2262 haveStartDate =
True 2264 haveStartDate =
False 2265 if "qmtest.end_time" in summary[
"fields"]:
2273 time.strptime(result[
"qmtest.start_time"],
2274 "%Y-%m-%dT%H:%M:%SZ"))
2277 "%b %d %H:%M %Z", time.localtime(self.
_startTime))
2279 self.
_site.set(
"BuildStamp", result[
"qmtest.start_time"])
2284 time.strptime(result[
"qmtest.end_time"],
"%Y-%m-%dT%H:%M:%SZ"))
2287 tl = ET.Element(
"Test")
2288 tl.text = summary[
"id"]
2292 Test = ET.Element(
"Test")
2293 if summary[
"outcome"] ==
"PASS":
2294 Test.set(
"Status",
"passed")
2295 elif summary[
"outcome"] ==
"FAIL":
2296 Test.set(
"Status",
"failed")
2297 elif summary[
"outcome"] ==
"SKIPPED" or summary[
2298 "outcome"] ==
"UNTESTED":
2299 Test.set(
"Status",
"skipped")
2300 elif summary[
"outcome"] ==
"ERROR":
2301 Test.set(
"Status",
"failed")
2302 Name = ET.SubElement(
2306 Name.text = summary[
"id"]
2307 Results = ET.SubElement(Test,
"Results")
2312 if haveStartDate
and haveEndDate:
2315 testduration = str(delta)
2316 Testduration = ET.SubElement(Results,
"NamedMeasurement")
2317 Testduration.set(
"name",
"Execution Time")
2318 Testduration.set(
"type",
"numeric/float")
2319 value = ET.SubElement(Testduration,
"Value")
2320 value.text = testduration
2323 for n
in (
"qmtest.end_time",
"qmtest.start_time",
"qmtest.cause",
2325 if n
in summary[
"fields"]:
2326 summary[
"fields"].remove(n)
2330 if "ExecTest.exit_code" in summary[
"fields"]:
2331 summary[
"fields"].remove(
"ExecTest.exit_code")
2332 ExitCode = ET.SubElement(Results,
"NamedMeasurement")
2333 ExitCode.set(
"name",
"exit_code")
2334 ExitCode.set(
"type",
"numeric/integer")
2335 value = ET.SubElement(ExitCode,
"Value")
2337 result[
"ExecTest.exit_code"])
2339 TestStartTime = ET.SubElement(Results,
"NamedMeasurement")
2340 TestStartTime.set(
"name",
"Start_Time")
2341 TestStartTime.set(
"type",
"String")
2342 value = ET.SubElement(TestStartTime,
"Value")
2345 time.strftime(
"%b %d %H:%M %Z %Y",
2350 TestEndTime = ET.SubElement(Results,
"NamedMeasurement")
2351 TestEndTime.set(
"name",
"End_Time")
2352 TestEndTime.set(
"type",
"String")
2353 value = ET.SubElement(TestEndTime,
"Value")
2356 time.strftime(
"%b %d %H:%M %Z %Y",
2361 if summary[
"cause"]:
2362 FailureCause = ET.SubElement(Results,
"NamedMeasurement")
2363 FailureCause.set(
"name",
"Cause")
2364 FailureCause.set(
"type",
"String")
2365 value = ET.SubElement(FailureCause,
"Value")
2370 for field
in summary[
"fields"]:
2371 fields[field] = ET.SubElement(Results,
"NamedMeasurement")
2372 fields[field].set(
"type",
"String")
2373 fields[field].set(
"name", field)
2374 value = ET.SubElement(fields[field],
"Value")
2376 if "<pre>" in result[field][0:6]:
2381 if "ExecTest.stdout" in result:
2382 Measurement = ET.SubElement(Results,
"Measurement")
2383 value = ET.SubElement(Measurement,
"Value")
2384 if "<pre>" in result[
"ExecTest.stdout"][0:6]:
2386 result[
"ExecTest.stdout"][5:-6])
2389 result[
"ExecTest.stdout"])
2399 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)