5 __author__ =
'Marco Clemencic CERN/PH-LBC' 20 from subprocess
import Popen, PIPE, STDOUT
23 from GaudiKernel
import ROOT6WorkAroundEnabled
32 os.environ[
'LC_ALL'] =
'C' 36 import xml.etree.cElementTree
as ET
38 import xml.etree.ElementTree
as ET
44 return timedelta.days * 86400 + timedelta.seconds + timedelta.microseconds / 1000000
48 from qm.test.classes.command
import ExecTestBase
49 from qm.test.result_stream
import ResultStream
56 if sys.platform ==
"win32":
59 from threading
import *
79 Class to changes the environment temporarily. 82 def __init__(self, orig=os.environ, keep_same=False):
84 Create a temporary environment on top of the one specified 85 (it can be another TemporaryEnvironment instance). 94 Set an environment variable recording the previous value. 102 self.
env[key] = value
106 Get an environment variable. 107 Needed to provide the same interface as os.environ. 113 Unset an environment variable. 114 Needed to provide the same interface as os.environ. 116 if key
not in self.
env:
123 Return the list of defined environment variables. 124 Needed to provide the same interface as os.environ. 126 return self.env.keys()
130 Return the list of (name,value) pairs for the defined environment variables. 131 Needed to provide the same interface as os.environ. 133 return self.env.items()
138 Needed to provide the same interface as os.environ. 140 return key
in self.
env 144 Revert all the changes done to the original environment. 146 for key, value
in self.old_values.items():
150 self.
env[key] = value
155 Revert the changes on destruction. 162 Generate a shell script to reproduce the changes in the environment. 164 shells = [
'csh',
'sh',
'bat']
165 if shell_type
not in shells:
166 raise RuntimeError(
"Shell type '%s' unknown. Available: %s" %
167 (shell_type, shells))
169 for key, value
in self.old_values.items():
170 if key
not in self.
env:
172 if shell_type ==
'csh':
173 out +=
'unsetenv %s\n' % key
174 elif shell_type ==
'sh':
175 out +=
'unset %s\n' % key
176 elif shell_type ==
'bat':
177 out +=
'set %s=\n' % key
180 if shell_type ==
'csh':
181 out +=
'setenv %s "%s"\n' % (key, self.
env[key])
182 elif shell_type ==
'sh':
183 out +=
'export %s="%s"\n' % (key, self.
env[key])
184 elif shell_type ==
'bat':
185 out +=
'set %s=%s\n' % (key, self.
env[key])
190 """Small class for temporary directories. 191 When instantiated, it creates a temporary directory and the instance 192 behaves as the string containing the directory name. 193 When the instance goes out of scope, it removes all the content of 194 the temporary directory (automatic clean-up). 212 shutil.rmtree(self.
name)
215 return getattr(self.
name, attr)
219 """Small class for temporary files. 220 When instantiated, it creates a temporary directory and the instance 221 behaves as the string containing the directory name. 222 When the instance goes out of scope, it removes all the content of 223 the temporary directory (automatic clean-up). 236 self._fd, self.
name = tempfile.mkstemp(suffix, prefix, dir, text)
237 self.
file = os.fdopen(self._fd,
"r+")
249 return getattr(self.
file, attr)
253 """Small wrapper to call CMT. 263 if type(args)
is str:
265 cmd =
"cmt %s" % command
273 result = os.popen4(cmd)[1].
read()
279 return lambda args=[]: self.
_run_cmt(attr, args)
282 """Returns a dictionary containing the runtime environment produced by CMT. 283 If a dictionary is passed a modified instance of it is returned. 287 for l
in self.setup(
"-csh").splitlines():
289 if l.startswith(
"setenv"):
290 dummy, name, value = l.split(
None, 3)
291 env[name] = value.strip(
'"')
292 elif l.startswith(
"unsetenv"):
293 dummy, name = l.split(
None, 2)
299 r = self.show([
"macro", k])
300 if r.find(
"CMT> Error: symbol not found") >= 0:
303 return self.show([
"macro_value", k]).strip()
311 Locates an executable in the executables path ($PATH) and returns the full 312 path to it. An application is looked for with or without the '.exe' suffix. 313 If the executable cannot be found, None is returned 315 if os.path.isabs(executable):
316 if not os.path.exists(executable):
317 if executable.endswith(
'.exe'):
318 if os.path.exists(executable[:-4]):
319 return executable[:-4]
321 for d
in os.environ.get(
"PATH").split(os.pathsep):
322 fullpath = os.path.join(d, executable)
323 if os.path.exists(fullpath):
325 if executable.endswith(
'.exe'):
326 return which(executable[:-4])
331 np = os.path.normpath(os.path.expandvars(p))
332 if os.path.exists(np):
333 p = os.path.realpath(np)
351 _illegal_xml_chars_RE = re.compile(
352 u'[\x00-\x08\x0b\x0c\x0e-\x1F\uD800-\uDFFF\uFFFE\uFFFF]')
356 "Return the hex string " 357 return "".join(
map(hexConvert, match.group()))
361 return hex(ord(char))
365 return _illegal_xml_chars_RE.sub(hexreplace, val)
369 """Filter out characters that are illegal in XML. 370 Looks for any character in val that is not allowed in XML 371 and replaces it with replacement ('?' by default). 374 return _illegal_xml_chars_RE.sub(replacement, val)
383 """Basic implementation of an option validator for Gaudi tests. 384 This implementation is based on the standard (LCG) validation functions 394 """Validate the output of the program. 396 'stdout' -- A string containing the data written to the standard output 399 'stderr' -- A string containing the data written to the standard error 402 'result' -- A 'Result' object. It may be used to annotate 403 the outcome according to the content of stderr. 405 returns -- A list of strings giving causes of failure.""" 410 causes.append(self.
cause)
416 """Compare 's1' and 's2', ignoring line endings. 422 returns -- True if 's1' and 's2' are the same, ignoring 423 differences in line endings.""" 429 to_ignore = re.compile(
430 r'Warning in <TInterpreter::ReadRootmapFile>: .* is already in .*' 434 return not to_ignore.match(l)
436 return filter(keep_line, s1.splitlines()) == filter(
437 keep_line, s2.splitlines())
439 return s1.splitlines() == s2.splitlines()
443 """ Base class for a callable that takes a file and returns a modified 450 if hasattr(input,
"__iter__"):
454 lines = input.splitlines()
462 output =
'\n'.join(output)
491 if line.find(s) >= 0:
506 if self.
start in line:
509 elif self.
end in line:
519 when = re.compile(when)
523 if isinstance(rhs, RegexpReplacer):
525 res._operations = self.
_operations + rhs._operations
527 res = FilePreprocessor.__add__(self, rhs)
532 if w
is None or w.search(line):
533 line = o.sub(r, line)
540 "[0-2]?[0-9]:[0-5][0-9]:[0-5][0-9] [0-9]{4}[-/][01][0-9][-/][0-3][0-9] *(CES?T)?",
541 "00:00:00 1970-01-01")
543 normalizeEOL.__processLine__ =
lambda line: str(line).rstrip() +
'\n' 547 skipEmptyLines.__processLine__ =
lambda line: (line.strip()
and line)
or None 561 line = line[:(pos + self.
siglen)]
562 lst = line[(pos + self.
siglen):].split()
564 line +=
" ".join(lst)
569 normalizeExamples = maskPointers + normalizeDate
572 (
"TIMER.TIMER",
r"\s+[+-]?[0-9]+[0-9.]*",
" 0"),
573 (
"release all pending",
r"^.*/([^/]*:.*)",
r"\1"),
574 (
"0x########",
r".*/([^/]*.*)",
r"[\1]"),
575 (
"^#.*file",
r"file '.*[/\\]([^/\\]*)$",
r"file '\1"),
576 (
"^JobOptionsSvc.*options successfully read in from",
577 r"read in from .*[/\\]([^/\\]*)$",
581 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}",
582 "00000000-0000-0000-0000-000000000000"),
584 (
"ServiceLocatorHelper::",
"ServiceLocatorHelper::(create|locate)Service",
585 "ServiceLocatorHelper::service"),
587 (
None,
r"e([-+])0([0-9][0-9])",
r"e\1\2"),
589 (
None,
r'Service reference count check:',
590 r'Looping over all active services...'),
592 (
None,
r"Property(.*)'ErrorCount':",
r"Property\1'ErrorCounter':"),
599 "JobOptionsSvc INFO # ",
600 "JobOptionsSvc WARNING # ",
603 "This machine has a speed",
606 "ToolSvc.Sequenc... INFO",
607 "DataListenerSvc INFO XML written to file:",
610 "DEBUG No writable file catalog found which contains FID:",
612 "DEBUG Service base class initialized successfully",
613 "DEBUG Incident timing:",
615 "INFO 'CnvServices':[",
619 'EventLoopMgr SUCCESS Event Number = ',
620 'EventLoopMgr SUCCESS ---> Loop Finished',
623 r"^JobOptionsSvc INFO *$",
626 r"(Always|SUCCESS)\s*(Root f|[^ ]* F)ile version:",
628 r"0x[0-9a-fA-F#]+ *Algorithm::sysInitialize *\[",
630 r"0x[0-9a-fA-F#]* *__gxx_personality_v0 *\[",
631 r"File '.*.xml' does not exist",
632 r"INFO Refer to dataset .* by its file ID:",
633 r"INFO Referring to dataset .* by its file ID:",
634 r"INFO Disconnect from dataset",
635 r"INFO Disconnected from dataset",
636 r"INFO Disconnected data IO:",
637 r"IncidentSvc\s*(DEBUG (Adding|Removing)|VERBOSE Calling)",
639 r"^StatusCodeSvc.*listing all unchecked return codes:",
640 r"^StatusCodeSvc\s*INFO\s*$",
641 r"Num\s*\|\s*Function\s*\|\s*Source Library",
644 r"ERROR Failed to modify file: .* Errno=2 No such file or directory",
646 r"^ +[0-9]+ \|.*ROOT",
647 r"^ +[0-9]+ \|.*\|.*Dict",
649 r"StatusCodeSvc.*all StatusCode instances where checked",
651 r"EventLoopMgr.*---> Loop Finished",
655 r"SUCCESS\s*Booked \d+ Histograms",
662 r'Warning in <TInterpreter::ReadRootmapFile>: .* is already in .*',
665 normalizeExamples = (lineSkipper + normalizeExamples + skipEmptyLines +
666 normalizeEOL +
LineSorter(
"Services to release : "))
670 def __init__(self, reffile, cause, result_key, preproc=normalizeExamples):
678 if os.path.isfile(self.
reffile):
679 orig = open(self.
reffile).xreadlines()
685 new = stdout.splitlines()
689 diffs = difflib.ndiff(orig, new, charjunk=difflib.IS_CHARACTER_JUNK)
690 filterdiffs =
map(
lambda x: x.strip(),
691 filter(
lambda x: x[0] !=
" ", diffs))
694 result[self.
result_key] = result.Quote(
"\n".join(filterdiffs))
698 +) standard output of the test""")
699 causes.append(self.
cause)
717 Given a block of text, tries to find it in the output. 718 The block had to be identified by a signature line. By default, the first 719 line is used as signature, or the line pointed to by signature_offset. If 720 signature_offset points outside the block, a signature line can be passed as 721 signature argument. Note: if 'signature' is None (the default), a negative 722 signature_offset is interpreted as index in a list (e.g. -1 means the last 723 line), otherwise the it is interpreted as the number of lines before the 724 first one of the block the signature must appear. 725 The parameter 'id' allow to distinguish between different calls to this 726 function in the same validation code. 729 reflines = filter(
None,
map(
lambda s: s.rstrip(), reference.splitlines()))
731 raise RuntimeError(
"Empty (or null) reference")
733 outlines = filter(
None,
map(
lambda s: s.rstrip(), stdout.splitlines()))
735 res_field =
"GaudiTest.RefBlock" 737 res_field +=
"_%s" % id
739 if signature
is None:
740 if signature_offset < 0:
741 signature_offset = len(reference) + signature_offset
742 signature = reflines[signature_offset]
745 pos = outlines.index(signature)
746 outlines = outlines[pos - signature_offset:pos + len(reflines) -
748 if reflines != outlines:
749 msg =
"standard output" 751 if not msg
in causes:
753 result[res_field +
".observed"] = result.Quote(
"\n".join(outlines))
755 causes.append(
"missing signature")
756 result[res_field +
".signature"] = result.Quote(signature)
757 if len(reflines) > 1
or signature != reflines[0]:
758 result[res_field +
".expected"] = result.Quote(
"\n".join(reflines))
765 Count the number of messages with required severity (by default ERROR and FATAL) 766 and check if their numbers match the expected ones (0 by default). 767 The dictionary "expected" can be used to tune the number of errors and fatals 768 allowed, or to limit the number of expected warnings etc. 770 stdout = kwargs[
"stdout"]
771 result = kwargs[
"result"]
772 causes = kwargs[
"causes"]
779 outlines = stdout.splitlines()
780 from math
import log10
781 fmt =
"%%%dd - %%s" % (int(log10(len(outlines)) + 1))
787 if len(words) >= 2
and words[1]
in errors:
788 errors[words[1]].append(fmt % (linecount, l.rstrip()))
791 if len(errors[e]) != expected[e]:
792 causes.append(
'%s(%d)' % (e, len(errors[e])))
793 result[
"GaudiTest.lines.%s" % e] = result.Quote(
'\n'.join(
795 result[
"GaudiTest.lines.%s.expected#" % e] = result.Quote(
803 Parse the TTree summary table in lines, starting from pos. 804 Returns a tuple with the dictionary with the digested informations and the 805 position of the first line after the summary. 812 return [f.strip()
for f
in l.strip(
"*\n").split(
':', 2)]
816 cols = splitcols(ll[0])
817 r[
"Name"], r[
"Title"] = cols[1:]
819 cols = splitcols(ll[1])
820 r[
"Entries"] = int(cols[1])
822 sizes = cols[2].split()
823 r[
"Total size"] = int(sizes[2])
824 if sizes[-1] ==
"memory":
827 r[
"File size"] = int(sizes[-1])
829 cols = splitcols(ll[2])
830 sizes = cols[2].split()
831 if cols[0] ==
"Baskets":
832 r[
"Baskets"] = int(cols[1])
833 r[
"Basket size"] = int(sizes[2])
834 r[
"Compression"] = float(sizes[-1])
837 if i < (count - 3)
and lines[i].startswith(
"*Tree"):
838 result = parseblock(lines[i:i + 3])
839 result[
"Branches"] = {}
841 while i < (count - 3)
and lines[i].startswith(
"*Br"):
842 if i < (count - 2)
and lines[i].startswith(
"*Branch "):
846 branch = parseblock(lines[i:i + 3])
847 result[
"Branches"][branch[
"Name"]] = branch
855 Scan stdout to find ROOT TTree summaries and digest them. 857 stars = re.compile(
r"^\*+$")
858 outlines = stdout.splitlines()
859 nlines = len(outlines)
865 while i < nlines
and not stars.match(outlines[i]):
870 trees[tree[
"Name"]] = tree
877 Check that all the keys in reference are in to_check too, with the same value. 878 If the value is a dict, the function is called recursively. to_check can 879 contain more keys than reference, that will not be tested. 880 The function returns at the first difference found. 885 ignore_re = re.compile(ignore)
886 keys = [key
for key
in reference
if not ignore_re.match(key)]
888 keys = reference.keys()
892 if (
type(reference[k])
is dict)
and (
type(to_check[k])
is dict):
894 failed = fail_keys =
cmpTreesDicts(reference[k], to_check[k],
898 failed = to_check[k] != reference[k]
903 fail_keys.insert(0, k)
914 if c
is None or r
is None:
916 return (fail_path, r, c)
920 h_count_re = re.compile(
r"^(.*)SUCCESS\s+Booked (\d+) Histograms :\s+(.*)")
925 Extract the histograms infos from the lines starting at pos. 926 Returns the position of the first line after the summary block. 929 h_table_head = re.compile(
930 r'SUCCESS\s+(1D|2D|3D|1D profile|2D profile) histograms in directory\s+"(\w*)"' 932 h_short_summ = re.compile(
r"ID=([^\"]+)\s+\"([^\"]+)\"\s+(.*)")
937 m = h_count_re.search(lines[pos])
938 name = m.group(1).strip()
939 total = int(m.group(2))
941 for k, v
in [x.split(
"=")
for x
in m.group(3).split()]:
944 header[
"Total"] = total
948 m = h_table_head.search(lines[pos])
951 t = t.replace(
" profile",
"Prof")
958 if l.startswith(
" | ID"):
960 titles = [x.strip()
for x
in l.split(
"|")][1:]
962 while pos < nlines
and lines[pos].startswith(
" |"):
964 values = [x.strip()
for x
in l.split(
"|")][1:]
966 for i
in range(len(titles)):
967 hcont[titles[i]] = values[i]
968 cont[hcont[
"ID"]] = hcont
970 elif l.startswith(
" ID="):
971 while pos < nlines
and lines[pos].startswith(
" ID="):
974 for x
in h_short_summ.search(lines[pos]).groups()
976 cont[values[0]] = values
980 "Cannot understand line %d: '%s'" % (pos, l))
984 summ[d][
"header"] = header
989 summ[name] = {
"header": header}
995 Scan stdout to find ROOT TTree summaries and digest them. 997 outlines = stdout.splitlines()
998 nlines = len(outlines) - 1
1006 match = h_count_re.search(outlines[pos])
1007 while pos < nlines
and not match:
1009 match = h_count_re.search(outlines[pos])
1012 summaries.update(summ)
1018 """Create a new 'Filter'. 1020 'input' -- The string containing the input to provide to the 1023 'timeout' -- As for 'TimeoutExecutable.__init__'.""" 1025 super(GaudiFilterExecutable, self).
__init__(input, timeout)
1032 tmpf = tempfile.mkstemp()
1037 """Copied from TimeoutExecutable to allow the re-implementation of 1040 if sys.platform ==
"win32":
1053 """Code copied from both FilterExecutable and TimeoutExecutable. 1056 if self._stdin_pipe:
1057 self._ClosePipeEnd(self._stdin_pipe[0])
1058 if self._stdout_pipe:
1059 self._ClosePipeEnd(self._stdout_pipe[1])
1060 if self._stderr_pipe:
1061 self._ClosePipeEnd(self._stderr_pipe[1])
1069 super(qm.executable.TimeoutExecutable, self).
_HandleChild()
1076 child_pid = self._GetChildPID()
1078 os.setpgid(child_pid, child_pid)
1106 os.setpgid(0, child_pid)
1115 max_fds = os.sysconf(
"SC_OPEN_MAX")
1118 for fd
in xrange(max_fds):
1129 if sys.platform ==
"linux2":
1132 os.path.join(
"/proc", str(child_pid),
"exe"),
1133 str(child_pid),
"-batch",
"-n",
"-x",
1134 "'%s'" % os.path.join(
1135 os.path.dirname(__file__),
1140 o = os.popen(
" ".join(cmd)).
read()
1145 os.kill(0, signal.SIGKILL)
1148 select.select([], [], [])
1153 elif self.
__timeout >= 0
and sys.platform ==
"win32":
1156 self.__monitor_thread.start()
1158 if sys.platform ==
"win32":
1161 """Code copied from FilterExecutable. 1162 Kill the child if the timeout expires. 1164 This function is run in the monitoring thread.""" 1172 result = win32event.WaitForSingleObject(self._GetChildPID(),
1175 if result == win32con.WAIT_TIMEOUT:
1185 """Standard Gaudi test. 1188 qm.fields.TextField(
1192 description=
"""The path to the program. 1194 This field indicates the path to the program. If it is not 1195 an absolute path, the value of the 'PATH' environment 1196 variable will be used to search for the program. 1197 If not specified, $GAUDIEXE or Gaudi.exe are used. 1200 qm.fields.TextField(
1202 title=
"Argument List",
1203 description=
"""The command-line arguments. 1205 If this field is left blank, the program is run without any 1208 Use this field to specify the option files. 1210 An implicit 0th argument (the path to the program) is added 1211 automatically.""")),
1212 qm.fields.TextField(
1215 description=
"""Options to be passed to the application. 1217 This field allows to pass a list of options to the main program 1218 without the need of a separate option file. 1220 The content of the field is written to a temporary file which name 1221 is passed the the application as last argument (appended to the 1222 field "Argument List". 1227 qm.fields.TextField(
1229 title=
"Working Directory",
1230 description=
"""Path to the working directory. 1232 If this field is left blank, the program will be run from the qmtest 1233 directory, otherwise from the directory specified.""",
1235 qm.fields.TextField(
1237 title=
"Reference Output",
1238 description=
"""Path to the file containing the reference output. 1240 If this field is left blank, any standard output will be considered 1243 If the reference file is specified, any output on standard error is 1245 qm.fields.TextField(
1246 name=
"error_reference",
1247 title=
"Reference for standard error",
1249 """Path to the file containing the reference for the standard error. 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 1257 qm.fields.TextField(
1258 name=
"unsupported_platforms",
1259 title=
"Unsupported Platforms",
1260 description=
"""Platform on which the test must not be run. 1262 List of regular expressions identifying the platforms on which the 1263 test is not run and the result is set to UNTESTED.""")),
1264 qm.fields.TextField(
1267 description=
"""Function to validate the output of the test. 1269 If defined, the function is used to validate the products of the 1271 The function is called passing as arguments: 1272 self: the test class instance 1273 stdout: the standard output of the executed test 1274 stderr: the standard error of the executed test 1275 result: the Result objects to fill with messages 1276 The function must return a list of causes for the failure. 1277 If specified, overrides standard output, standard error and 1283 qm.fields.BooleanField(
1284 name=
"use_temp_dir",
1285 title=
"Use temporary directory",
1286 description=
"""Use temporary directory. 1288 If set to true, use a temporary directory as working directory. 1290 default_value=
"false"),
1291 qm.fields.IntegerField(
1293 title=
"Expected signal",
1294 description=
"""Expect termination by signal.""",
1295 default_value=
None),
1302 for x
in [str(y).strip()
for y
in self.unsupported_platforms]
if x
1304 for p_re
in unsupported:
1305 if p_re.search(platform):
1306 result.SetOutcome(result.UNTESTED)
1307 result[result.CAUSE] =
'Platform not supported.' 1313 Return the platform Id defined in CMTCONFIG or SCRAM_ARCH. 1317 if "CMTCONFIG" in os.environ:
1318 arch = os.environ[
"CMTCONFIG"]
1319 elif "SCRAM_ARCH" in os.environ:
1320 arch = os.environ[
"SCRAM_ARCH"]
1325 Return True if the current platform is Windows. 1327 This function was needed because of the change in the CMTCONFIG format, 1328 from win32_vc71_dbg to i686-winxp-vc9-dbg. 1331 return "winxp" in platform
or platform.startswith(
"win")
1339 def platformSplit(p):
1340 return set(p.split(
'-' in p
and '-' or '_'))
1342 reference = os.path.normpath(os.path.expandvars(reffile))
1344 spec_ref = reference[:-3] + self.
GetPlatform()[0:3] + reference[-3:]
1345 if os.path.isfile(spec_ref):
1346 reference = spec_ref
1349 dirname, basename = os.path.split(reference)
1352 head = basename +
"." 1353 head_len = len(head)
1355 if 'do0' in platform:
1358 for f
in os.listdir(dirname):
1359 if f.startswith(head):
1360 req_plat = platformSplit(f[head_len:])
1361 if platform.issuperset(req_plat):
1362 candidates.append((len(req_plat), f))
1367 reference = os.path.join(dirname, candidates[-1][1])
1375 ignore=
r"Basket|.*size|Compression"):
1377 Compare the TTree summaries in stdout with the ones in trees_dict or in 1378 the reference file. By default ignore the size, compression and basket 1380 The presence of TTree summaries when none is expected is not a failure. 1382 if trees_dict
is None:
1385 if reference
and os.path.isfile(reference):
1390 from pprint
import PrettyPrinter
1391 pp = PrettyPrinter()
1393 result[
"GaudiTest.TTrees.expected"] = result.Quote(
1394 pp.pformat(trees_dict))
1396 result[
"GaudiTest.TTrees.ignore"] = result.Quote(ignore)
1401 causes.append(
"trees summaries")
1404 result[
"GaudiTest.TTrees.failure_on"] = result.Quote(msg)
1405 result[
"GaudiTest.TTrees.found"] = result.Quote(pp.pformat(trees))
1416 Compare the TTree summaries in stdout with the ones in trees_dict or in 1417 the reference file. By default ignore the size, compression and basket 1419 The presence of TTree summaries when none is expected is not a failure. 1424 if reference
and os.path.isfile(reference):
1429 from pprint
import PrettyPrinter
1430 pp = PrettyPrinter()
1432 result[
"GaudiTest.Histos.expected"] = result.Quote(
1435 result[
"GaudiTest.Histos.ignore"] = result.Quote(ignore)
1440 causes.append(
"histos summaries")
1442 result[
"GaudiTest.Histos.failure_on"] = result.Quote(msg)
1443 result[
"GaudiTest.Histos.found"] = result.Quote(pp.pformat(histos))
1454 Default validation action: compare standard output and error to the 1459 preproc = normalizeExamples
1463 if reference
and os.path.isfile(reference):
1464 result[
"GaudiTest.output_reference"] = reference
1468 "GaudiTest.output_diff",
1469 preproc=preproc)(stdout, result)
1477 newref = open(reference +
".new",
"w")
1479 for l
in stdout.splitlines():
1480 newref.write(l.rstrip() +
'\n')
1490 if reference
and os.path.isfile(reference):
1491 result[
"GaudiTest.error_reference"] = reference
1495 "GaudiTest.error_diff",
1496 preproc=preproc)(stderr, result)
1499 newref = open(reference +
".new",
"w")
1501 for l
in stderr.splitlines():
1502 newref.write(l.rstrip() +
'\n')
1506 "ExecTest.expected_stderr")(stderr,
1514 if self.validator.strip() !=
"":
1516 class CallWrapper(object):
1518 Small wrapper class to dynamically bind some default arguments 1522 def __init__(self, callable, extra_args={}):
1526 from inspect
import getargspec
1533 def __call__(self, *args, **kwargs):
1537 kwargs = dict(kwargs)
1541 if a
not in positional
and a
not in kwargs:
1546 exported_symbols = {
1557 "findReferenceBlock":
1558 CallWrapper(findReferenceBlock, {
1563 "validateWithReference":
1572 CallWrapper(countErrorLines, {
1577 "checkTTreesSummaries":
1583 "checkHistosSummaries":
1590 exec self.validator
in globals(), exported_symbols
1598 Add the content of the environment to the result object. 1600 Copied from the QMTest class of COOL. 1602 vars = os.environ.keys()
1604 result[
'GaudiTest.environment'] = \
1606 '\n'.join([
"%s=%s" % (v, os.environ[v])
for v
in vars]))
1608 def Run(self, context, result):
1611 'context' -- A 'Context' giving run-time parameters to the 1614 'result' -- A 'Result' object. The outcome will be 1615 'Result.PASS' when this method is called. The 'result' may be 1616 modified by this method to indicate outcomes other than 1617 'Result.PASS' or to add annotations.""" 1626 elif "GAUDIEXE" in os.environ:
1627 prog = os.environ[
"GAUDIEXE"]
1632 dummy, prog_ext = os.path.splitext(prog)
1633 if prog_ext
not in [
".exe",
".py",
".bat"]
and self.
isWinPlatform():
1637 prog =
which(prog)
or prog
1640 args =
map(rationalizepath, self.args)
1646 if self.options.strip():
1649 r"from\s+Gaudi.Configuration\s+import\s+\*|from\s+Configurables\s+import",
1653 tmpfile.writelines(
"\n".join(self.options.splitlines()))
1655 args.append(tmpfile.name)
1656 result[
"GaudiTest.options"] = result.Quote(self.options)
1659 if prog_ext ==
".py":
1660 args.insert(0, prog)
1662 prog =
which(
"python.exe")
or "python.exe" 1664 prog =
which(
"python")
or "python" 1667 origdir = os.getcwd()
1669 os.chdir(str(os.path.normpath(os.path.expandvars(self.workdir))))
1671 if "QMTEST_TMPDIR" in os.environ:
1672 qmtest_tmpdir = os.environ[
"QMTEST_TMPDIR"]
1673 if not os.path.exists(qmtest_tmpdir):
1674 os.makedirs(qmtest_tmpdir)
1675 os.chdir(qmtest_tmpdir)
1676 elif "qmtest.tmpdir" in context:
1677 os.chdir(context[
"qmtest.tmpdir"])
1679 if "QMTEST_IGNORE_TIMEOUT" not in os.environ:
1687 prog, args, destdir=os.path.join(origdir,
'.eclipse'))
1689 self.
RunProgram(prog, [prog] + args, context, result)
1691 if result.GetOutcome()
not in [result.PASS]:
1698 """Run the 'program'. 1700 'program' -- The path to the program to run. 1702 'arguments' -- A list of the arguments to the program. This 1703 list must contain a first argument corresponding to 'argv[0]'. 1705 'context' -- A 'Context' giving run-time parameters to the 1708 'result' -- A 'Result' object. The outcome will be 1709 'Result.PASS' when this method is called. The 'result' may be 1710 modified by this method to indicate outcomes other than 1711 'Result.PASS' or to add annotations. 1713 @attention: This method has been copied from command.ExecTestBase 1714 (QMTest 2.3.0) and modified to keep stdout and stderr 1715 for tests that have been terminated by a signal. 1716 (Fundamental for debugging in the Application Area) 1720 environment = self.MakeEnvironment(context)
1722 if "slc6" in environment.get(
'CMTCONFIG',
''):
1723 environment[
'TERM'] =
'dumb' 1736 exit_status = e.Run(arguments, environment, path=program)
1738 if e.stack_trace_file
and os.path.exists(e.stack_trace_file):
1739 stack_trace = open(e.stack_trace_file).
read()
1740 os.remove(e.stack_trace_file)
1744 result[
"ExecTest.stack_trace"] = result.Quote(stack_trace)
1747 if (sys.platform ==
"win32" or os.WIFEXITED(exit_status)
1753 if self.exit_code
is None:
1755 elif sys.platform ==
"win32":
1756 exit_code = exit_status
1758 exit_code = os.WEXITSTATUS(exit_status)
1763 result[
"ExecTest.exit_code"] = str(exit_code)
1764 result[
"ExecTest.stdout"] = result.Quote(stdout)
1765 result[
"ExecTest.stderr"] = result.Quote(stderr)
1767 if exit_code != self.exit_code:
1768 causes.append(
"exit_code")
1769 result[
"ExecTest.expected_exit_code"] \
1770 = str(self.exit_code)
1775 result.Fail(
"Unexpected %s." % string.join(causes,
", "))
1776 elif os.WIFSIGNALED(exit_status):
1779 signal_number = str(os.WTERMSIG(exit_status))
1781 result.Fail(
"Program terminated by signal.")
1785 result.Fail(
"Exceeded time limit (%ds), terminated." % timeout)
1786 result[
"ExecTest.signal_number"] = signal_number
1787 result[
"ExecTest.stdout"] = result.Quote(e.stdout)
1788 result[
"ExecTest.stderr"] = result.Quote(e.stderr)
1790 result[
"ExecTest.expected_signal_number"] = str(self.
signal)
1791 elif os.WIFSTOPPED(exit_status):
1794 signal_number = str(os.WSTOPSIG(exit_status))
1796 result.Fail(
"Program stopped by signal.")
1800 result.Fail(
"Exceeded time limit (%ds), stopped." % timeout)
1801 result[
"ExecTest.signal_number"] = signal_number
1802 result[
"ExecTest.stdout"] = result.Quote(e.stdout)
1803 result[
"ExecTest.stderr"] = result.Quote(e.stderr)
1807 result.Fail(
"Program did not terminate normally.")
1813 result[
"ExecTest.stdout"] = result[
"ExecTest.stdout"].replace(
1819 if 'NO_ECLIPSE_LAUNCHERS' in os.environ:
1824 projbasedir = os.path.normpath(destdir)
1825 while not os.path.exists(os.path.join(projbasedir,
".project")):
1826 oldprojdir = projbasedir
1827 projbasedir = os.path.normpath(
1828 os.path.join(projbasedir, os.pardir))
1831 if oldprojdir == projbasedir:
1835 if not os.path.exists(destdir):
1836 os.makedirs(destdir)
1838 from xml.etree
import ElementTree
as ET
1839 t = ET.parse(os.path.join(projbasedir,
".project"))
1840 projectName = t.find(
"name").text
1843 destfile =
"%s.launch" % self._Runnable__id
1845 destfile = os.path.join(destdir, destfile)
1847 if self.options.strip():
1851 tempfile = args.pop()
1852 optsfile = destfile + os.path.splitext(tempfile)[1]
1853 shutil.copyfile(tempfile, optsfile)
1854 args.append(optsfile)
1857 from xml.sax.saxutils
import quoteattr
1861 data[
"environment"] =
"\n".join([
1862 '<mapEntry key=%s value=%s/>' % (quoteattr(k), quoteattr(v))
1863 for k, v
in os.environ.iteritems()
1864 if k
not in (
'MAKEOVERRIDES',
'MAKEFLAGS',
'MAKELEVEL')
1867 data[
"exec"] =
which(prog)
or prog
1868 if os.path.basename(data[
"exec"]).lower().startswith(
"python"):
1870 data[
"stopAtMain"] =
"false" 1872 data[
"stopAtMain"] =
"true" 1874 data[
"args"] =
" ".join(
map(rationalizepath, args))
1876 data[
"args"] =
" ".join(
1877 [
"/debugexe"] +
map(rationalizepath, [data[
"exec"]] + args))
1878 data[
"exec"] =
which(
"vcexpress.exe")
1881 data[
"workdir"] = os.getcwd()
1885 data[
"workdir"] = destdir
1887 data[
"project"] = projectName.strip()
1890 xml_template =
u"""<?xml version="1.0" encoding="UTF-8" standalone="no"?> 1891 <launchConfiguration type="org.eclipse.cdt.launch.applicationLaunchType"> 1892 <booleanAttribute key="org.eclipse.cdt.debug.mi.core.AUTO_SOLIB" value="true"/> 1893 <listAttribute key="org.eclipse.cdt.debug.mi.core.AUTO_SOLIB_LIST"/> 1894 <stringAttribute key="org.eclipse.cdt.debug.mi.core.DEBUG_NAME" value="gdb"/> 1895 <stringAttribute key="org.eclipse.cdt.debug.mi.core.GDB_INIT" value=".gdbinit"/> 1896 <listAttribute key="org.eclipse.cdt.debug.mi.core.SOLIB_PATH"/> 1897 <booleanAttribute key="org.eclipse.cdt.debug.mi.core.STOP_ON_SOLIB_EVENTS" value="false"/> 1898 <booleanAttribute key="org.eclipse.cdt.debug.mi.core.breakpointsFullPath" value="false"/> 1899 <stringAttribute key="org.eclipse.cdt.debug.mi.core.commandFactory" value="org.eclipse.cdt.debug.mi.core.standardCommandFactory"/> 1900 <stringAttribute key="org.eclipse.cdt.debug.mi.core.protocol" value="mi"/> 1901 <booleanAttribute key="org.eclipse.cdt.debug.mi.core.verboseMode" value="false"/> 1902 <intAttribute key="org.eclipse.cdt.launch.ATTR_BUILD_BEFORE_LAUNCH_ATTR" value="0"/> 1903 <stringAttribute key="org.eclipse.cdt.launch.COREFILE_PATH" value=""/> 1904 <stringAttribute key="org.eclipse.cdt.launch.DEBUGGER_ID" value="org.eclipse.cdt.debug.mi.core.CDebuggerNew"/> 1905 <stringAttribute key="org.eclipse.cdt.launch.DEBUGGER_REGISTER_GROUPS" value=""/> 1906 <stringAttribute key="org.eclipse.cdt.launch.DEBUGGER_START_MODE" value="run"/> 1907 <booleanAttribute key="org.eclipse.cdt.launch.DEBUGGER_STOP_AT_MAIN" value="%(stopAtMain)s"/> 1908 <stringAttribute key="org.eclipse.cdt.launch.DEBUGGER_STOP_AT_MAIN_SYMBOL" value="main"/> 1909 <booleanAttribute key="org.eclipse.cdt.launch.ENABLE_REGISTER_BOOKKEEPING" value="false"/> 1910 <booleanAttribute key="org.eclipse.cdt.launch.ENABLE_VARIABLE_BOOKKEEPING" value="false"/> 1911 <stringAttribute key="org.eclipse.cdt.launch.FORMAT" value="<?xml version="1.0" encoding="UTF-8" standalone="no"?><contentList/>"/> 1912 <stringAttribute key="org.eclipse.cdt.launch.GLOBAL_VARIABLES" value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <globalVariableList/> "/> 1913 <stringAttribute key="org.eclipse.cdt.launch.MEMORY_BLOCKS" value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <memoryBlockExpressionList/> "/> 1914 <stringAttribute key="org.eclipse.cdt.launch.PROGRAM_ARGUMENTS" value="%(args)s"/> 1915 <stringAttribute key="org.eclipse.cdt.launch.PROGRAM_NAME" value="%(exec)s"/> 1916 <stringAttribute key="org.eclipse.cdt.launch.PROJECT_ATTR" value="%(project)s"/> 1917 <stringAttribute key="org.eclipse.cdt.launch.PROJECT_BUILD_CONFIG_ID_ATTR" value=""/> 1918 <stringAttribute key="org.eclipse.cdt.launch.WORKING_DIRECTORY" value="%(workdir)s"/> 1919 <booleanAttribute key="org.eclipse.cdt.launch.ui.ApplicationCDebuggerTab.DEFAULTS_SET" value="true"/> 1920 <booleanAttribute key="org.eclipse.cdt.launch.use_terminal" value="true"/> 1921 <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS"> 1922 <listEntry value="/%(project)s"/> 1924 <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES"> 1925 <listEntry value="4"/> 1927 <booleanAttribute key="org.eclipse.debug.core.appendEnvironmentVariables" value="false"/> 1928 <mapAttribute key="org.eclipse.debug.core.environmentVariables"> 1931 <mapAttribute key="org.eclipse.debug.core.preferred_launchers"> 1932 <mapEntry key="[debug]" value="org.eclipse.cdt.cdi.launch.localCLaunch"/> 1934 <listAttribute key="org.eclipse.debug.ui.favoriteGroups"> 1935 <listEntry value="org.eclipse.debug.ui.launchGroup.debug"/> 1937 </launchConfiguration> 1942 data[k] = codecs.decode(data[k],
'utf-8')
1943 xml = xml_template % data
1946 codecs.open(destfile,
"w", encoding=
'utf-8').write(xml)
1948 print 'WARNING: problem generating Eclipse launcher' 1955 import simplejson
as json
1959 """An 'HTMLResultStream' writes its output to a set of HTML files. 1961 The argument 'dir' is used to select the destination directory for the HTML 1963 The destination directory may already contain the report from a previous run 1964 (for example of a different package), in which case it will be extended to 1965 include the new data. 1968 qm.fields.TextField(
1970 title=
"Destination Directory",
1971 description=
"""The name of the directory. 1973 All results will be written to the directory indicated.""",
1979 """Prepare the destination directory. 1981 Creates the destination directory and store in it some preliminary 1982 annotations and the static files found in the template directory 1985 ResultStream.__init__(self, arguments, **args)
1990 templateDir = os.path.join(os.path.dirname(__file__),
"html_report")
1991 if not os.path.isdir(self.dir):
1992 os.makedirs(self.dir)
1994 for f
in os.listdir(templateDir):
1995 src = os.path.join(templateDir, f)
1996 dst = os.path.join(self.dir, f)
1997 if not os.path.isdir(src)
and not os.path.exists(dst):
1998 shutil.copy(src, dst)
2000 if "CMTCONFIG" in os.environ:
2006 """Helper function to extend the global summary file in the destination 2013 ids = set([i[
"id"]
for i
in self.
_summary])
2014 newSummary = [i
for i
in oldSummary
if i[
"id"]
not in ids]
2016 json.dump(newSummary, open(self.
_summaryFile,
"w"), sort_keys=
True)
2019 """Writes the annotation to the annotation file. 2020 If the key is already present with a different value, the value becomes 2021 a list and the new value is appended to it, except for start_time and 2030 key, value =
map(str, [key, value])
2031 if key ==
"qmtest.run.start_time":
2036 if key
not in annotations:
2037 annotations[key] = value
2038 if "qmtest.run.end_time" in annotations:
2039 del annotations[
"qmtest.run.end_time"]
2042 if key
in annotations:
2043 old = annotations[key]
2044 if type(old)
is list:
2045 if value
not in old:
2046 annotations[key].append(value)
2048 annotations[key] = [old, value]
2050 annotations[key] = value
2056 """Prepare the test result directory in the destination directory storing 2057 into it the result fields. 2058 A summary of the test result is stored both in a file in the test directory 2059 and in the global summary file. 2062 summary[
"id"] = result.GetId()
2063 summary[
"outcome"] = result.GetOutcome()
2064 summary[
"cause"] = result.GetCause()
2065 summary[
"fields"] = result.keys()
2066 summary[
"fields"].sort()
2069 for f
in [
"id",
"outcome",
"cause"]:
2070 summary[f] = str(summary[f])
2071 summary[
"fields"] =
map(str, summary[
"fields"])
2073 self._summary.append(summary)
2079 testOutDir = os.path.join(self.dir, summary[
"id"])
2080 if not os.path.isdir(testOutDir):
2081 os.makedirs(testOutDir)
2084 open(os.path.join(testOutDir,
"summary.json"),
"w"),
2086 for f
in summary[
"fields"]:
2087 open(os.path.join(testOutDir, f),
"w").write(result[f])
2096 class XMLResultStream(ResultStream):
2097 """An 'XMLResultStream' writes its output to a Ctest XML file. 2099 The argument 'dir' is used to select the destination file for the XML 2101 The destination directory may already contain the report from a previous run 2102 (for example of a different package), in which case it will be overrided to 2106 qm.fields.TextField(
2108 title=
"Destination Directory",
2109 description=
"""The name of the directory. 2111 All results will be written to the directory indicated.""",
2114 qm.fields.TextField(
2116 title=
"Output File Prefix",
2117 description=
"""The output file name will be the specified prefix 2118 followed by 'Test.xml' (CTest convention).""",
2124 """Prepare the destination directory. 2126 Creates the destination directory and store in it some preliminary 2129 ResultStream.__init__(self, arguments, **args)
2131 self.
_xmlFile = os.path.join(self.dir, self.prefix +
'Test.xml')
2137 if not os.path.isfile(self.
_xmlFile):
2139 if not os.path.exists(os.path.dirname(self.
_xmlFile)):
2140 os.makedirs(os.path.dirname(self.
_xmlFile))
2142 newdataset = ET.Element(
"newdataset")
2148 newdataset = self._tree.getroot()
2155 for site
in newdataset.getiterator():
2157 if site.get(
"OSPlatform") == os.uname()[4]:
2166 import multiprocessing
2168 "BuildName": os.getenv(
"CMTCONFIG"),
2169 "Name": os.uname()[1],
2170 "Generator":
"QMTest " + qm.version,
2171 "OSName": os.uname()[0],
2172 "Hostname": socket.gethostname(),
2173 "OSRelease": os.uname()[2],
2174 "OSVersion": os.uname()[3],
2175 "OSPlatform": os.uname()[4],
2176 "Is64Bits":
"unknown",
2177 "VendorString":
"unknown",
2178 "VendorID":
"unknown",
2179 "FamilyID":
"unknown",
2180 "ModelID":
"unknown",
2181 "ProcessorCacheSize":
"unknown",
2182 "NumberOfLogicalCPU": str(multiprocessing.cpu_count()),
2183 "NumberOfPhysicalCPU":
"0",
2184 "TotalVirtualMemory":
"0",
2185 "TotalPhysicalMemory":
"0",
2186 "LogicalProcessorsPerPhysical":
"0",
2187 "ProcessorClockFrequency":
"0",
2189 self.
_site = ET.SubElement(newdataset,
"Site", attrib)
2208 self.
_Testing = self._site.find(
"Testing")
2211 self.
_TestList = self._Testing.find(
"TestList")
2216 # Add some non-QMTest attributes 2217 if "CMTCONFIG" in os.environ: 2218 self.WriteAnnotation("cmt.cmtconfig", os.environ["CMTCONFIG"]) 2220 self.WriteAnnotation("hostname", socket.gethostname()) 2224 if key ==
"qmtest.run.start_time":
2225 if self._site.get(
"qmtest.run.start_time")
is not None:
2227 self._site.set(str(key), str(value))
2230 """Prepare the test result directory in the destination directory storing 2231 into it the result fields. 2232 A summary of the test result is stored both in a file in the test directory 2233 and in the global summary file. 2236 summary[
"id"] = result.GetId()
2237 summary[
"outcome"] = result.GetOutcome()
2238 summary[
"cause"] = result.GetCause()
2239 summary[
"fields"] = result.keys()
2240 summary[
"fields"].sort()
2243 for f
in [
"id",
"outcome",
"cause"]:
2244 summary[f] = str(summary[f])
2245 summary[
"fields"] =
map(str, summary[
"fields"])
2250 if "qmtest.start_time" in summary[
"fields"]:
2251 haveStartDate =
True 2253 haveStartDate =
False 2254 if "qmtest.end_time" in summary[
"fields"]:
2262 time.strptime(result[
"qmtest.start_time"],
2263 "%Y-%m-%dT%H:%M:%SZ"))
2264 if self._StartTestTime.text
is None:
2265 self._StartDateTime.text = time.strftime(
2266 "%b %d %H:%M %Z", time.localtime(self.
_startTime))
2267 self._StartTestTime.text = str(self.
_startTime)
2268 self._site.set(
"BuildStamp", result[
"qmtest.start_time"])
2273 time.strptime(result[
"qmtest.end_time"],
"%Y-%m-%dT%H:%M:%SZ"))
2276 tl = ET.Element(
"Test")
2277 tl.text = summary[
"id"]
2278 self._TestList.insert(0, tl)
2281 Test = ET.Element(
"Test")
2282 if summary[
"outcome"] ==
"PASS":
2283 Test.set(
"Status",
"passed")
2284 elif summary[
"outcome"] ==
"FAIL":
2285 Test.set(
"Status",
"failed")
2286 elif summary[
"outcome"] ==
"SKIPPED" or summary[
2287 "outcome"] ==
"UNTESTED":
2288 Test.set(
"Status",
"skipped")
2289 elif summary[
"outcome"] ==
"ERROR":
2290 Test.set(
"Status",
"failed")
2291 Name = ET.SubElement(
2295 Name.text = summary[
"id"]
2296 Results = ET.SubElement(Test,
"Results")
2299 self._Testing.insert(3, Test)
2301 if haveStartDate
and haveEndDate:
2304 testduration = str(delta)
2305 Testduration = ET.SubElement(Results,
"NamedMeasurement")
2306 Testduration.set(
"name",
"Execution Time")
2307 Testduration.set(
"type",
"numeric/float")
2308 value = ET.SubElement(Testduration,
"Value")
2309 value.text = testduration
2312 for n
in (
"qmtest.end_time",
"qmtest.start_time",
"qmtest.cause",
2314 if n
in summary[
"fields"]:
2315 summary[
"fields"].remove(n)
2319 if "ExecTest.exit_code" in summary[
"fields"]:
2320 summary[
"fields"].remove(
"ExecTest.exit_code")
2321 ExitCode = ET.SubElement(Results,
"NamedMeasurement")
2322 ExitCode.set(
"name",
"exit_code")
2323 ExitCode.set(
"type",
"numeric/integer")
2324 value = ET.SubElement(ExitCode,
"Value")
2326 result[
"ExecTest.exit_code"])
2328 TestStartTime = ET.SubElement(Results,
"NamedMeasurement")
2329 TestStartTime.set(
"name",
"Start_Time")
2330 TestStartTime.set(
"type",
"String")
2331 value = ET.SubElement(TestStartTime,
"Value")
2334 time.strftime(
"%b %d %H:%M %Z %Y",
2339 TestEndTime = ET.SubElement(Results,
"NamedMeasurement")
2340 TestEndTime.set(
"name",
"End_Time")
2341 TestEndTime.set(
"type",
"String")
2342 value = ET.SubElement(TestEndTime,
"Value")
2345 time.strftime(
"%b %d %H:%M %Z %Y",
2350 if summary[
"cause"]:
2351 FailureCause = ET.SubElement(Results,
"NamedMeasurement")
2352 FailureCause.set(
"name",
"Cause")
2353 FailureCause.set(
"type",
"String")
2354 value = ET.SubElement(FailureCause,
"Value")
2359 for field
in summary[
"fields"]:
2360 fields[field] = ET.SubElement(Results,
"NamedMeasurement")
2361 fields[field].set(
"type",
"String")
2362 fields[field].set(
"name", field)
2363 value = ET.SubElement(fields[field],
"Value")
2365 if "<pre>" in result[field][0:6]:
2370 if result.has_key(
"ExecTest.stdout"):
2371 Measurement = ET.SubElement(Results,
"Measurement")
2372 value = ET.SubElement(Measurement,
"Value")
2373 if "<pre>" in result[
"ExecTest.stdout"][0:6]:
2375 result[
"ExecTest.stdout"][5:-6])
2378 result[
"ExecTest.stdout"])
2382 self._tree.write(self.
_xmlFile,
"utf-8")
2387 self._EndTestTime.text = str(self.
_endTime)
2388 self._EndDateTime.text = time.strftime(
"%b %d %H:%M %Z",
2396 self._ElapsedMinutes.text = str(delta / 60)
2400 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)
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)
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)