5 __author__ =
'Marco Clemencic CERN/PH-LBC' 20 from subprocess
import Popen, PIPE, STDOUT
23 from GaudiKernel
import ROOT6WorkAroundEnabled
30 os.environ[
'LC_ALL'] =
'C' 34 import xml.etree.cElementTree
as ET
36 import xml.etree.ElementTree
as ET
42 return timedelta.days * 86400 + timedelta.seconds + timedelta.microseconds / 1000000
46 from qm.test.classes.command
import ExecTestBase
47 from qm.test.result_stream
import ResultStream
54 if sys.platform ==
"win32":
57 from threading
import *
77 Class to changes the environment temporarily. 80 def __init__(self, orig=os.environ, keep_same=False):
82 Create a temporary environment on top of the one specified 83 (it can be another TemporaryEnvironment instance). 92 Set an environment variable recording the previous value. 100 self.
env[key] = value
104 Get an environment variable. 105 Needed to provide the same interface as os.environ. 111 Unset an environment variable. 112 Needed to provide the same interface as os.environ. 114 if key
not in self.
env:
121 Return the list of defined environment variables. 122 Needed to provide the same interface as os.environ. 124 return self.env.keys()
128 Return the list of (name,value) pairs for the defined environment variables. 129 Needed to provide the same interface as os.environ. 131 return self.env.items()
136 Needed to provide the same interface as os.environ. 138 return key
in self.
env 142 Revert all the changes done to the original environment. 144 for key, value
in self.old_values.items():
148 self.
env[key] = value
153 Revert the changes on destruction. 160 Generate a shell script to reproduce the changes in the environment. 162 shells = [
'csh',
'sh',
'bat']
163 if shell_type
not in shells:
165 "Shell type '%s' unknown. Available: %s" % (shell_type, shells))
167 for key, value
in self.old_values.items():
168 if key
not in self.
env:
170 if shell_type ==
'csh':
171 out +=
'unsetenv %s\n' % key
172 elif shell_type ==
'sh':
173 out +=
'unset %s\n' % key
174 elif shell_type ==
'bat':
175 out +=
'set %s=\n' % key
178 if shell_type ==
'csh':
179 out +=
'setenv %s "%s"\n' % (key, self.
env[key])
180 elif shell_type ==
'sh':
181 out +=
'export %s="%s"\n' % (key, self.
env[key])
182 elif shell_type ==
'bat':
183 out +=
'set %s=%s\n' % (key, self.
env[key])
188 """Small class for temporary directories. 189 When instantiated, it creates a temporary directory and the instance 190 behaves as the string containing the directory name. 191 When the instance goes out of scope, it removes all the content of 192 the temporary directory (automatic clean-up). 210 shutil.rmtree(self.
name)
213 return getattr(self.
name, attr)
217 """Small class for temporary files. 218 When instantiated, it creates a temporary directory and the instance 219 behaves as the string containing the directory name. 220 When the instance goes out of scope, it removes all the content of 221 the temporary directory (automatic clean-up). 224 def __init__(self, suffix='', prefix='tmp', dir=None, text=False, keep=False):
229 self._fd, self.
name = tempfile.mkstemp(suffix, prefix, dir, text)
230 self.
file = os.fdopen(self._fd,
"r+")
242 return getattr(self.
file, attr)
246 """Small wrapper to call CMT. 256 if type(args)
is str:
258 cmd =
"cmt %s" % command
266 result = os.popen4(cmd)[1].
read()
272 return lambda args=[]: self.
_run_cmt(attr, args)
275 """Returns a dictionary containing the runtime environment produced by CMT. 276 If a dictionary is passed a modified instance of it is returned. 280 for l
in self.setup(
"-csh").splitlines():
282 if l.startswith(
"setenv"):
283 dummy, name, value = l.split(
None, 3)
284 env[name] = value.strip(
'"')
285 elif l.startswith(
"unsetenv"):
286 dummy, name = l.split(
None, 2)
292 r = self.show([
"macro", k])
293 if r.find(
"CMT> Error: symbol not found") >= 0:
296 return self.show([
"macro_value", k]).strip()
304 Locates an executable in the executables path ($PATH) and returns the full 305 path to it. An application is looked for with or without the '.exe' suffix. 306 If the executable cannot be found, None is returned 308 if os.path.isabs(executable):
309 if not os.path.exists(executable):
310 if executable.endswith(
'.exe'):
311 if os.path.exists(executable[:-4]):
312 return executable[:-4]
314 for d
in os.environ.get(
"PATH").split(os.pathsep):
315 fullpath = os.path.join(d, executable)
316 if os.path.exists(fullpath):
318 if executable.endswith(
'.exe'):
319 return which(executable[:-4])
324 np = os.path.normpath(os.path.expandvars(p))
325 if os.path.exists(np):
326 p = os.path.realpath(np)
344 _illegal_xml_chars_RE = re.compile(
345 u'[\x00-\x08\x0b\x0c\x0e-\x1F\uD800-\uDFFF\uFFFE\uFFFF]')
349 "Return the hex string " 350 return "".join(
map(hexConvert, match.group()))
354 return hex(ord(char))
358 return _illegal_xml_chars_RE.sub(hexreplace, val)
362 """Filter out characters that are illegal in XML. 363 Looks for any character in val that is not allowed in XML 364 and replaces it with replacement ('?' by default). 367 return _illegal_xml_chars_RE.sub(replacement, val)
375 """Basic implementation of an option validator for Gaudi tests. 376 This implementation is based on the standard (LCG) validation functions 386 """Validate the output of the program. 388 'stdout' -- A string containing the data written to the standard output 391 'stderr' -- A string containing the data written to the standard error 394 'result' -- A 'Result' object. It may be used to annotate 395 the outcome according to the content of stderr. 397 returns -- A list of strings giving causes of failure.""" 402 causes.append(self.
cause)
408 """Compare 's1' and 's2', ignoring line endings. 414 returns -- True if 's1' and 's2' are the same, ignoring 415 differences in line endings.""" 421 to_ignore = re.compile(
422 r'Warning in <TInterpreter::ReadRootmapFile>: .* is already in .*')
424 def keep_line(l):
return not to_ignore.match(l)
425 return filter(keep_line, s1.splitlines()) == filter(keep_line, s2.splitlines())
427 return s1.splitlines() == s2.splitlines()
431 """ Base class for a callable that takes a file and returns a modified 438 if hasattr(input,
"__iter__"):
442 lines = input.splitlines()
450 output =
'\n'.join(output)
479 if line.find(s) >= 0:
494 if self.
start in line:
497 elif self.
end in line:
507 when = re.compile(when)
511 if isinstance(rhs, RegexpReplacer):
513 res._operations = self.
_operations + rhs._operations
515 res = FilePreprocessor.__add__(self, rhs)
520 if w
is None or w.search(line):
521 line = o.sub(r, line)
527 normalizeDate =
RegexpReplacer(
"[0-2]?[0-9]:[0-5][0-9]:[0-5][0-9] [0-9]{4}[-/][01][0-9][-/][0-3][0-9] *(CES?T)?",
528 "00:00:00 1970-01-01")
530 normalizeEOL.__processLine__ =
lambda line: str(line).rstrip() +
'\n' 534 skipEmptyLines.__processLine__ =
lambda line: (line.strip()
and line)
or None 548 line = line[:(pos + self.
siglen)]
549 lst = line[(pos + self.
siglen):].split()
551 line +=
" ".join(lst)
556 normalizeExamples = maskPointers + normalizeDate
559 (
"TIMER.TIMER",
r"\s+[+-]?[0-9]+[0-9.]*",
" 0"),
560 (
"release all pending",
r"^.*/([^/]*:.*)",
r"\1"),
561 (
"0x########",
r"\[.*/([^/]*.*)\]",
r"[\1]"),
562 (
"^#.*file",
r"file '.*[/\\]([^/\\]*)$",
r"file '\1"),
563 (
"^JobOptionsSvc.*options successfully read in from",
564 r"read in from .*[/\\]([^/\\]*)$",
r"file \1"),
566 (
None,
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}",
567 "00000000-0000-0000-0000-000000000000"),
569 (
"ServiceLocatorHelper::",
"ServiceLocatorHelper::(create|locate)Service",
570 "ServiceLocatorHelper::service"),
572 (
None,
r"e([-+])0([0-9][0-9])",
r"e\1\2"),
574 (
None,
r'Service reference count check:',
575 r'Looping over all active services...'),
577 (
None,
r"Property(.*)'ErrorCount':",
r"Property\1'ErrorCounter':"),
582 "JobOptionsSvc INFO # ",
583 "JobOptionsSvc WARNING # ",
586 "This machine has a speed",
589 "ToolSvc.Sequenc... INFO",
590 "DataListenerSvc INFO XML written to file:",
591 "[INFO]",
"[WARNING]",
592 "DEBUG No writable file catalog found which contains FID:",
594 "DEBUG Service base class initialized successfully",
595 "DEBUG Incident timing:",
597 "INFO 'CnvServices':[",
601 'EventLoopMgr SUCCESS Event Number = ',
602 'EventLoopMgr SUCCESS ---> Loop Finished',
604 r"^JobOptionsSvc INFO *$",
607 r"(Always|SUCCESS)\s*(Root f|[^ ]* F)ile version:",
609 r"0x[0-9a-fA-F#]+ *Algorithm::sysInitialize\(\) *\[",
611 r"0x[0-9a-fA-F#]* *__gxx_personality_v0 *\[",
612 r"File '.*.xml' does not exist",
613 r"INFO Refer to dataset .* by its file ID:",
614 r"INFO Referring to dataset .* by its file ID:",
615 r"INFO Disconnect from dataset",
616 r"INFO Disconnected from dataset",
617 r"INFO Disconnected data IO:",
618 r"IncidentSvc\s*(DEBUG (Adding|Removing)|VERBOSE Calling)",
620 r"^StatusCodeSvc.*listing all unchecked return codes:",
621 r"^StatusCodeSvc\s*INFO\s*$",
622 r"Num\s*\|\s*Function\s*\|\s*Source Library",
625 r"ERROR Failed to modify file: .* Errno=2 No such file or directory",
627 r"^ +[0-9]+ \|.*ROOT",
628 r"^ +[0-9]+ \|.*\|.*Dict",
630 r"StatusCodeSvc.*all StatusCode instances where checked",
632 r"EventLoopMgr.*---> Loop Finished",
636 r"SUCCESS\s*Booked \d+ Histogram\(s\)",
643 r'Warning in <TInterpreter::ReadRootmapFile>: .* is already in .*',
646 normalizeExamples = (lineSkipper + normalizeExamples + skipEmptyLines +
647 normalizeEOL +
LineSorter(
"Services to release : "))
651 def __init__(self, reffile, cause, result_key, preproc=normalizeExamples):
659 if os.path.isfile(self.
reffile):
660 orig = open(self.
reffile).xreadlines()
666 new = stdout.splitlines()
670 diffs = difflib.ndiff(orig, new, charjunk=difflib.IS_CHARACTER_JUNK)
671 filterdiffs =
map(
lambda x: x.strip(), filter(
672 lambda x: x[0] !=
" ", diffs))
675 result[self.
result_key] = result.Quote(
"\n".join(filterdiffs))
679 +) standard output of the test""")
680 causes.append(self.
cause)
689 def findReferenceBlock(reference, stdout, result, causes, signature_offset=0, signature=None,
692 Given a block of text, tries to find it in the output. 693 The block had to be identified by a signature line. By default, the first 694 line is used as signature, or the line pointed to by signature_offset. If 695 signature_offset points outside the block, a signature line can be passed as 696 signature argument. Note: if 'signature' is None (the default), a negative 697 signature_offset is interpreted as index in a list (e.g. -1 means the last 698 line), otherwise the it is interpreted as the number of lines before the 699 first one of the block the signature must appear. 700 The parameter 'id' allow to distinguish between different calls to this 701 function in the same validation code. 704 reflines = filter(
None,
map(
lambda s: s.rstrip(), reference.splitlines()))
706 raise RuntimeError(
"Empty (or null) reference")
708 outlines = filter(
None,
map(
lambda s: s.rstrip(), stdout.splitlines()))
710 res_field =
"GaudiTest.RefBlock" 712 res_field +=
"_%s" % id
714 if signature
is None:
715 if signature_offset < 0:
716 signature_offset = len(reference) + signature_offset
717 signature = reflines[signature_offset]
720 pos = outlines.index(signature)
721 outlines = outlines[pos - signature_offset:pos +
722 len(reflines) - signature_offset]
723 if reflines != outlines:
724 msg =
"standard output" 726 if not msg
in causes:
728 result[res_field +
".observed"] = result.Quote(
"\n".join(outlines))
730 causes.append(
"missing signature")
731 result[res_field +
".signature"] = result.Quote(signature)
732 if len(reflines) > 1
or signature != reflines[0]:
733 result[res_field +
".expected"] = result.Quote(
"\n".join(reflines))
740 Count the number of messages with required severity (by default ERROR and FATAL) 741 and check if their numbers match the expected ones (0 by default). 742 The dictionary "expected" can be used to tune the number of errors and fatals 743 allowed, or to limit the number of expected warnings etc. 745 stdout = kwargs[
"stdout"]
746 result = kwargs[
"result"]
747 causes = kwargs[
"causes"]
754 outlines = stdout.splitlines()
755 from math
import log10
756 fmt =
"%%%dd - %%s" % (int(log10(len(outlines)) + 1))
762 if len(words) >= 2
and words[1]
in errors:
763 errors[words[1]].append(fmt % (linecount, l.rstrip()))
766 if len(errors[e]) != expected[e]:
767 causes.append(
'%s(%d)' % (e, len(errors[e])))
768 result[
"GaudiTest.lines.%s" %
769 e] = result.Quote(
'\n'.join(errors[e]))
770 result[
"GaudiTest.lines.%s.expected#" %
771 e] = result.Quote(str(expected[e]))
778 Parse the TTree summary table in lines, starting from pos. 779 Returns a tuple with the dictionary with the digested informations and the 780 position of the first line after the summary. 786 def splitcols(l):
return [f.strip()
for f
in l.strip(
"*\n").split(
':', 2)]
790 cols = splitcols(ll[0])
791 r[
"Name"], r[
"Title"] = cols[1:]
793 cols = splitcols(ll[1])
794 r[
"Entries"] = int(cols[1])
796 sizes = cols[2].split()
797 r[
"Total size"] = int(sizes[2])
798 if sizes[-1] ==
"memory":
801 r[
"File size"] = int(sizes[-1])
803 cols = splitcols(ll[2])
804 sizes = cols[2].split()
805 if cols[0] ==
"Baskets":
806 r[
"Baskets"] = int(cols[1])
807 r[
"Basket size"] = int(sizes[2])
808 r[
"Compression"] = float(sizes[-1])
811 if i < (count - 3)
and lines[i].startswith(
"*Tree"):
812 result = parseblock(lines[i:i + 3])
813 result[
"Branches"] = {}
815 while i < (count - 3)
and lines[i].startswith(
"*Br"):
816 if i < (count - 2)
and lines[i].startswith(
"*Branch "):
820 branch = parseblock(lines[i:i + 3])
821 result[
"Branches"][branch[
"Name"]] = branch
829 Scan stdout to find ROOT TTree summaries and digest them. 831 stars = re.compile(
r"^\*+$")
832 outlines = stdout.splitlines()
833 nlines = len(outlines)
839 while i < nlines
and not stars.match(outlines[i]):
844 trees[tree[
"Name"]] = tree
851 Check that all the keys in reference are in to_check too, with the same value. 852 If the value is a dict, the function is called recursively. to_check can 853 contain more keys than reference, that will not be tested. 854 The function returns at the first difference found. 859 ignore_re = re.compile(ignore)
860 keys = [key
for key
in reference
if not ignore_re.match(key)]
862 keys = reference.keys()
866 if (
type(reference[k])
is dict)
and (
type(to_check[k])
is dict):
869 reference[k], to_check[k], ignore)
872 failed = to_check[k] != reference[k]
877 fail_keys.insert(0, k)
888 if c
is None or r
is None:
890 return (fail_path, r, c)
894 h_count_re = re.compile(
r"^(.*)SUCCESS\s+Booked (\d+) Histogram\(s\) :\s+(.*)")
899 Extract the histograms infos from the lines starting at pos. 900 Returns the position of the first line after the summary block. 903 h_table_head = re.compile(
904 r'SUCCESS\s+List of booked (1D|2D|3D|1D profile|2D profile) histograms in directory\s+"(\w*)"')
905 h_short_summ = re.compile(
r"ID=([^\"]+)\s+\"([^\"]+)\"\s+(.*)")
910 m = h_count_re.search(lines[pos])
911 name = m.group(1).strip()
912 total = int(m.group(2))
914 for k, v
in [x.split(
"=")
for x
in m.group(3).split()]:
917 header[
"Total"] = total
921 m = h_table_head.search(lines[pos])
924 t = t.replace(
" profile",
"Prof")
931 if l.startswith(
" | ID"):
933 titles = [x.strip()
for x
in l.split(
"|")][1:]
935 while pos < nlines
and lines[pos].startswith(
" |"):
937 values = [x.strip()
for x
in l.split(
"|")][1:]
939 for i
in range(len(titles)):
940 hcont[titles[i]] = values[i]
941 cont[hcont[
"ID"]] = hcont
943 elif l.startswith(
" ID="):
944 while pos < nlines
and lines[pos].startswith(
" ID="):
946 for x
in h_short_summ.search(lines[pos]).groups()]
947 cont[values[0]] = values
951 "Cannot understand line %d: '%s'" % (pos, l))
955 summ[d][
"header"] = header
960 summ[name] = {
"header": header}
966 Scan stdout to find ROOT TTree summaries and digest them. 968 outlines = stdout.splitlines()
969 nlines = len(outlines) - 1
977 match = h_count_re.search(outlines[pos])
978 while pos < nlines
and not match:
980 match = h_count_re.search(outlines[pos])
983 summaries.update(summ)
989 """Create a new 'Filter'. 991 'input' -- The string containing the input to provide to the 994 'timeout' -- As for 'TimeoutExecutable.__init__'.""" 996 super(GaudiFilterExecutable, self).
__init__(input, timeout)
1003 tmpf = tempfile.mkstemp()
1008 """Copied from TimeoutExecutable to allow the re-implementation of 1011 if sys.platform ==
"win32":
1023 """Code copied from both FilterExecutable and TimeoutExecutable. 1026 if self._stdin_pipe:
1027 self._ClosePipeEnd(self._stdin_pipe[0])
1028 if self._stdout_pipe:
1029 self._ClosePipeEnd(self._stdout_pipe[1])
1030 if self._stderr_pipe:
1031 self._ClosePipeEnd(self._stderr_pipe[1])
1039 super(qm.executable.TimeoutExecutable, self).
_HandleChild()
1046 child_pid = self._GetChildPID()
1048 os.setpgid(child_pid, child_pid)
1076 os.setpgid(0, child_pid)
1085 max_fds = os.sysconf(
"SC_OPEN_MAX")
1088 for fd
in xrange(max_fds):
1099 if sys.platform ==
"linux2":
1102 "/proc", str(child_pid),
"exe"),
1104 "-batch",
"-n",
"-x",
1105 "'%s'" % os.path.join(os.path.dirname(__file__),
"stack-trace.gdb")]
1108 o = os.popen(
" ".join(cmd)).
read()
1113 os.kill(0, signal.SIGKILL)
1116 select.select([], [], [])
1121 elif self.
__timeout >= 0
and sys.platform ==
"win32":
1124 self.__monitor_thread.start()
1126 if sys.platform ==
"win32":
1129 """Code copied from FilterExecutable. 1130 Kill the child if the timeout expires. 1132 This function is run in the monitoring thread.""" 1140 result = win32event.WaitForSingleObject(self._GetChildPID(),
1143 if result == win32con.WAIT_TIMEOUT:
1152 """Standard Gaudi test. 1155 qm.fields.TextField(
1159 description=
"""The path to the program. 1161 This field indicates the path to the program. If it is not 1162 an absolute path, the value of the 'PATH' environment 1163 variable will be used to search for the program. 1164 If not specified, $GAUDIEXE or Gaudi.exe are used. 1167 qm.fields.SetField(qm.fields.TextField(
1169 title=
"Argument List",
1170 description=
"""The command-line arguments. 1172 If this field is left blank, the program is run without any 1175 Use this field to specify the option files. 1177 An implicit 0th argument (the path to the program) is added 1180 qm.fields.TextField(
1183 description=
"""Options to be passed to the application. 1185 This field allows to pass a list of options to the main program 1186 without the need of a separate option file. 1188 The content of the field is written to a temporary file which name 1189 is passed the the application as last argument (appended to the 1190 field "Argument List". 1196 qm.fields.TextField(
1198 title=
"Working Directory",
1199 description=
"""Path to the working directory. 1201 If this field is left blank, the program will be run from the qmtest 1202 directory, otherwise from the directory specified.""",
1205 qm.fields.TextField(
1207 title=
"Reference Output",
1208 description=
"""Path to the file containing the reference output. 1210 If this field is left blank, any standard output will be considered 1213 If the reference file is specified, any output on standard error is 1216 qm.fields.TextField(
1217 name=
"error_reference",
1218 title=
"Reference for standard error",
1219 description=
"""Path to the file containing the reference for the standard error. 1221 If this field is left blank, any standard output will be considered 1224 If the reference file is specified, any output on standard error is 1227 qm.fields.SetField(qm.fields.TextField(
1228 name=
"unsupported_platforms",
1229 title=
"Unsupported Platforms",
1230 description=
"""Platform on which the test must not be run. 1232 List of regular expressions identifying the platforms on which the 1233 test is not run and the result is set to UNTESTED.""" 1236 qm.fields.TextField(
1239 description=
"""Function to validate the output of the test. 1241 If defined, the function is used to validate the products of the 1243 The function is called passing as arguments: 1244 self: the test class instance 1245 stdout: the standard output of the executed test 1246 stderr: the standard error of the executed test 1247 result: the Result objects to fill with messages 1248 The function must return a list of causes for the failure. 1249 If specified, overrides standard output, standard error and 1257 qm.fields.BooleanField(
1258 name=
"use_temp_dir",
1259 title=
"Use temporary directory",
1260 description=
"""Use temporary directory. 1262 If set to true, use a temporary directory as working directory. 1264 default_value=
"false" 1267 qm.fields.IntegerField(
1269 title=
"Expected signal",
1270 description=
"""Expect termination by signal.""",
1277 unsupported = [re.compile(x)
1278 for x
in [str(y).strip()
1279 for y
in self.unsupported_platforms]
1282 for p_re
in unsupported:
1283 if p_re.search(platform):
1284 result.SetOutcome(result.UNTESTED)
1285 result[result.CAUSE] =
'Platform not supported.' 1291 Return the platform Id defined in CMTCONFIG or SCRAM_ARCH. 1295 if "CMTCONFIG" in os.environ:
1296 arch = os.environ[
"CMTCONFIG"]
1297 elif "SCRAM_ARCH" in os.environ:
1298 arch = os.environ[
"SCRAM_ARCH"]
1303 Return True if the current platform is Windows. 1305 This function was needed because of the change in the CMTCONFIG format, 1306 from win32_vc71_dbg to i686-winxp-vc9-dbg. 1309 return "winxp" in platform
or platform.startswith(
"win")
1317 def platformSplit(p):
return set(p.split(
'-' in p
and '-' or '_'))
1319 reference = os.path.normpath(os.path.expandvars(reffile))
1321 spec_ref = reference[:-3] + self.
GetPlatform()[0:3] + reference[-3:]
1322 if os.path.isfile(spec_ref):
1323 reference = spec_ref
1326 dirname, basename = os.path.split(reference)
1329 head = basename +
"." 1330 head_len = len(head)
1332 if 'do0' in platform:
1335 for f
in os.listdir(dirname):
1336 if f.startswith(head):
1337 req_plat = platformSplit(f[head_len:])
1338 if platform.issuperset(req_plat):
1339 candidates.append((len(req_plat), f))
1344 reference = os.path.join(dirname, candidates[-1][1])
1349 ignore=
r"Basket|.*size|Compression"):
1351 Compare the TTree summaries in stdout with the ones in trees_dict or in 1352 the reference file. By default ignore the size, compression and basket 1354 The presence of TTree summaries when none is expected is not a failure. 1356 if trees_dict
is None:
1359 if reference
and os.path.isfile(reference):
1364 from pprint
import PrettyPrinter
1365 pp = PrettyPrinter()
1367 result[
"GaudiTest.TTrees.expected"] = result.Quote(
1368 pp.pformat(trees_dict))
1370 result[
"GaudiTest.TTrees.ignore"] = result.Quote(ignore)
1375 causes.append(
"trees summaries")
1377 trees_dict, trees, failed)
1378 result[
"GaudiTest.TTrees.failure_on"] = result.Quote(msg)
1379 result[
"GaudiTest.TTrees.found"] = result.Quote(pp.pformat(trees))
1387 Compare the TTree summaries in stdout with the ones in trees_dict or in 1388 the reference file. By default ignore the size, compression and basket 1390 The presence of TTree summaries when none is expected is not a failure. 1395 if reference
and os.path.isfile(reference):
1400 from pprint
import PrettyPrinter
1401 pp = PrettyPrinter()
1403 result[
"GaudiTest.Histos.expected"] = result.Quote(
1406 result[
"GaudiTest.Histos.ignore"] = result.Quote(ignore)
1411 causes.append(
"histos summaries")
1413 result[
"GaudiTest.Histos.failure_on"] = result.Quote(msg)
1414 result[
"GaudiTest.Histos.found"] = result.Quote(pp.pformat(histos))
1420 Default validation action: compare standard output and error to the 1425 preproc = normalizeExamples
1429 if reference
and os.path.isfile(reference):
1430 result[
"GaudiTest.output_reference"] = reference
1433 "GaudiTest.output_diff",
1434 preproc=preproc)(stdout, result)
1442 newref = open(reference +
".new",
"w")
1444 for l
in stdout.splitlines():
1445 newref.write(l.rstrip() +
'\n')
1455 if reference
and os.path.isfile(reference):
1456 result[
"GaudiTest.error_reference"] = reference
1459 "GaudiTest.error_diff",
1460 preproc=preproc)(stderr, result)
1463 newref = open(reference +
".new",
"w")
1465 for l
in stderr.splitlines():
1466 newref.write(l.rstrip() +
'\n')
1471 "ExecTest.expected_stderr")(stderr, result)
1478 if self.validator.strip() !=
"":
1479 class CallWrapper(object):
1481 Small wrapper class to dynamically bind some default arguments 1485 def __init__(self, callable, extra_args={}):
1489 from inspect
import getargspec
1496 def __call__(self, *args, **kwargs):
1500 kwargs = dict(kwargs)
1504 if a
not in positional
and a
not in kwargs:
1508 exported_symbols = {
"self": self,
1513 "findReferenceBlock":
1514 CallWrapper(findReferenceBlock, {
"stdout": stdout,
1517 "validateWithReference":
1523 CallWrapper(countErrorLines, {
"stdout": stdout,
1526 "checkTTreesSummaries":
1530 "checkHistosSummaries":
1536 exec self.validator
in globals(), exported_symbols
1544 Add the content of the environment to the result object. 1546 Copied from the QMTest class of COOL. 1548 vars = os.environ.keys()
1550 result[
'GaudiTest.environment'] = \
1552 '\n'.join([
"%s=%s" % (v, os.environ[v])
for v
in vars]))
1554 def Run(self, context, result):
1557 'context' -- A 'Context' giving run-time parameters to the 1560 'result' -- A 'Result' object. The outcome will be 1561 'Result.PASS' when this method is called. The 'result' may be 1562 modified by this method to indicate outcomes other than 1563 'Result.PASS' or to add annotations.""" 1572 elif "GAUDIEXE" in os.environ:
1573 prog = os.environ[
"GAUDIEXE"]
1578 dummy, prog_ext = os.path.splitext(prog)
1579 if prog_ext
not in [
".exe",
".py",
".bat"]
and self.
isWinPlatform():
1583 prog =
which(prog)
or prog
1586 args =
map(rationalizepath, self.args)
1592 if self.options.strip():
1594 if re.search(
r"from\s+Gaudi.Configuration\s+import\s+\*|from\s+Configurables\s+import", self.options):
1597 tmpfile.writelines(
"\n".join(self.options.splitlines()))
1599 args.append(tmpfile.name)
1600 result[
"GaudiTest.options"] = result.Quote(self.options)
1603 if prog_ext ==
".py":
1604 args.insert(0, prog)
1606 prog =
which(
"python.exe")
or "python.exe" 1608 prog =
which(
"python")
or "python" 1611 origdir = os.getcwd()
1613 os.chdir(str(os.path.normpath(os.path.expandvars(self.workdir))))
1615 if "QMTEST_TMPDIR" in os.environ:
1616 qmtest_tmpdir = os.environ[
"QMTEST_TMPDIR"]
1617 if not os.path.exists(qmtest_tmpdir):
1618 os.makedirs(qmtest_tmpdir)
1619 os.chdir(qmtest_tmpdir)
1620 elif "qmtest.tmpdir" in context:
1621 os.chdir(context[
"qmtest.tmpdir"])
1623 if "QMTEST_IGNORE_TIMEOUT" not in os.environ:
1631 prog, args, destdir=os.path.join(origdir,
'.eclipse'))
1637 if result.GetOutcome()
not in [result.PASS]:
1644 """Run the 'program'. 1646 'program' -- The path to the program to run. 1648 'arguments' -- A list of the arguments to the program. This 1649 list must contain a first argument corresponding to 'argv[0]'. 1651 'context' -- A 'Context' giving run-time parameters to the 1654 'result' -- A 'Result' object. The outcome will be 1655 'Result.PASS' when this method is called. The 'result' may be 1656 modified by this method to indicate outcomes other than 1657 'Result.PASS' or to add annotations. 1659 @attention: This method has been copied from command.ExecTestBase 1660 (QMTest 2.3.0) and modified to keep stdout and stderr 1661 for tests that have been terminated by a signal. 1662 (Fundamental for debugging in the Application Area) 1666 environment = self.MakeEnvironment(context)
1668 if "slc6" in environment.get(
'CMTCONFIG',
''):
1669 environment[
'TERM'] =
'dumb' 1682 exit_status = e.Run(arguments, environment, path=program)
1684 if e.stack_trace_file
and os.path.exists(e.stack_trace_file):
1685 stack_trace = open(e.stack_trace_file).
read()
1686 os.remove(e.stack_trace_file)
1690 result[
"ExecTest.stack_trace"] = result.Quote(stack_trace)
1693 if (sys.platform ==
"win32" or os.WIFEXITED(exit_status)
1699 if self.exit_code
is None:
1701 elif sys.platform ==
"win32":
1702 exit_code = exit_status
1704 exit_code = os.WEXITSTATUS(exit_status)
1709 result[
"ExecTest.exit_code"] = str(exit_code)
1710 result[
"ExecTest.stdout"] = result.Quote(stdout)
1711 result[
"ExecTest.stderr"] = result.Quote(stderr)
1713 if exit_code != self.exit_code:
1714 causes.append(
"exit_code")
1715 result[
"ExecTest.expected_exit_code"] \
1716 = str(self.exit_code)
1721 result.Fail(
"Unexpected %s." % string.join(causes,
", "))
1722 elif os.WIFSIGNALED(exit_status):
1725 signal_number = str(os.WTERMSIG(exit_status))
1727 result.Fail(
"Program terminated by signal.")
1731 result.Fail(
"Exceeded time limit (%ds), terminated." % timeout)
1732 result[
"ExecTest.signal_number"] = signal_number
1733 result[
"ExecTest.stdout"] = result.Quote(e.stdout)
1734 result[
"ExecTest.stderr"] = result.Quote(e.stderr)
1736 result[
"ExecTest.expected_signal_number"] = str(self.
signal)
1737 elif os.WIFSTOPPED(exit_status):
1740 signal_number = str(os.WSTOPSIG(exit_status))
1742 result.Fail(
"Program stopped by signal.")
1746 result.Fail(
"Exceeded time limit (%ds), stopped." % timeout)
1747 result[
"ExecTest.signal_number"] = signal_number
1748 result[
"ExecTest.stdout"] = result.Quote(e.stdout)
1749 result[
"ExecTest.stderr"] = result.Quote(e.stderr)
1753 result.Fail(
"Program did not terminate normally.")
1759 result[
"ExecTest.stdout"] = result[
"ExecTest.stdout"].replace(
1765 if 'NO_ECLIPSE_LAUNCHERS' in os.environ:
1770 projbasedir = os.path.normpath(destdir)
1771 while not os.path.exists(os.path.join(projbasedir,
".project")):
1772 oldprojdir = projbasedir
1773 projbasedir = os.path.normpath(
1774 os.path.join(projbasedir, os.pardir))
1777 if oldprojdir == projbasedir:
1781 if not os.path.exists(destdir):
1782 os.makedirs(destdir)
1784 from xml.etree
import ElementTree
as ET
1785 t = ET.parse(os.path.join(projbasedir,
".project"))
1786 projectName = t.find(
"name").text
1789 destfile =
"%s.launch" % self._Runnable__id
1791 destfile = os.path.join(destdir, destfile)
1793 if self.options.strip():
1797 tempfile = args.pop()
1798 optsfile = destfile + os.path.splitext(tempfile)[1]
1799 shutil.copyfile(tempfile, optsfile)
1800 args.append(optsfile)
1803 from xml.sax.saxutils
import quoteattr
1807 data[
"environment"] =
"\n".join([
'<mapEntry key=%s value=%s/>' % (quoteattr(k), quoteattr(v))
1808 for k, v
in os.environ.iteritems()
1809 if k
not in (
'MAKEOVERRIDES',
'MAKEFLAGS',
'MAKELEVEL')])
1811 data[
"exec"] =
which(prog)
or prog
1812 if os.path.basename(data[
"exec"]).lower().startswith(
"python"):
1814 data[
"stopAtMain"] =
"false" 1816 data[
"stopAtMain"] =
"true" 1818 data[
"args"] =
" ".join(
map(rationalizepath, args))
1820 data[
"args"] =
" ".join(
1821 [
"/debugexe"] +
map(rationalizepath, [data[
"exec"]] + args))
1822 data[
"exec"] =
which(
"vcexpress.exe")
1825 data[
"workdir"] = os.getcwd()
1829 data[
"workdir"] = destdir
1831 data[
"project"] = projectName.strip()
1834 xml_template =
u"""<?xml version="1.0" encoding="UTF-8" standalone="no"?> 1835 <launchConfiguration type="org.eclipse.cdt.launch.applicationLaunchType"> 1836 <booleanAttribute key="org.eclipse.cdt.debug.mi.core.AUTO_SOLIB" value="true"/> 1837 <listAttribute key="org.eclipse.cdt.debug.mi.core.AUTO_SOLIB_LIST"/> 1838 <stringAttribute key="org.eclipse.cdt.debug.mi.core.DEBUG_NAME" value="gdb"/> 1839 <stringAttribute key="org.eclipse.cdt.debug.mi.core.GDB_INIT" value=".gdbinit"/> 1840 <listAttribute key="org.eclipse.cdt.debug.mi.core.SOLIB_PATH"/> 1841 <booleanAttribute key="org.eclipse.cdt.debug.mi.core.STOP_ON_SOLIB_EVENTS" value="false"/> 1842 <booleanAttribute key="org.eclipse.cdt.debug.mi.core.breakpointsFullPath" value="false"/> 1843 <stringAttribute key="org.eclipse.cdt.debug.mi.core.commandFactory" value="org.eclipse.cdt.debug.mi.core.standardCommandFactory"/> 1844 <stringAttribute key="org.eclipse.cdt.debug.mi.core.protocol" value="mi"/> 1845 <booleanAttribute key="org.eclipse.cdt.debug.mi.core.verboseMode" value="false"/> 1846 <intAttribute key="org.eclipse.cdt.launch.ATTR_BUILD_BEFORE_LAUNCH_ATTR" value="0"/> 1847 <stringAttribute key="org.eclipse.cdt.launch.COREFILE_PATH" value=""/> 1848 <stringAttribute key="org.eclipse.cdt.launch.DEBUGGER_ID" value="org.eclipse.cdt.debug.mi.core.CDebuggerNew"/> 1849 <stringAttribute key="org.eclipse.cdt.launch.DEBUGGER_REGISTER_GROUPS" value=""/> 1850 <stringAttribute key="org.eclipse.cdt.launch.DEBUGGER_START_MODE" value="run"/> 1851 <booleanAttribute key="org.eclipse.cdt.launch.DEBUGGER_STOP_AT_MAIN" value="%(stopAtMain)s"/> 1852 <stringAttribute key="org.eclipse.cdt.launch.DEBUGGER_STOP_AT_MAIN_SYMBOL" value="main"/> 1853 <booleanAttribute key="org.eclipse.cdt.launch.ENABLE_REGISTER_BOOKKEEPING" value="false"/> 1854 <booleanAttribute key="org.eclipse.cdt.launch.ENABLE_VARIABLE_BOOKKEEPING" value="false"/> 1855 <stringAttribute key="org.eclipse.cdt.launch.FORMAT" value="<?xml version="1.0" encoding="UTF-8" standalone="no"?><contentList/>"/> 1856 <stringAttribute key="org.eclipse.cdt.launch.GLOBAL_VARIABLES" value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <globalVariableList/> "/> 1857 <stringAttribute key="org.eclipse.cdt.launch.MEMORY_BLOCKS" value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <memoryBlockExpressionList/> "/> 1858 <stringAttribute key="org.eclipse.cdt.launch.PROGRAM_ARGUMENTS" value="%(args)s"/> 1859 <stringAttribute key="org.eclipse.cdt.launch.PROGRAM_NAME" value="%(exec)s"/> 1860 <stringAttribute key="org.eclipse.cdt.launch.PROJECT_ATTR" value="%(project)s"/> 1861 <stringAttribute key="org.eclipse.cdt.launch.PROJECT_BUILD_CONFIG_ID_ATTR" value=""/> 1862 <stringAttribute key="org.eclipse.cdt.launch.WORKING_DIRECTORY" value="%(workdir)s"/> 1863 <booleanAttribute key="org.eclipse.cdt.launch.ui.ApplicationCDebuggerTab.DEFAULTS_SET" value="true"/> 1864 <booleanAttribute key="org.eclipse.cdt.launch.use_terminal" value="true"/> 1865 <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS"> 1866 <listEntry value="/%(project)s"/> 1868 <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES"> 1869 <listEntry value="4"/> 1871 <booleanAttribute key="org.eclipse.debug.core.appendEnvironmentVariables" value="false"/> 1872 <mapAttribute key="org.eclipse.debug.core.environmentVariables"> 1875 <mapAttribute key="org.eclipse.debug.core.preferred_launchers"> 1876 <mapEntry key="[debug]" value="org.eclipse.cdt.cdi.launch.localCLaunch"/> 1878 <listAttribute key="org.eclipse.debug.ui.favoriteGroups"> 1879 <listEntry value="org.eclipse.debug.ui.launchGroup.debug"/> 1881 </launchConfiguration> 1886 data[k] = codecs.decode(data[k],
'utf-8')
1887 xml = xml_template % data
1890 codecs.open(destfile,
"w", encoding=
'utf-8').
write(xml)
1892 print 'WARNING: problem generating Eclipse launcher' 1899 import simplejson
as json
1903 """An 'HTMLResultStream' writes its output to a set of HTML files. 1905 The argument 'dir' is used to select the destination directory for the HTML 1907 The destination directory may already contain the report from a previous run 1908 (for example of a different package), in which case it will be extended to 1909 include the new data. 1912 qm.fields.TextField(
1914 title=
"Destination Directory",
1915 description=
"""The name of the directory. 1917 All results will be written to the directory indicated.""",
1923 """Prepare the destination directory. 1925 Creates the destination directory and store in it some preliminary 1926 annotations and the static files found in the template directory 1929 ResultStream.__init__(self, arguments, **args)
1934 templateDir = os.path.join(os.path.dirname(__file__),
"html_report")
1935 if not os.path.isdir(self.dir):
1936 os.makedirs(self.dir)
1938 for f
in os.listdir(templateDir):
1939 src = os.path.join(templateDir, f)
1940 dst = os.path.join(self.dir, f)
1941 if not os.path.isdir(src)
and not os.path.exists(dst):
1942 shutil.copy(src, dst)
1944 if "CMTCONFIG" in os.environ:
1950 """Helper function to extend the global summary file in the destination 1957 ids = set([i[
"id"]
for i
in self.
_summary])
1958 newSummary = [i
for i
in oldSummary
if i[
"id"]
not in ids]
1964 """Writes the annotation to the annotation file. 1965 If the key is already present with a different value, the value becomes 1966 a list and the new value is appended to it, except for start_time and 1975 key, value =
map(str, [key, value])
1976 if key ==
"qmtest.run.start_time":
1981 if key
not in annotations:
1982 annotations[key] = value
1983 if "qmtest.run.end_time" in annotations:
1984 del annotations[
"qmtest.run.end_time"]
1987 if key
in annotations:
1988 old = annotations[key]
1989 if type(old)
is list:
1990 if value
not in old:
1991 annotations[key].append(value)
1993 annotations[key] = [old, value]
1995 annotations[key] = value
2001 """Prepare the test result directory in the destination directory storing 2002 into it the result fields. 2003 A summary of the test result is stored both in a file in the test directory 2004 and in the global summary file. 2007 summary[
"id"] = result.GetId()
2008 summary[
"outcome"] = result.GetOutcome()
2009 summary[
"cause"] = result.GetCause()
2010 summary[
"fields"] = result.keys()
2011 summary[
"fields"].sort()
2014 for f
in [
"id",
"outcome",
"cause"]:
2015 summary[f] = str(summary[f])
2016 summary[
"fields"] =
map(str, summary[
"fields"])
2018 self._summary.append(summary)
2024 testOutDir = os.path.join(self.dir, summary[
"id"])
2025 if not os.path.isdir(testOutDir):
2026 os.makedirs(testOutDir)
2027 json.dump(summary, open(os.path.join(testOutDir,
"summary.json"),
"w"),
2029 for f
in summary[
"fields"]:
2030 open(os.path.join(testOutDir, f),
"w").
write(result[f])
2039 class XMLResultStream(ResultStream):
2040 """An 'XMLResultStream' writes its output to a Ctest XML file. 2042 The argument 'dir' is used to select the destination file for the XML 2044 The destination directory may already contain the report from a previous run 2045 (for example of a different package), in which case it will be overrided to 2049 qm.fields.TextField(
2051 title=
"Destination Directory",
2052 description=
"""The name of the directory. 2054 All results will be written to the directory indicated.""",
2057 qm.fields.TextField(
2059 title=
"Output File Prefix",
2060 description=
"""The output file name will be the specified prefix 2061 followed by 'Test.xml' (CTest convention).""",
2067 """Prepare the destination directory. 2069 Creates the destination directory and store in it some preliminary 2072 ResultStream.__init__(self, arguments, **args)
2074 self.
_xmlFile = os.path.join(self.dir, self.prefix +
'Test.xml')
2080 if not os.path.isfile(self.
_xmlFile):
2082 if not os.path.exists(os.path.dirname(self.
_xmlFile)):
2083 os.makedirs(os.path.dirname(self.
_xmlFile))
2085 newdataset = ET.Element(
"newdataset")
2091 newdataset = self._tree.getroot()
2098 for site
in newdataset.getiterator():
2100 if site.get(
"OSPlatform") == os.uname()[4]:
2109 import multiprocessing
2111 "BuildName": os.getenv(
"CMTCONFIG"),
2112 "Name": os.uname()[1],
2113 "Generator":
"QMTest " + qm.version,
2114 "OSName": os.uname()[0],
2115 "Hostname": socket.gethostname(),
2116 "OSRelease": os.uname()[2],
2117 "OSVersion": os.uname()[3],
2118 "OSPlatform": os.uname()[4],
2119 "Is64Bits":
"unknown",
2120 "VendorString":
"unknown",
2121 "VendorID":
"unknown",
2122 "FamilyID":
"unknown",
2123 "ModelID":
"unknown",
2124 "ProcessorCacheSize":
"unknown",
2125 "NumberOfLogicalCPU": str(multiprocessing.cpu_count()),
2126 "NumberOfPhysicalCPU":
"0",
2127 "TotalVirtualMemory":
"0",
2128 "TotalPhysicalMemory":
"0",
2129 "LogicalProcessorsPerPhysical":
"0",
2130 "ProcessorClockFrequency":
"0",
2132 self.
_site = ET.SubElement(newdataset,
"Site", attrib)
2151 self.
_Testing = self._site.find(
"Testing")
2154 self.
_TestList = self._Testing.find(
"TestList")
2160 # Add some non-QMTest attributes 2161 if "CMTCONFIG" in os.environ: 2162 self.WriteAnnotation("cmt.cmtconfig", os.environ["CMTCONFIG"]) 2164 self.WriteAnnotation("hostname", socket.gethostname()) 2168 if key ==
"qmtest.run.start_time":
2169 if self._site.get(
"qmtest.run.start_time")
is not None:
2171 self._site.set(str(key), str(value))
2174 """Prepare the test result directory in the destination directory storing 2175 into it the result fields. 2176 A summary of the test result is stored both in a file in the test directory 2177 and in the global summary file. 2180 summary[
"id"] = result.GetId()
2181 summary[
"outcome"] = result.GetOutcome()
2182 summary[
"cause"] = result.GetCause()
2183 summary[
"fields"] = result.keys()
2184 summary[
"fields"].sort()
2187 for f
in [
"id",
"outcome",
"cause"]:
2188 summary[f] = str(summary[f])
2189 summary[
"fields"] =
map(str, summary[
"fields"])
2194 if "qmtest.start_time" in summary[
"fields"]:
2195 haveStartDate =
True 2197 haveStartDate =
False 2198 if "qmtest.end_time" in summary[
"fields"]:
2205 self.
_startTime = calendar.timegm(time.strptime(
2206 result[
"qmtest.start_time"],
"%Y-%m-%dT%H:%M:%SZ"))
2207 if self._StartTestTime.text
is None:
2208 self._StartDateTime.text = time.strftime(
2209 "%b %d %H:%M %Z", time.localtime(self.
_startTime))
2210 self._StartTestTime.text = str(self.
_startTime)
2211 self._site.set(
"BuildStamp", result[
"qmtest.start_time"])
2215 self.
_endTime = calendar.timegm(time.strptime(
2216 result[
"qmtest.end_time"],
"%Y-%m-%dT%H:%M:%SZ"))
2219 tl = ET.Element(
"Test")
2220 tl.text = summary[
"id"]
2221 self._TestList.insert(0, tl)
2224 Test = ET.Element(
"Test")
2225 if summary[
"outcome"] ==
"PASS":
2226 Test.set(
"Status",
"passed")
2227 elif summary[
"outcome"] ==
"FAIL":
2228 Test.set(
"Status",
"failed")
2229 elif summary[
"outcome"] ==
"SKIPPED" or summary[
"outcome"] ==
"UNTESTED":
2230 Test.set(
"Status",
"skipped")
2231 elif summary[
"outcome"] ==
"ERROR":
2232 Test.set(
"Status",
"failed")
2233 Name = ET.SubElement(Test,
"Name",)
2234 Name.text = summary[
"id"]
2235 Results = ET.SubElement(Test,
"Results")
2238 self._Testing.insert(3, Test)
2240 if haveStartDate
and haveEndDate:
2243 testduration = str(delta)
2244 Testduration = ET.SubElement(Results,
"NamedMeasurement")
2245 Testduration.set(
"name",
"Execution Time")
2246 Testduration.set(
"type",
"numeric/float")
2247 value = ET.SubElement(Testduration,
"Value")
2248 value.text = testduration
2251 for n
in (
"qmtest.end_time",
"qmtest.start_time",
"qmtest.cause",
"ExecTest.stdout"):
2252 if n
in summary[
"fields"]:
2253 summary[
"fields"].remove(n)
2257 if "ExecTest.exit_code" in summary[
"fields"]:
2258 summary[
"fields"].remove(
"ExecTest.exit_code")
2259 ExitCode = ET.SubElement(Results,
"NamedMeasurement")
2260 ExitCode.set(
"name",
"exit_code")
2261 ExitCode.set(
"type",
"numeric/integer")
2262 value = ET.SubElement(ExitCode,
"Value")
2264 result[
"ExecTest.exit_code"])
2266 TestStartTime = ET.SubElement(Results,
"NamedMeasurement")
2267 TestStartTime.set(
"name",
"Start_Time")
2268 TestStartTime.set(
"type",
"String")
2269 value = ET.SubElement(TestStartTime,
"Value")
2272 "%b %d %H:%M %Z %Y", time.localtime(self.
_startTime)))
2276 TestEndTime = ET.SubElement(Results,
"NamedMeasurement")
2277 TestEndTime.set(
"name",
"End_Time")
2278 TestEndTime.set(
"type",
"String")
2279 value = ET.SubElement(TestEndTime,
"Value")
2282 "%b %d %H:%M %Z %Y", time.localtime(self.
_endTime)))
2286 if summary[
"cause"]:
2287 FailureCause = ET.SubElement(Results,
"NamedMeasurement")
2288 FailureCause.set(
"name",
"Cause")
2289 FailureCause.set(
"type",
"String")
2290 value = ET.SubElement(FailureCause,
"Value")
2295 for field
in summary[
"fields"]:
2296 fields[field] = ET.SubElement(Results,
"NamedMeasurement")
2297 fields[field].set(
"type",
"String")
2298 fields[field].set(
"name", field)
2299 value = ET.SubElement(fields[field],
"Value")
2301 if "<pre>" in result[field][0:6]:
2306 if result.has_key(
"ExecTest.stdout"):
2307 Measurement = ET.SubElement(Results,
"Measurement")
2308 value = ET.SubElement(Measurement,
"Value")
2309 if "<pre>" in result[
"ExecTest.stdout"][0:6]:
2311 result[
"ExecTest.stdout"][5:-6])
2314 result[
"ExecTest.stdout"])
2318 self._tree.write(self.
_xmlFile,
"utf-8")
2323 self._EndTestTime.text = str(self.
_endTime)
2324 self._EndDateTime.text = time.strftime(
2325 "%b %d %H:%M %Z", time.localtime(self.
_endTime))
2332 self._ElapsedMinutes.text = str(delta / 60)
2336 self._tree.write(self.
_xmlFile,
"utf-8")
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 __init__(self, arguments=None, args)
def CheckHistosSummaries(self, stdout, result, causes, dict=None, ignore=None)
def __init__(self, signature)
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)
decltype(auto) constexpr apply(F &&f, Tuple &&t) noexcept(noexcept( detail::apply_impl(std::forward< F >(f), std::forward< Tuple >(t), std::make_index_sequence< std::tuple_size< std::remove_reference_t< Tuple >>::value >{})))
def runtime_env(self, env=None)
def _expandReferenceFileName(self, reffile)
def escape_xml_illegal_chars(val, replacement='?')
MsgStream & hex(MsgStream &log)
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)
decltype(auto) range(Args &&...args)
Zips multiple containers together to form a single range.
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 __getattr__(self, attr)
def findHistosSummaries(stdout)
def ValidateOutput(self, stdout, stderr, result)
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, arguments=None, args)
def __init__(self, path=None)
def __getattr__(self, attr)
def __init__(self, start, end)
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)