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
40 return timedelta.days*86400 + timedelta.seconds + timedelta.microseconds/1000000
44 from qm.test.classes.command
import ExecTestBase
45 from qm.test.result_stream
import ResultStream
52 if sys.platform ==
"win32":
55 from threading
import *
73 Class to changes the environment temporarily. 75 def __init__(self, orig = os.environ, keep_same = False):
77 Create a temporary environment on top of the one specified 78 (it can be another TemporaryEnvironment instance). 87 Set an environment variable recording the previous value. 99 Get an environment variable. 100 Needed to provide the same interface as os.environ. 106 Unset an environment variable. 107 Needed to provide the same interface as os.environ. 109 if key
not in self.
env :
116 Return the list of defined environment variables. 117 Needed to provide the same interface as os.environ. 119 return self.env.keys()
123 Return the list of (name,value) pairs for the defined environment variables. 124 Needed to provide the same interface as os.environ. 126 return self.env.items()
131 Needed to provide the same interface as os.environ. 133 return key
in self.
env 137 Revert all the changes done to the original environment. 139 for key,value
in self.old_values.items():
143 self.
env[key] = value
148 Revert the changes on destruction. 155 Generate a shell script to reproduce the changes in the environment. 157 shells = [
'csh',
'sh',
'bat' ]
158 if shell_type
not in shells:
159 raise RuntimeError(
"Shell type '%s' unknown. Available: %s"%(shell_type,shells))
161 for key,value
in self.old_values.items():
162 if key
not in self.
env:
164 if shell_type ==
'csh':
165 out +=
'unsetenv %s\n'%key
166 elif shell_type ==
'sh':
167 out +=
'unset %s\n'%key
168 elif shell_type ==
'bat':
169 out +=
'set %s=\n'%key
172 if shell_type ==
'csh':
173 out +=
'setenv %s "%s"\n'%(key,self.
env[key])
174 elif shell_type ==
'sh':
175 out +=
'export %s="%s"\n'%(key,self.
env[key])
176 elif shell_type ==
'bat':
177 out +=
'set %s=%s\n'%(key,self.
env[key])
181 """Small class for temporary directories. 182 When instantiated, it creates a temporary directory and the instance 183 behaves as the string containing the directory name. 184 When the instance goes out of scope, it removes all the content of 185 the temporary directory (automatic clean-up). 202 shutil.rmtree(self.
name)
205 return getattr(self.
name,attr)
208 """Small class for temporary files. 209 When instantiated, it creates a temporary directory and the instance 210 behaves as the string containing the directory name. 211 When the instance goes out of scope, it removes all the content of 212 the temporary directory (automatic clean-up). 214 def __init__(self, suffix='', prefix='tmp', dir=None, text=False, keep = False):
219 self._fd, self.
name = tempfile.mkstemp(suffix,prefix,dir,text)
220 self.
file = os.fdopen(self._fd,
"r+")
232 return getattr(self.
file,attr)
235 """Small wrapper to call CMT. 244 if type(args)
is str:
246 cmd =
"cmt %s"%command
254 result = os.popen4(cmd)[1].
read()
260 return lambda args=[]: self.
_run_cmt(attr, args)
263 """Returns a dictionary containing the runtime environment produced by CMT. 264 If a dictionary is passed a modified instance of it is returned. 268 for l
in self.setup(
"-csh").splitlines():
270 if l.startswith(
"setenv"):
271 dummy,name,value = l.split(
None,3)
272 env[name] = value.strip(
'"')
273 elif l.startswith(
"unsetenv"):
274 dummy,name = l.split(
None,2)
279 r = self.show([
"macro",k])
280 if r.find(
"CMT> Error: symbol not found") >= 0:
283 return self.show([
"macro_value",k]).strip()
291 Locates an executable in the executables path ($PATH) and returns the full 292 path to it. An application is looked for with or without the '.exe' suffix. 293 If the executable cannot be found, None is returned 295 if os.path.isabs(executable):
296 if not os.path.exists(executable):
297 if executable.endswith(
'.exe'):
298 if os.path.exists(executable[:-4]):
299 return executable[:-4]
301 for d
in os.environ.get(
"PATH").split(os.pathsep):
302 fullpath = os.path.join(d, executable)
303 if os.path.exists(fullpath):
305 if executable.endswith(
'.exe'):
306 return which(executable[:-4])
310 np = os.path.normpath(os.path.expandvars(p))
311 if os.path.exists(np):
312 p = os.path.realpath(np)
329 _illegal_xml_chars_RE = re.compile(
u'[\x00-\x08\x0b\x0c\x0e-\x1F\uD800-\uDFFF\uFFFE\uFFFF]')
332 "Return the hex string " 333 return "".join(
map(hexConvert,match.group()))
336 return hex(ord(char))
338 return _illegal_xml_chars_RE.sub(hexreplace, val)
341 """Filter out characters that are illegal in XML. 342 Looks for any character in val that is not allowed in XML 343 and replaces it with replacement ('?' by default). 346 return _illegal_xml_chars_RE.sub(replacement, val)
352 """Basic implementation of an option validator for Gaudi tests. 353 This implementation is based on the standard (LCG) validation functions 362 """Validate the output of the program. 364 'stdout' -- A string containing the data written to the standard output 367 'stderr' -- A string containing the data written to the standard error 370 'result' -- A 'Result' object. It may be used to annotate 371 the outcome according to the content of stderr. 373 returns -- A list of strings giving causes of failure.""" 378 causes.append(self.
cause)
384 """Compare 's1' and 's2', ignoring line endings. 390 returns -- True if 's1' and 's2' are the same, ignoring 391 differences in line endings.""" 397 to_ignore = re.compile(
r'Warning in <TInterpreter::ReadRootmapFile>: .* is already in .*')
398 keep_line =
lambda l:
not to_ignore.match(l)
399 return filter(keep_line, s1.splitlines()) == filter(keep_line, s2.splitlines())
401 return s1.splitlines() == s2.splitlines()
404 """ Base class for a callable that takes a file and returns a modified 409 if hasattr(input,
"__iter__"):
413 lines = input.splitlines()
418 if l: output.append(l)
419 if mergeback: output =
'\n'.join(output)
443 if line.find(s) >= 0:
return None 445 if r.search(line):
return None 455 if self.
start in line:
458 elif self.
end in line:
467 when = re.compile(when)
470 if isinstance(rhs, RegexpReplacer):
472 res._operations = self.
_operations + rhs._operations
474 res = FilePreprocessor.__add__(self, rhs)
478 if w
is None or w.search(line):
479 line = o.sub(r, line)
484 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)?",
485 "00:00:00 1970-01-01")
487 normalizeEOL.__processLine__ =
lambda line: str(line).rstrip() +
'\n' 491 skipEmptyLines.__processLine__ =
lambda line: (line.strip()
and line)
or None 502 line = line[:(pos+self.
siglen)]
503 lst = line[(pos+self.
siglen):].split()
505 line +=
" ".join(lst)
509 normalizeExamples = maskPointers + normalizeDate
512 (
"TIMER.TIMER",
r"\s+[+-]?[0-9]+[0-9.]*",
" 0"),
513 (
"release all pending",
r"^.*/([^/]*:.*)",
r"\1"),
514 (
"0x########",
r"\[.*/([^/]*.*)\]",
r"[\1]"),
515 (
"^#.*file",
r"file '.*[/\\]([^/\\]*)$",
r"file '\1"),
516 (
"^JobOptionsSvc.*options successfully read in from",
r"read in from .*[/\\]([^/\\]*)$",
r"file \1"),
518 (
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}",
"00000000-0000-0000-0000-000000000000"),
520 (
"ServiceLocatorHelper::",
"ServiceLocatorHelper::(create|locate)Service",
"ServiceLocatorHelper::service"),
522 (
None,
r"e([-+])0([0-9][0-9])",
r"e\1\2"),
524 (
None,
r'Service reference count check:',
r'Looping over all active services...'),
526 (
None,
r"Property(.*)'ErrorCount':",
r"Property\1'ErrorCounter':"),
531 "JobOptionsSvc INFO # ",
532 "JobOptionsSvc WARNING # ",
535 "This machine has a speed",
538 "ToolSvc.Sequenc... INFO",
539 "DataListenerSvc INFO XML written to file:",
540 "[INFO]",
"[WARNING]",
541 "DEBUG No writable file catalog found which contains FID:",
543 "DEBUG Service base class initialized successfully",
544 "DEBUG Incident timing:",
545 "INFO 'CnvServices':[",
549 'EventLoopMgr SUCCESS Event Number = ',
550 'EventLoopMgr SUCCESS ---> Loop Finished',
552 r"^JobOptionsSvc INFO *$",
554 r"(Always|SUCCESS)\s*(Root f|[^ ]* F)ile version:",
555 r"0x[0-9a-fA-F#]+ *Algorithm::sysInitialize\(\) *\[",
556 r"0x[0-9a-fA-F#]* *__gxx_personality_v0 *\[",
557 r"File '.*.xml' does not exist",
558 r"INFO Refer to dataset .* by its file ID:",
559 r"INFO Referring to dataset .* by its file ID:",
560 r"INFO Disconnect from dataset",
561 r"INFO Disconnected from dataset",
562 r"INFO Disconnected data IO:",
563 r"IncidentSvc\s*(DEBUG (Adding|Removing)|VERBOSE Calling)",
565 r"^StatusCodeSvc.*listing all unchecked return codes:",
566 r"^StatusCodeSvc\s*INFO\s*$",
567 r"Num\s*\|\s*Function\s*\|\s*Source Library",
570 r"ERROR Failed to modify file: .* Errno=2 No such file or directory",
572 r"^ +[0-9]+ \|.*ROOT",
573 r"^ +[0-9]+ \|.*\|.*Dict",
575 r"StatusCodeSvc.*all StatusCode instances where checked",
577 r"EventLoopMgr.*---> Loop Finished",
581 r"SUCCESS\s*Booked \d+ Histogram\(s\)",
588 r'Warning in <TInterpreter::ReadRootmapFile>: .* is already in .*',
591 normalizeExamples = (lineSkipper + normalizeExamples + skipEmptyLines +
592 normalizeEOL +
LineSorter(
"Services to release : "))
595 def __init__(self, reffile, cause, result_key, preproc = normalizeExamples):
602 if os.path.isfile(self.
reffile):
603 orig = open(self.
reffile).xreadlines()
609 new = stdout.splitlines()
613 diffs = difflib.ndiff(orig,new,charjunk=difflib.IS_CHARACTER_JUNK)
614 filterdiffs =
map(
lambda x: x.strip(),filter(
lambda x: x[0] !=
" ",diffs))
617 result[self.
result_key] = result.Quote(
"\n".join(filterdiffs))
621 +) standard output of the test""")
622 causes.append(self.
cause)
629 def findReferenceBlock(reference, stdout, result, causes, signature_offset=0, signature=None,
632 Given a block of text, tries to find it in the output. 633 The block had to be identified by a signature line. By default, the first 634 line is used as signature, or the line pointed to by signature_offset. If 635 signature_offset points outside the block, a signature line can be passed as 636 signature argument. Note: if 'signature' is None (the default), a negative 637 signature_offset is interpreted as index in a list (e.g. -1 means the last 638 line), otherwise the it is interpreted as the number of lines before the 639 first one of the block the signature must appear. 640 The parameter 'id' allow to distinguish between different calls to this 641 function in the same validation code. 644 reflines = filter(
None,
map(
lambda s: s.rstrip(), reference.splitlines()))
646 raise RuntimeError(
"Empty (or null) reference")
648 outlines = filter(
None,
map(
lambda s: s.rstrip(), stdout.splitlines()))
650 res_field =
"GaudiTest.RefBlock" 652 res_field +=
"_%s" % id
654 if signature
is None:
655 if signature_offset < 0:
656 signature_offset = len(reference)+signature_offset
657 signature = reflines[signature_offset]
660 pos = outlines.index(signature)
661 outlines = outlines[pos-signature_offset:pos+len(reflines)-signature_offset]
662 if reflines != outlines:
663 msg =
"standard output" 665 if not msg
in causes:
667 result[res_field +
".observed"] = result.Quote(
"\n".join(outlines))
669 causes.append(
"missing signature")
670 result[res_field +
".signature"] = result.Quote(signature)
671 if len(reflines) > 1
or signature != reflines[0]:
672 result[res_field +
".expected"] = result.Quote(
"\n".join(reflines))
678 Count the number of messages with required severity (by default ERROR and FATAL) 679 and check if their numbers match the expected ones (0 by default). 680 The dictionary "expected" can be used to tune the number of errors and fatals 681 allowed, or to limit the number of expected warnings etc. 683 stdout = kwargs[
"stdout"]
684 result = kwargs[
"result"]
685 causes = kwargs[
"causes"]
692 outlines = stdout.splitlines()
693 from math
import log10
694 fmt =
"%%%dd - %%s" % (int(log10(len(outlines))+1))
700 if len(words) >= 2
and words[1]
in errors:
701 errors[words[1]].append(fmt%(linecount,l.rstrip()))
704 if len(errors[e]) != expected[e]:
705 causes.append(
'%s(%d)'%(e,len(errors[e])))
706 result[
"GaudiTest.lines.%s"%e] = result.Quote(
'\n'.join(errors[e]))
707 result[
"GaudiTest.lines.%s.expected#"%e] = result.Quote(str(expected[e]))
714 Parse the TTree summary table in lines, starting from pos. 715 Returns a tuple with the dictionary with the digested informations and the 716 position of the first line after the summary. 722 splitcols =
lambda l: [ f.strip()
for f
in l.strip(
"*\n").split(
':',2) ]
725 cols = splitcols(ll[0])
726 r[
"Name"], r[
"Title"] = cols[1:]
728 cols = splitcols(ll[1])
729 r[
"Entries"] = int(cols[1])
731 sizes = cols[2].split()
732 r[
"Total size"] = int(sizes[2])
733 if sizes[-1] ==
"memory":
736 r[
"File size"] = int(sizes[-1])
738 cols = splitcols(ll[2])
739 sizes = cols[2].split()
740 if cols[0] ==
"Baskets":
741 r[
"Baskets"] = int(cols[1])
742 r[
"Basket size"] = int(sizes[2])
743 r[
"Compression"] = float(sizes[-1])
746 if i < (count - 3)
and lines[i].startswith(
"*Tree"):
747 result = parseblock(lines[i:i+3])
748 result[
"Branches"] = {}
750 while i < (count - 3)
and lines[i].startswith(
"*Br"):
751 if i < (count - 2)
and lines[i].startswith(
"*Branch "):
755 branch = parseblock(lines[i:i+3])
756 result[
"Branches"][branch[
"Name"]] = branch
763 Scan stdout to find ROOT TTree summaries and digest them. 765 stars = re.compile(
r"^\*+$")
766 outlines = stdout.splitlines()
767 nlines = len(outlines)
773 while i < nlines
and not stars.match(outlines[i]):
778 trees[tree[
"Name"]] = tree
784 Check that all the keys in reference are in to_check too, with the same value. 785 If the value is a dict, the function is called recursively. to_check can 786 contain more keys than reference, that will not be tested. 787 The function returns at the first difference found. 792 ignore_re = re.compile(ignore)
793 keys = [ key
for key
in reference
if not ignore_re.match(key) ]
795 keys = reference.keys()
799 if (
type(reference[k])
is dict)
and (
type(to_check[k])
is dict):
801 failed = fail_keys =
cmpTreesDicts(reference[k], to_check[k], ignore)
804 failed = to_check[k] != reference[k]
809 fail_keys.insert(0, k)
819 if c
is None or r
is None:
821 return (fail_path, r, c)
824 h_count_re = re.compile(
r"^(.*)SUCCESS\s+Booked (\d+) Histogram\(s\) :\s+(.*)")
828 Extract the histograms infos from the lines starting at pos. 829 Returns the position of the first line after the summary block. 832 h_table_head = re.compile(
r'SUCCESS\s+List of booked (1D|2D|3D|1D profile|2D profile) histograms in directory\s+"(\w*)"')
833 h_short_summ = re.compile(
r"ID=([^\"]+)\s+\"([^\"]+)\"\s+(.*)")
838 m = h_count_re.search(lines[pos])
839 name = m.group(1).strip()
840 total = int(m.group(2))
842 for k, v
in [ x.split(
"=")
for x
in m.group(3).split() ]:
845 header[
"Total"] = total
849 m = h_table_head.search(lines[pos])
852 t = t.replace(
" profile",
"Prof")
859 if l.startswith(
" | ID"):
861 titles = [ x.strip()
for x
in l.split(
"|")][1:]
863 while pos < nlines
and lines[pos].startswith(
" |"):
865 values = [ x.strip()
for x
in l.split(
"|")][1:]
867 for i
in range(len(titles)):
868 hcont[titles[i]] = values[i]
869 cont[hcont[
"ID"]] = hcont
871 elif l.startswith(
" ID="):
872 while pos < nlines
and lines[pos].startswith(
" ID="):
873 values = [ x.strip()
for x
in h_short_summ.search(lines[pos]).groups() ]
874 cont[values[0]] = values
877 raise RuntimeError(
"Cannot understand line %d: '%s'" % (pos, l))
881 summ[d][
"header"] = header
886 summ[name] = {
"header": header}
891 Scan stdout to find ROOT TTree summaries and digest them. 893 outlines = stdout.splitlines()
894 nlines = len(outlines) - 1
902 match = h_count_re.search(outlines[pos])
903 while pos < nlines
and not match:
905 match = h_count_re.search(outlines[pos])
908 summaries.update(summ)
913 """Create a new 'Filter'. 915 'input' -- The string containing the input to provide to the 918 'timeout' -- As for 'TimeoutExecutable.__init__'.""" 920 super(GaudiFilterExecutable, self).
__init__(input, timeout)
927 tmpf = tempfile.mkstemp()
932 """Copied from TimeoutExecutable to allow the re-implementation of 935 if sys.platform ==
"win32":
946 """Code copied from both FilterExecutable and TimeoutExecutable. 950 self._ClosePipeEnd(self._stdin_pipe[0])
951 if self._stdout_pipe:
952 self._ClosePipeEnd(self._stdout_pipe[1])
953 if self._stderr_pipe:
954 self._ClosePipeEnd(self._stderr_pipe[1])
962 super(qm.executable.TimeoutExecutable, self).
_HandleChild()
969 child_pid = self._GetChildPID()
971 os.setpgid(child_pid, child_pid)
999 os.setpgid(0, child_pid)
1008 max_fds = os.sysconf(
"SC_OPEN_MAX")
1011 for fd
in xrange(max_fds):
1022 if sys.platform ==
"linux2":
1024 os.path.join(
"/proc", str(child_pid),
"exe"),
1026 "-batch",
"-n",
"-x",
1027 "'%s'" % os.path.join(os.path.dirname(__file__),
"stack-trace.gdb")]
1030 o = os.popen(
" ".join(cmd)).
read()
1035 os.kill(0, signal.SIGKILL)
1038 select.select ([], [], [])
1043 elif self.
__timeout >= 0
and sys.platform ==
"win32":
1046 self.__monitor_thread.start()
1048 if sys.platform ==
"win32":
1051 """Code copied from FilterExecutable. 1052 Kill the child if the timeout expires. 1054 This function is run in the monitoring thread.""" 1062 result = win32event.WaitForSingleObject(self._GetChildPID(),
1065 if result == win32con.WAIT_TIMEOUT:
1072 """Standard Gaudi test. 1075 qm.fields.TextField(
1079 description=
"""The path to the program. 1081 This field indicates the path to the program. If it is not 1082 an absolute path, the value of the 'PATH' environment 1083 variable will be used to search for the program. 1084 If not specified, $GAUDIEXE or Gaudi.exe are used. 1087 qm.fields.SetField(qm.fields.TextField(
1089 title=
"Argument List",
1090 description=
"""The command-line arguments. 1092 If this field is left blank, the program is run without any 1095 Use this field to specify the option files. 1097 An implicit 0th argument (the path to the program) is added 1100 qm.fields.TextField(
1103 description=
"""Options to be passed to the application. 1105 This field allows to pass a list of options to the main program 1106 without the need of a separate option file. 1108 The content of the field is written to a temporary file which name 1109 is passed the the application as last argument (appended to the 1110 field "Argument List". 1116 qm.fields.TextField(
1118 title=
"Working Directory",
1119 description=
"""Path to the working directory. 1121 If this field is left blank, the program will be run from the qmtest 1122 directory, otherwise from the directory specified.""",
1125 qm.fields.TextField(
1127 title=
"Reference Output",
1128 description=
"""Path to the file containing the reference output. 1130 If this field is left blank, any standard output will be considered 1133 If the reference file is specified, any output on standard error is 1136 qm.fields.TextField(
1137 name=
"error_reference",
1138 title=
"Reference for standard error",
1139 description=
"""Path to the file containing the reference for the standard error. 1141 If this field is left blank, any standard output will be considered 1144 If the reference file is specified, any output on standard error is 1147 qm.fields.SetField(qm.fields.TextField(
1148 name =
"unsupported_platforms",
1149 title =
"Unsupported Platforms",
1150 description =
"""Platform on which the test must not be run. 1152 List of regular expressions identifying the platforms on which the 1153 test is not run and the result is set to UNTESTED.""" 1156 qm.fields.TextField(
1158 title =
"Validator",
1159 description =
"""Function to validate the output of the test. 1161 If defined, the function is used to validate the products of the 1163 The function is called passing as arguments: 1164 self: the test class instance 1165 stdout: the standard output of the executed test 1166 stderr: the standard error of the executed test 1167 result: the Result objects to fill with messages 1168 The function must return a list of causes for the failure. 1169 If specified, overrides standard output, standard error and 1177 qm.fields.BooleanField(
1178 name =
"use_temp_dir",
1179 title =
"Use temporary directory",
1180 description =
"""Use temporary directory. 1182 If set to true, use a temporary directory as working directory. 1184 default_value=
"false" 1187 qm.fields.IntegerField(
1189 title =
"Expected signal",
1190 description =
"""Expect termination by signal.""",
1197 unsupported = [ re.compile(x)
1198 for x
in [ str(y).strip()
1199 for y
in self.unsupported_platforms ]
1202 for p_re
in unsupported:
1203 if p_re.search(platform):
1204 result.SetOutcome(result.UNTESTED)
1205 result[result.CAUSE] =
'Platform not supported.' 1211 Return the platform Id defined in CMTCONFIG or SCRAM_ARCH. 1215 if "CMTCONFIG" in os.environ:
1216 arch = os.environ[
"CMTCONFIG"]
1217 elif "SCRAM_ARCH" in os.environ:
1218 arch = os.environ[
"SCRAM_ARCH"]
1223 Return True if the current platform is Windows. 1225 This function was needed because of the change in the CMTCONFIG format, 1226 from win32_vc71_dbg to i686-winxp-vc9-dbg. 1229 return "winxp" in platform
or platform.startswith(
"win")
1237 platformSplit =
lambda p: set(p.split(
'-' in p
and '-' or '_'))
1239 reference = os.path.normpath(os.path.expandvars(reffile))
1241 spec_ref = reference[:-3] + self.
GetPlatform()[0:3] + reference[-3:]
1242 if os.path.isfile(spec_ref):
1243 reference = spec_ref
1246 dirname, basename = os.path.split(reference)
1247 if not dirname: dirname =
'.' 1248 head = basename +
"." 1249 head_len = len(head)
1251 if 'do0' in platform:
1254 for f
in os.listdir(dirname):
1255 if f.startswith(head):
1256 req_plat = platformSplit(f[head_len:])
1257 if platform.issuperset(req_plat):
1258 candidates.append( (len(req_plat), f) )
1263 reference = os.path.join(dirname, candidates[-1][1])
1268 ignore =
r"Basket|.*size|Compression"):
1270 Compare the TTree summaries in stdout with the ones in trees_dict or in 1271 the reference file. By default ignore the size, compression and basket 1273 The presence of TTree summaries when none is expected is not a failure. 1275 if trees_dict
is None:
1278 if reference
and os.path.isfile(reference):
1283 from pprint
import PrettyPrinter
1284 pp = PrettyPrinter()
1286 result[
"GaudiTest.TTrees.expected"] = result.Quote(pp.pformat(trees_dict))
1288 result[
"GaudiTest.TTrees.ignore"] = result.Quote(ignore)
1293 causes.append(
"trees summaries")
1295 result[
"GaudiTest.TTrees.failure_on"] = result.Quote(msg)
1296 result[
"GaudiTest.TTrees.found"] = result.Quote(pp.pformat(trees))
1304 Compare the TTree summaries in stdout with the ones in trees_dict or in 1305 the reference file. By default ignore the size, compression and basket 1307 The presence of TTree summaries when none is expected is not a failure. 1312 if reference
and os.path.isfile(reference):
1317 from pprint
import PrettyPrinter
1318 pp = PrettyPrinter()
1320 result[
"GaudiTest.Histos.expected"] = result.Quote(pp.pformat(dict))
1322 result[
"GaudiTest.Histos.ignore"] = result.Quote(ignore)
1327 causes.append(
"histos summaries")
1329 result[
"GaudiTest.Histos.failure_on"] = result.Quote(msg)
1330 result[
"GaudiTest.Histos.found"] = result.Quote(pp.pformat(histos))
1336 Default validation action: compare standard output and error to the 1341 preproc = normalizeExamples
1345 if reference
and os.path.isfile(reference):
1346 result[
"GaudiTest.output_reference"] = reference
1349 "GaudiTest.output_diff",
1350 preproc = preproc)(stdout, result)
1358 newref = open(reference +
".new",
"w")
1360 for l
in stdout.splitlines():
1361 newref.write(l.rstrip() +
'\n')
1371 if reference
and os.path.isfile(reference):
1372 result[
"GaudiTest.error_reference"] = reference
1375 "GaudiTest.error_diff",
1376 preproc = preproc)(stderr, result)
1379 newref = open(reference +
".new",
"w")
1381 for l
in stderr.splitlines():
1382 newref.write(l.rstrip() +
'\n')
1387 "ExecTest.expected_stderr")(stderr, result)
1394 if self.validator.strip() !=
"":
1395 class CallWrapper(object):
1397 Small wrapper class to dynamically bind some default arguments 1400 def __init__(self, callable, extra_args = {}):
1404 from inspect
import getargspec
1410 def __call__(self, *args, **kwargs):
1414 kwargs = dict(kwargs)
1418 if a
not in positional
and a
not in kwargs:
1422 exported_symbols = {
"self":self,
1427 "findReferenceBlock":
1428 CallWrapper(findReferenceBlock, {
"stdout":stdout,
1431 "validateWithReference":
1437 CallWrapper(countErrorLines, {
"stdout":stdout,
1440 "checkTTreesSummaries":
1444 "checkHistosSummaries":
1450 exec self.validator
in globals(), exported_symbols
1458 Add the content of the environment to the result object. 1460 Copied from the QMTest class of COOL. 1462 vars = os.environ.keys()
1464 result[
'GaudiTest.environment'] = \
1465 result.Quote(
'\n'.join([
"%s=%s"%(v,os.environ[v])
for v
in vars]))
1467 def Run(self, context, result):
1470 'context' -- A 'Context' giving run-time parameters to the 1473 'result' -- A 'Result' object. The outcome will be 1474 'Result.PASS' when this method is called. The 'result' may be 1475 modified by this method to indicate outcomes other than 1476 'Result.PASS' or to add annotations.""" 1485 elif "GAUDIEXE" in os.environ:
1486 prog = os.environ[
"GAUDIEXE"]
1491 dummy, prog_ext = os.path.splitext(prog)
1492 if prog_ext
not in [
".exe",
".py",
".bat" ]
and self.
isWinPlatform():
1496 prog =
which(prog)
or prog
1499 args =
map(rationalizepath, self.args)
1506 if self.options.strip():
1508 if re.search(
r"from\s+Gaudi.Configuration\s+import\s+\*|from\s+Configurables\s+import", self.options):
1511 tmpfile.writelines(
"\n".join(self.options.splitlines()))
1513 args.append(tmpfile.name)
1514 result[
"GaudiTest.options"] = result.Quote(self.options)
1517 if prog_ext ==
".py":
1520 prog =
which(
"python.exe")
or "python.exe" 1522 prog =
which(
"python")
or "python" 1525 origdir = os.getcwd()
1527 os.chdir(str(os.path.normpath(os.path.expandvars(self.workdir))))
1529 if "QMTEST_TMPDIR" in os.environ:
1530 qmtest_tmpdir = os.environ[
"QMTEST_TMPDIR"]
1531 if not os.path.exists(qmtest_tmpdir):
1532 os.makedirs(qmtest_tmpdir)
1533 os.chdir(qmtest_tmpdir)
1534 elif "qmtest.tmpdir" in context:
1535 os.chdir(context[
"qmtest.tmpdir"])
1537 if "QMTEST_IGNORE_TIMEOUT" not in os.environ:
1550 if result.GetOutcome()
not in [ result.PASS ]:
1557 """Run the 'program'. 1559 'program' -- The path to the program to run. 1561 'arguments' -- A list of the arguments to the program. This 1562 list must contain a first argument corresponding to 'argv[0]'. 1564 'context' -- A 'Context' giving run-time parameters to the 1567 'result' -- A 'Result' object. The outcome will be 1568 'Result.PASS' when this method is called. The 'result' may be 1569 modified by this method to indicate outcomes other than 1570 'Result.PASS' or to add annotations. 1572 @attention: This method has been copied from command.ExecTestBase 1573 (QMTest 2.3.0) and modified to keep stdout and stderr 1574 for tests that have been terminated by a signal. 1575 (Fundamental for debugging in the Application Area) 1579 environment = self.MakeEnvironment(context)
1581 if "slc6" in environment.get(
'CMTCONFIG',
''):
1582 environment[
'TERM'] =
'dumb' 1595 exit_status = e.Run(arguments, environment, path = program)
1597 if e.stack_trace_file
and os.path.exists(e.stack_trace_file):
1598 stack_trace = open(e.stack_trace_file).
read()
1599 os.remove(e.stack_trace_file)
1603 result[
"ExecTest.stack_trace"] = result.Quote(stack_trace)
1606 if (sys.platform ==
"win32" or os.WIFEXITED(exit_status)
1612 if self.exit_code
is None:
1614 elif sys.platform ==
"win32":
1615 exit_code = exit_status
1617 exit_code = os.WEXITSTATUS(exit_status)
1622 result[
"ExecTest.exit_code"] = str(exit_code)
1623 result[
"ExecTest.stdout"] = result.Quote(stdout)
1624 result[
"ExecTest.stderr"] = result.Quote(stderr)
1626 if exit_code != self.exit_code:
1627 causes.append(
"exit_code")
1628 result[
"ExecTest.expected_exit_code"] \
1629 = str(self.exit_code)
1634 result.Fail(
"Unexpected %s." % string.join(causes,
", "))
1635 elif os.WIFSIGNALED(exit_status):
1638 signal_number = str(os.WTERMSIG(exit_status))
1640 result.Fail(
"Program terminated by signal.")
1644 result.Fail(
"Exceeded time limit (%ds), terminated." % timeout)
1645 result[
"ExecTest.signal_number"] = signal_number
1646 result[
"ExecTest.stdout"] = result.Quote(e.stdout)
1647 result[
"ExecTest.stderr"] = result.Quote(e.stderr)
1649 result[
"ExecTest.expected_signal_number"] = str(self.
signal)
1650 elif os.WIFSTOPPED(exit_status):
1653 signal_number = str(os.WSTOPSIG(exit_status))
1655 result.Fail(
"Program stopped by signal.")
1659 result.Fail(
"Exceeded time limit (%ds), stopped." % timeout)
1660 result[
"ExecTest.signal_number"] = signal_number
1661 result[
"ExecTest.stdout"] = result.Quote(e.stdout)
1662 result[
"ExecTest.stderr"] = result.Quote(e.stderr)
1666 result.Fail(
"Program did not terminate normally.")
1672 result[
"ExecTest.stdout"] = result[
"ExecTest.stdout"].replace(esc,repr_esc)
1677 if 'NO_ECLIPSE_LAUNCHERS' in os.environ:
1682 projbasedir = os.path.normpath(destdir)
1683 while not os.path.exists(os.path.join(projbasedir,
".project")):
1684 oldprojdir = projbasedir
1685 projbasedir = os.path.normpath(os.path.join(projbasedir, os.pardir))
1688 if oldprojdir == projbasedir:
1692 if not os.path.exists(destdir):
1693 os.makedirs(destdir)
1695 from xml.etree
import ElementTree
as ET
1696 t = ET.parse(os.path.join(projbasedir,
".project"))
1697 projectName = t.find(
"name").text
1700 destfile =
"%s.launch" % self._Runnable__id
1702 destfile = os.path.join(destdir, destfile)
1704 if self.options.strip():
1708 tempfile = args.pop()
1709 optsfile = destfile + os.path.splitext(tempfile)[1]
1710 shutil.copyfile(tempfile, optsfile)
1711 args.append(optsfile)
1714 from xml.sax.saxutils
import quoteattr
1718 data[
"environment"] =
"\n".join([
'<mapEntry key=%s value=%s/>' % (quoteattr(k), quoteattr(v))
1719 for k, v
in os.environ.iteritems()
1720 if k
not in (
'MAKEOVERRIDES',
'MAKEFLAGS',
'MAKELEVEL')])
1722 data[
"exec"] =
which(prog)
or prog
1723 if os.path.basename(data[
"exec"]).lower().startswith(
"python"):
1724 data[
"stopAtMain"] =
"false" 1726 data[
"stopAtMain"] =
"true" 1728 data[
"args"] =
" ".join(
map(rationalizepath, args))
1730 data[
"args"] =
" ".join([
"/debugexe"] +
map(rationalizepath, [data[
"exec"]] + args))
1731 data[
"exec"] =
which(
"vcexpress.exe")
1734 data[
"workdir"] = os.getcwd()
1738 data[
"workdir"] = destdir
1740 data[
"project"] = projectName.strip()
1743 xml_template =
u"""<?xml version="1.0" encoding="UTF-8" standalone="no"?> 1744 <launchConfiguration type="org.eclipse.cdt.launch.applicationLaunchType"> 1745 <booleanAttribute key="org.eclipse.cdt.debug.mi.core.AUTO_SOLIB" value="true"/> 1746 <listAttribute key="org.eclipse.cdt.debug.mi.core.AUTO_SOLIB_LIST"/> 1747 <stringAttribute key="org.eclipse.cdt.debug.mi.core.DEBUG_NAME" value="gdb"/> 1748 <stringAttribute key="org.eclipse.cdt.debug.mi.core.GDB_INIT" value=".gdbinit"/> 1749 <listAttribute key="org.eclipse.cdt.debug.mi.core.SOLIB_PATH"/> 1750 <booleanAttribute key="org.eclipse.cdt.debug.mi.core.STOP_ON_SOLIB_EVENTS" value="false"/> 1751 <booleanAttribute key="org.eclipse.cdt.debug.mi.core.breakpointsFullPath" value="false"/> 1752 <stringAttribute key="org.eclipse.cdt.debug.mi.core.commandFactory" value="org.eclipse.cdt.debug.mi.core.standardCommandFactory"/> 1753 <stringAttribute key="org.eclipse.cdt.debug.mi.core.protocol" value="mi"/> 1754 <booleanAttribute key="org.eclipse.cdt.debug.mi.core.verboseMode" value="false"/> 1755 <intAttribute key="org.eclipse.cdt.launch.ATTR_BUILD_BEFORE_LAUNCH_ATTR" value="0"/> 1756 <stringAttribute key="org.eclipse.cdt.launch.COREFILE_PATH" value=""/> 1757 <stringAttribute key="org.eclipse.cdt.launch.DEBUGGER_ID" value="org.eclipse.cdt.debug.mi.core.CDebuggerNew"/> 1758 <stringAttribute key="org.eclipse.cdt.launch.DEBUGGER_REGISTER_GROUPS" value=""/> 1759 <stringAttribute key="org.eclipse.cdt.launch.DEBUGGER_START_MODE" value="run"/> 1760 <booleanAttribute key="org.eclipse.cdt.launch.DEBUGGER_STOP_AT_MAIN" value="%(stopAtMain)s"/> 1761 <stringAttribute key="org.eclipse.cdt.launch.DEBUGGER_STOP_AT_MAIN_SYMBOL" value="main"/> 1762 <booleanAttribute key="org.eclipse.cdt.launch.ENABLE_REGISTER_BOOKKEEPING" value="false"/> 1763 <booleanAttribute key="org.eclipse.cdt.launch.ENABLE_VARIABLE_BOOKKEEPING" value="false"/> 1764 <stringAttribute key="org.eclipse.cdt.launch.FORMAT" value="<?xml version="1.0" encoding="UTF-8" standalone="no"?><contentList/>"/> 1765 <stringAttribute key="org.eclipse.cdt.launch.GLOBAL_VARIABLES" value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <globalVariableList/> "/> 1766 <stringAttribute key="org.eclipse.cdt.launch.MEMORY_BLOCKS" value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <memoryBlockExpressionList/> "/> 1767 <stringAttribute key="org.eclipse.cdt.launch.PROGRAM_ARGUMENTS" value="%(args)s"/> 1768 <stringAttribute key="org.eclipse.cdt.launch.PROGRAM_NAME" value="%(exec)s"/> 1769 <stringAttribute key="org.eclipse.cdt.launch.PROJECT_ATTR" value="%(project)s"/> 1770 <stringAttribute key="org.eclipse.cdt.launch.PROJECT_BUILD_CONFIG_ID_ATTR" value=""/> 1771 <stringAttribute key="org.eclipse.cdt.launch.WORKING_DIRECTORY" value="%(workdir)s"/> 1772 <booleanAttribute key="org.eclipse.cdt.launch.ui.ApplicationCDebuggerTab.DEFAULTS_SET" value="true"/> 1773 <booleanAttribute key="org.eclipse.cdt.launch.use_terminal" value="true"/> 1774 <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS"> 1775 <listEntry value="/%(project)s"/> 1777 <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES"> 1778 <listEntry value="4"/> 1780 <booleanAttribute key="org.eclipse.debug.core.appendEnvironmentVariables" value="false"/> 1781 <mapAttribute key="org.eclipse.debug.core.environmentVariables"> 1784 <mapAttribute key="org.eclipse.debug.core.preferred_launchers"> 1785 <mapEntry key="[debug]" value="org.eclipse.cdt.cdi.launch.localCLaunch"/> 1787 <listAttribute key="org.eclipse.debug.ui.favoriteGroups"> 1788 <listEntry value="org.eclipse.debug.ui.launchGroup.debug"/> 1790 </launchConfiguration> 1795 data[k] = codecs.decode(data[k],
'utf-8')
1796 xml = xml_template % data
1799 codecs.open(destfile,
"w", encoding=
'utf-8').
write(xml)
1801 print 'WARNING: problem generating Eclipse launcher' 1808 import simplejson
as json
1811 """An 'HTMLResultStream' writes its output to a set of HTML files. 1813 The argument 'dir' is used to select the destination directory for the HTML 1815 The destination directory may already contain the report from a previous run 1816 (for example of a different package), in which case it will be extended to 1817 include the new data. 1820 qm.fields.TextField(
1822 title =
"Destination Directory",
1823 description =
"""The name of the directory. 1825 All results will be written to the directory indicated.""",
1827 default_value =
""),
1831 """Prepare the destination directory. 1833 Creates the destination directory and store in it some preliminary 1834 annotations and the static files found in the template directory 1837 ResultStream.__init__(self, arguments, **args)
1842 templateDir = os.path.join(os.path.dirname(__file__),
"html_report")
1843 if not os.path.isdir(self.dir):
1844 os.makedirs(self.dir)
1846 for f
in os.listdir(templateDir):
1847 src = os.path.join(templateDir, f)
1848 dst = os.path.join(self.dir, f)
1849 if not os.path.isdir(src)
and not os.path.exists(dst):
1850 shutil.copy(src, dst)
1852 if "CMTCONFIG" in os.environ:
1858 """Helper function to extend the global summary file in the destination 1865 ids = set([ i[
"id"]
for i
in self.
_summary ])
1866 newSummary = [ i
for i
in oldSummary
if i[
"id"]
not in ids ]
1872 """Writes the annotation to the annotation file. 1873 If the key is already present with a different value, the value becomes 1874 a list and the new value is appended to it, except for start_time and 1883 key, value =
map(str, [key, value])
1884 if key ==
"qmtest.run.start_time":
1889 if key
not in annotations:
1890 annotations[key] = value
1891 if "qmtest.run.end_time" in annotations:
1892 del annotations[
"qmtest.run.end_time"]
1895 if key
in annotations:
1896 old = annotations[key]
1897 if type(old)
is list:
1898 if value
not in old:
1899 annotations[key].append(value)
1901 annotations[key] = [old, value]
1903 annotations[key] = value
1909 """Prepare the test result directory in the destination directory storing 1910 into it the result fields. 1911 A summary of the test result is stored both in a file in the test directory 1912 and in the global summary file. 1915 summary[
"id"] = result.GetId()
1916 summary[
"outcome"] = result.GetOutcome()
1917 summary[
"cause"] = result.GetCause()
1918 summary[
"fields"] = result.keys()
1919 summary[
"fields"].sort()
1922 for f
in [
"id",
"outcome",
"cause"]:
1923 summary[f] = str(summary[f])
1924 summary[
"fields"] =
map(str, summary[
"fields"])
1926 self._summary.append(summary)
1932 testOutDir = os.path.join(self.dir, summary[
"id"])
1933 if not os.path.isdir(testOutDir):
1934 os.makedirs(testOutDir)
1935 json.dump(summary, open(os.path.join(testOutDir,
"summary.json"),
"w"),
1937 for f
in summary[
"fields"]:
1938 open(os.path.join(testOutDir, f),
"w").
write(result[f])
1949 class XMLResultStream(ResultStream):
1950 """An 'XMLResultStream' writes its output to a Ctest XML file. 1952 The argument 'dir' is used to select the destination file for the XML 1954 The destination directory may already contain the report from a previous run 1955 (for example of a different package), in which case it will be overrided to 1959 qm.fields.TextField(
1961 title =
"Destination Directory",
1962 description =
"""The name of the directory. 1964 All results will be written to the directory indicated.""",
1966 default_value =
""),
1967 qm.fields.TextField(
1969 title =
"Output File Prefix",
1970 description =
"""The output file name will be the specified prefix 1971 followed by 'Test.xml' (CTest convention).""",
1973 default_value =
""),
1977 """Prepare the destination directory. 1979 Creates the destination directory and store in it some preliminary 1982 ResultStream.__init__(self, arguments, **args)
1984 self.
_xmlFile = os.path.join(self.dir, self.prefix +
'Test.xml')
1990 if not os.path.isfile(self.
_xmlFile):
1992 if not os.path.exists(os.path.dirname(self.
_xmlFile)):
1993 os.makedirs(os.path.dirname(self.
_xmlFile))
1995 newdataset = ET.Element(
"newdataset")
2001 newdataset = self._tree.getroot()
2008 for site
in newdataset.getiterator() :
2009 if site.get(
"OSPlatform") == os.uname()[4]:
2019 import multiprocessing
2021 "BuildName" : os.getenv(
"CMTCONFIG"),
2022 "Name" : os.uname()[1] ,
2023 "Generator" :
"QMTest "+qm.version ,
2024 "OSName" : os.uname()[0] ,
2025 "Hostname" : socket.gethostname() ,
2026 "OSRelease" : os.uname()[2] ,
2027 "OSVersion" :os.uname()[3] ,
2028 "OSPlatform" :os.uname()[4] ,
2029 "Is64Bits" :
"unknown" ,
2030 "VendorString" :
"unknown" ,
2031 "VendorID" :
"unknown" ,
2032 "FamilyID" :
"unknown" ,
2033 "ModelID" :
"unknown" ,
2034 "ProcessorCacheSize" :
"unknown" ,
2035 "NumberOfLogicalCPU" : str(multiprocessing.cpu_count()) ,
2036 "NumberOfPhysicalCPU" :
"0" ,
2037 "TotalVirtualMemory" :
"0" ,
2038 "TotalPhysicalMemory" :
"0" ,
2039 "LogicalProcessorsPerPhysical" :
"0" ,
2040 "ProcessorClockFrequency" :
"0" ,
2042 self.
_site = ET.SubElement(newdataset,
"Site", attrib)
2065 self.
_Testing = self._site.find(
"Testing")
2068 self.
_TestList = self._Testing.find(
"TestList")
2074 # Add some non-QMTest attributes 2075 if "CMTCONFIG" in os.environ: 2076 self.WriteAnnotation("cmt.cmtconfig", os.environ["CMTCONFIG"]) 2078 self.WriteAnnotation("hostname", socket.gethostname()) 2083 if key ==
"qmtest.run.start_time":
2084 if self._site.get(
"qmtest.run.start_time")
is not None :
2086 self._site.set(str(key),str(value))
2088 """Prepare the test result directory in the destination directory storing 2089 into it the result fields. 2090 A summary of the test result is stored both in a file in the test directory 2091 and in the global summary file. 2094 summary[
"id"] = result.GetId()
2095 summary[
"outcome"] = result.GetOutcome()
2096 summary[
"cause"] = result.GetCause()
2097 summary[
"fields"] = result.keys()
2098 summary[
"fields"].sort()
2102 for f
in [
"id",
"outcome",
"cause"]:
2103 summary[f] = str(summary[f])
2104 summary[
"fields"] =
map(str, summary[
"fields"])
2110 if "qmtest.start_time" in summary[
"fields"]:
2111 haveStartDate =
True 2113 haveStartDate =
False 2114 if "qmtest.end_time" in summary[
"fields"]:
2121 self.
_startTime = calendar.timegm(time.strptime(result[
"qmtest.start_time"],
"%Y-%m-%dT%H:%M:%SZ"))
2122 if self._StartTestTime.text
is None:
2123 self._StartDateTime.text = time.strftime(
"%b %d %H:%M %Z", time.localtime(self.
_startTime))
2124 self._StartTestTime.text = str(self.
_startTime)
2125 self._site.set(
"BuildStamp" , result[
"qmtest.start_time"] )
2129 self.
_endTime = calendar.timegm(time.strptime(result[
"qmtest.end_time"],
"%Y-%m-%dT%H:%M:%SZ"))
2133 tl = ET.Element(
"Test")
2134 tl.text = summary[
"id"]
2135 self._TestList.insert(0,tl)
2138 Test = ET.Element(
"Test")
2139 if summary[
"outcome"] ==
"PASS":
2140 Test.set(
"Status",
"passed")
2141 elif summary[
"outcome"] ==
"FAIL":
2142 Test.set(
"Status",
"failed")
2143 elif summary[
"outcome"] ==
"SKIPPED" or summary[
"outcome"] ==
"UNTESTED":
2144 Test.set(
"Status",
"skipped")
2145 elif summary[
"outcome"] ==
"ERROR":
2146 Test.set(
"Status",
"failed")
2147 Name = ET.SubElement(Test,
"Name",)
2148 Name.text = summary[
"id"]
2149 Results = ET.SubElement(Test,
"Results")
2152 self._Testing.insert(3,Test)
2154 if haveStartDate
and haveEndDate:
2157 testduration = str(delta)
2158 Testduration= ET.SubElement(Results,
"NamedMeasurement")
2159 Testduration.set(
"name",
"Execution Time")
2160 Testduration.set(
"type",
"numeric/float" )
2161 value = ET.SubElement(Testduration,
"Value")
2162 value.text = testduration
2165 for n
in (
"qmtest.end_time",
"qmtest.start_time",
"qmtest.cause",
"ExecTest.stdout"):
2166 if n
in summary[
"fields"]:
2167 summary[
"fields"].remove(n)
2171 if "ExecTest.exit_code" in summary[
"fields"] :
2172 summary[
"fields"].remove(
"ExecTest.exit_code")
2173 ExitCode= ET.SubElement(Results,
"NamedMeasurement")
2174 ExitCode.set(
"name",
"exit_code")
2175 ExitCode.set(
"type",
"numeric/integer" )
2176 value = ET.SubElement(ExitCode,
"Value")
2179 TestStartTime= ET.SubElement(Results,
"NamedMeasurement")
2180 TestStartTime.set(
"name",
"Start_Time")
2181 TestStartTime.set(
"type",
"String" )
2182 value = ET.SubElement(TestStartTime,
"Value")
2188 TestEndTime= ET.SubElement(Results,
"NamedMeasurement")
2189 TestEndTime.set(
"name",
"End_Time")
2190 TestEndTime.set(
"type",
"String" )
2191 value = ET.SubElement(TestEndTime,
"Value")
2197 if summary[
"cause"]:
2198 FailureCause= ET.SubElement(Results,
"NamedMeasurement")
2199 FailureCause.set(
"name",
"Cause")
2200 FailureCause.set(
"type",
"String" )
2201 value = ET.SubElement(FailureCause,
"Value")
2206 for field
in summary[
"fields"] :
2207 fields[field] = ET.SubElement(Results,
"NamedMeasurement")
2208 fields[field].set(
"type",
"String")
2209 fields[field].set(
"name",field)
2210 value = ET.SubElement(fields[field],
"Value")
2212 if "<pre>" in result[field][0:6] :
2218 if result.has_key(
"ExecTest.stdout" ) :
2219 Measurement = ET.SubElement(Results,
"Measurement")
2220 value = ET.SubElement(Measurement,
"Value")
2221 if "<pre>" in result[
"ExecTest.stdout"][0:6] :
2228 self._tree.write(self.
_xmlFile,
"utf-8")
2234 self._EndTestTime.text = str(self.
_endTime)
2235 self._EndDateTime.text = time.strftime(
"%b %d %H:%M %Z", time.localtime(self.
_endTime))
2242 self._ElapsedMinutes.text = str(delta/60)
2245 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)
decltype(auto) range(Args &&...args)
Zips multiple containers together to form a single range.
def PlatformIsNotSupported(self, context, result)
def __init__(self, reffile, cause, result_key, preproc=normalizeExamples)
def __processLine__(self, line)
def DumpEnvironment(self, result)
def __delitem__(self, key)
def _HandleChild(self)
Needs to replace the ones from RedirectedExecutable and TimeoutExecutable.
def __init__(self, members=[])
def __contains__(self, key)
def read(f, regex='.*', skipevents=0)
def runtime_env(self, env=None)
def _expandReferenceFileName(self, reffile)
def escape_xml_illegal_chars(val, replacement='?')
MsgStream & hex(MsgStream &log)
def WriteAnnotation(self, key, value)
def __setitem__(self, key, value)
def which(executable)
Locates an executable in the executables path ($PATH) and returns the full path to it...
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)
_EndDateTime
End time elements.
struct GAUDI_API map
Parametrisation class for map-like implementation.
def convert_xml_illegal_chars(val)
def _parseTTreeSummary(lines, pos)
def __call__(self, stdout, result)
def gen_script(self, shell_type)
def getCmpFailingValues(reference, to_check, fail_path)
def Run(self, context, result)
def _CreateEclipseLaunch(self, prog, args, destdir=None)
def __processLine__(self, line)
Output Validation Classes.
def __processLine__(self, line)
def total_seconds_replacement(timedelta)
def _run_cmt(self, command, args)
def WriteAnnotation(self, key, value)
def __call__(self, input)
def __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)
constexpr void apply(const Fun &, Container &, Args...)
def __init__(self, start, end)
Special preprocessor sorting the list of strings (whitespace separated) that follow a signature on a ...
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)