The Gaudi Framework  v30r4 (9b837755)
GaudiTesting.BaseTest Namespace Reference

Classes

class  BaseTest
 
class  BasicOutputValidator
 
class  BlockSkipper
 
class  FilePreprocessor
 
class  FilePreprocessorSequence
 
class  LineSkipper
 
class  LineSorter
 
class  ReferenceFileValidator
 
class  RegexpReplacer
 
class  Result
 
class  SortGroupOfLines
 

Functions

def sanitize_for_xml (data)
 
def dumpProcs (name)
 
def kill_tree (ppid, sig)
 
def ROOT6WorkAroundEnabled (id=None)
 
def RationalizePath (p)
 
def which (executable)
 
def findTTreeSummaries (stdout)
 
def cmpTreesDicts (reference, to_check, ignore=None)
 
def getCmpFailingValues (reference, to_check, fail_path)
 
def _parseTTreeSummary (lines, pos)
 
def parseHistosSummary (lines, pos)
 
def findHistosSummaries (stdout)
 
def PlatformIsNotSupported (self, context, result)
 
def GetPlatform (self)
 
def isWinPlatform (self)
 

Variables

 maskPointers = RegexpReplacer("0x[0-9a-fA-F]{4,16}", "0x########")
 
 normalizeDate
 
 normalizeEOL = FilePreprocessor()
 
 __processLine__
 
 skipEmptyLines = FilePreprocessor()
 
 normalizeExamples = maskPointers+normalizeDate
 
 lineSkipper
 
 regexps
 
 h_count_re
 

Function Documentation

def GaudiTesting.BaseTest._parseTTreeSummary (   lines,
  pos 
)
private
Parse the TTree summary table in lines, starting from pos.
Returns a tuple with the dictionary with the digested informations and the
position of the first line after the summary.

Definition at line 1077 of file BaseTest.py.

1077 def _parseTTreeSummary(lines, pos):
1078  """
1079  Parse the TTree summary table in lines, starting from pos.
1080  Returns a tuple with the dictionary with the digested informations and the
1081  position of the first line after the summary.
1082  """
1083  result = {}
1084  i = pos + 1 # first line is a sequence of '*'
1085  count = len(lines)
1086 
1087  def splitcols(l): return [f.strip() for f in l.strip("*\n").split(':', 2)]
1088 
1089  def parseblock(ll):
1090  r = {}
1091  cols = splitcols(ll[0])
1092  r["Name"], r["Title"] = cols[1:]
1093 
1094  cols = splitcols(ll[1])
1095  r["Entries"] = int(cols[1])
1096 
1097  sizes = cols[2].split()
1098  r["Total size"] = int(sizes[2])
1099  if sizes[-1] == "memory":
1100  r["File size"] = 0
1101  else:
1102  r["File size"] = int(sizes[-1])
1103 
1104  cols = splitcols(ll[2])
1105  sizes = cols[2].split()
1106  if cols[0] == "Baskets":
1107  r["Baskets"] = int(cols[1])
1108  r["Basket size"] = int(sizes[2])
1109  r["Compression"] = float(sizes[-1])
1110  return r
1111 
1112  if i < (count - 3) and lines[i].startswith("*Tree"):
1113  result = parseblock(lines[i:i + 3])
1114  result["Branches"] = {}
1115  i += 4
1116  while i < (count - 3) and lines[i].startswith("*Br"):
1117  if i < (count - 2) and lines[i].startswith("*Branch "):
1118  # skip branch header
1119  i += 3
1120  continue
1121  branch = parseblock(lines[i:i + 3])
1122  result["Branches"][branch["Name"]] = branch
1123  i += 4
1124 
1125  return (result, i)
1126 
1127 
def _parseTTreeSummary(lines, pos)
Definition: BaseTest.py:1077
def GaudiTesting.BaseTest.cmpTreesDicts (   reference,
  to_check,
  ignore = None 
)
    Check that all the keys in reference are in to_check too, with the same value.
    If the value is a dict, the function is called recursively. to_check can
    contain more keys than reference, that will not be tested.
    The function returns at the first difference found.

Definition at line 1027 of file BaseTest.py.

1027 def cmpTreesDicts(reference, to_check, ignore=None):
1028  """
1029  Check that all the keys in reference are in to_check too, with the same value.
1030  If the value is a dict, the function is called recursively. to_check can
1031  contain more keys than reference, that will not be tested.
1032  The function returns at the first difference found.
1033  """
1034  fail_keys = []
1035  # filter the keys in the reference dictionary
1036  if ignore:
1037  ignore_re = re.compile(ignore)
1038  keys = [key for key in reference if not ignore_re.match(key)]
1039  else:
1040  keys = reference.keys()
1041  # loop over the keys (not ignored) in the reference dictionary
1042  for k in keys:
1043  if k in to_check: # the key must be in the dictionary to_check
1044  if (type(reference[k]) is dict) and (type(to_check[k]) is dict):
1045  # if both reference and to_check values are dictionaries,
1046  # recurse
1047  failed = fail_keys = cmpTreesDicts(
1048  reference[k], to_check[k], ignore)
1049  else:
1050  # compare the two values
1051  failed = to_check[k] != reference[k]
1052  else: # handle missing keys in the dictionary to check (i.e. failure)
1053  to_check[k] = None
1054  failed = True
1055  if failed:
1056  fail_keys.insert(0, k)
1057  break # exit from the loop at the first failure
1058  return fail_keys # return the list of keys bringing to the different values
1059 
1060 
def cmpTreesDicts(reference, to_check, ignore=None)
Definition: BaseTest.py:1027
def GaudiTesting.BaseTest.dumpProcs (   name)
helper to debug GAUDI-1084, dump the list of processes

Definition at line 34 of file BaseTest.py.

34 def dumpProcs(name):
35  '''helper to debug GAUDI-1084, dump the list of processes'''
36  from getpass import getuser
37  if 'WORKSPACE' in os.environ:
38  p = Popen(['ps', '-fH', '-U', getuser()], stdout=PIPE)
39  with open(os.path.join(os.environ['WORKSPACE'], name), 'w') as f:
40  f.write(p.communicate()[0])
41 
42 
def dumpProcs(name)
Definition: BaseTest.py:34
def GaudiTesting.BaseTest.findHistosSummaries (   stdout)
    Scan stdout to find ROOT TTree summaries and digest them.

Definition at line 1195 of file BaseTest.py.

1196  """
1197  Scan stdout to find ROOT TTree summaries and digest them.
1198  """
1199  outlines = stdout.splitlines()
1200  nlines = len(outlines) - 1
1201  summaries = {}
1202  global h_count_re
1203 
1204  pos = 0
1205  while pos < nlines:
1206  summ = {}
1207  # find first line of block:
1208  match = h_count_re.search(outlines[pos])
1209  while pos < nlines and not match:
1210  pos += 1
1211  match = h_count_re.search(outlines[pos])
1212  if match:
1213  summ, pos = parseHistosSummary(outlines, pos)
1214  summaries.update(summ)
1215  return summaries
1216 
1217 
def findHistosSummaries(stdout)
Definition: BaseTest.py:1195
def parseHistosSummary(lines, pos)
Definition: BaseTest.py:1128
def GaudiTesting.BaseTest.findTTreeSummaries (   stdout)
    Scan stdout to find ROOT TTree summaries and digest them.

Definition at line 1005 of file BaseTest.py.

1006  """
1007  Scan stdout to find ROOT TTree summaries and digest them.
1008  """
1009  stars = re.compile(r"^\*+$")
1010  outlines = stdout.splitlines()
1011  nlines = len(outlines)
1012  trees = {}
1013 
1014  i = 0
1015  while i < nlines: # loop over the output
1016  # look for
1017  while i < nlines and not stars.match(outlines[i]):
1018  i += 1
1019  if i < nlines:
1020  tree, i = _parseTTreeSummary(outlines, i)
1021  if tree:
1022  trees[tree["Name"]] = tree
1023 
1024  return trees
1025 
1026 
def _parseTTreeSummary(lines, pos)
Definition: BaseTest.py:1077
def findTTreeSummaries(stdout)
Definition: BaseTest.py:1005
def GaudiTesting.BaseTest.getCmpFailingValues (   reference,
  to_check,
  fail_path 
)

Definition at line 1061 of file BaseTest.py.

1061 def getCmpFailingValues(reference, to_check, fail_path):
1062  c = to_check
1063  r = reference
1064  for k in fail_path:
1065  c = c.get(k, None)
1066  r = r.get(k, None)
1067  if c is None or r is None:
1068  break # one of the dictionaries is not deep enough
1069  return (fail_path, r, c)
1070 
1071 
1072 # signature of the print-out of the histograms
def getCmpFailingValues(reference, to_check, fail_path)
Definition: BaseTest.py:1061
def GaudiTesting.BaseTest.GetPlatform (   self)
    Return the platform Id defined in CMTCONFIG or SCRAM_ARCH.

Definition at line 1230 of file BaseTest.py.

1230 def GetPlatform(self):
1231  """
1232  Return the platform Id defined in CMTCONFIG or SCRAM_ARCH.
1233  """
1234  arch = "None"
1235  # check architecture name
1236  if "BINARY_TAG" in os.environ:
1237  arch = os.environ["BINARY_TAG"]
1238  elif "CMTCONFIG" in os.environ:
1239  arch = os.environ["CMTCONFIG"]
1240  elif "SCRAM_ARCH" in os.environ:
1241  arch = os.environ["SCRAM_ARCH"]
1242  return arch
1243 
1244 
def GetPlatform(self)
Definition: BaseTest.py:1230
def GaudiTesting.BaseTest.isWinPlatform (   self)
    Return True if the current platform is Windows.

    This function was needed because of the change in the CMTCONFIG format,
    from win32_vc71_dbg to i686-winxp-vc9-dbg.

Definition at line 1245 of file BaseTest.py.

1245 def isWinPlatform(self):
1246  """
1247  Return True if the current platform is Windows.
1248 
1249  This function was needed because of the change in the CMTCONFIG format,
1250  from win32_vc71_dbg to i686-winxp-vc9-dbg.
1251  """
1252  platform = GetPlatform(self)
1253  return "winxp" in platform or platform.startswith("win")
1254 
def GetPlatform(self)
Definition: BaseTest.py:1230
def isWinPlatform(self)
Definition: BaseTest.py:1245
def GaudiTesting.BaseTest.kill_tree (   ppid,
  sig 
)
Send a signal to a process and all its child processes (starting from the
leaves).

Definition at line 43 of file BaseTest.py.

43 def kill_tree(ppid, sig):
44  '''
45  Send a signal to a process and all its child processes (starting from the
46  leaves).
47  '''
48  log = logging.getLogger('kill_tree')
49  ps_cmd = ['ps', '--no-headers', '-o', 'pid', '--ppid', str(ppid)]
50  get_children = Popen(ps_cmd, stdout=PIPE, stderr=PIPE)
51  children = map(int, get_children.communicate()[0].split())
52  for child in children:
53  kill_tree(child, sig)
54  try:
55  log.debug('killing process %d', ppid)
56  os.kill(ppid, sig)
57  except OSError, err:
58  if err.errno != 3: # No such process
59  raise
60  log.debug('no such process %d', ppid)
61 
62 # -------------------------------------------------------------------------#
63 
64 
struct GAUDI_API map
Parametrisation class for map-like implementation.
def kill_tree(ppid, sig)
Definition: BaseTest.py:43
def GaudiTesting.BaseTest.parseHistosSummary (   lines,
  pos 
)
    Extract the histograms infos from the lines starting at pos.
    Returns the position of the first line after the summary block.

Definition at line 1128 of file BaseTest.py.

1128 def parseHistosSummary(lines, pos):
1129  """
1130  Extract the histograms infos from the lines starting at pos.
1131  Returns the position of the first line after the summary block.
1132  """
1133  global h_count_re
1134  h_table_head = re.compile(
1135  r'SUCCESS\s+List of booked (1D|2D|3D|1D profile|2D profile) histograms in directory\s+"(\w*)"')
1136  h_short_summ = re.compile(r"ID=([^\"]+)\s+\"([^\"]+)\"\s+(.*)")
1137 
1138  nlines = len(lines)
1139 
1140  # decode header
1141  m = h_count_re.search(lines[pos])
1142  name = m.group(1).strip()
1143  total = int(m.group(2))
1144  header = {}
1145  for k, v in [x.split("=") for x in m.group(3).split()]:
1146  header[k] = int(v)
1147  pos += 1
1148  header["Total"] = total
1149 
1150  summ = {}
1151  while pos < nlines:
1152  m = h_table_head.search(lines[pos])
1153  if m:
1154  t, d = m.groups(1) # type and directory
1155  t = t.replace(" profile", "Prof")
1156  pos += 1
1157  if pos < nlines:
1158  l = lines[pos]
1159  else:
1160  l = ""
1161  cont = {}
1162  if l.startswith(" | ID"):
1163  # table format
1164  titles = [x.strip() for x in l.split("|")][1:]
1165  pos += 1
1166  while pos < nlines and lines[pos].startswith(" |"):
1167  l = lines[pos]
1168  values = [x.strip() for x in l.split("|")][1:]
1169  hcont = {}
1170  for i in range(len(titles)):
1171  hcont[titles[i]] = values[i]
1172  cont[hcont["ID"]] = hcont
1173  pos += 1
1174  elif l.startswith(" ID="):
1175  while pos < nlines and lines[pos].startswith(" ID="):
1176  values = [x.strip()
1177  for x in h_short_summ.search(lines[pos]).groups()]
1178  cont[values[0]] = values
1179  pos += 1
1180  else: # not interpreted
1181  raise RuntimeError(
1182  "Cannot understand line %d: '%s'" % (pos, l))
1183  if not d in summ:
1184  summ[d] = {}
1185  summ[d][t] = cont
1186  summ[d]["header"] = header
1187  else:
1188  break
1189  if not summ:
1190  # If the full table is not present, we use only the header
1191  summ[name] = {"header": header}
1192  return summ, pos
1193 
1194 
decltype(auto) range(Args &&...args)
Zips multiple containers together to form a single range.
def parseHistosSummary(lines, pos)
Definition: BaseTest.py:1128
def GaudiTesting.BaseTest.PlatformIsNotSupported (   self,
  context,
  result 
)

Definition at line 1218 of file BaseTest.py.

1218 def PlatformIsNotSupported(self, context, result):
1219  platform = GetPlatform(self)
1220  unsupported = [re.compile(x) for x in [str(y).strip()
1221  for y in unsupported_platforms] if x]
1222  for p_re in unsupported:
1223  if p_re.search(platform):
1224  result.SetOutcome(result.UNTESTED)
1225  result[result.CAUSE] = 'Platform not supported.'
1226  return True
1227  return False
1228 
1229 
def GetPlatform(self)
Definition: BaseTest.py:1230
def PlatformIsNotSupported(self, context, result)
Definition: BaseTest.py:1218
def GaudiTesting.BaseTest.RationalizePath (   p)
Function used to normalize the used path

Definition at line 566 of file BaseTest.py.

567  """
568  Function used to normalize the used path
569  """
570  newPath = os.path.normpath(os.path.expandvars(p))
571  if os.path.exists(newPath):
572  p = os.path.realpath(newPath)
573  return p
574 
575 
def GaudiTesting.BaseTest.ROOT6WorkAroundEnabled (   id = None)

Definition at line 559 of file BaseTest.py.

560  # dummy implementation
561  return False
562 
563 # --------------------------------- TOOLS ---------------------------------#
564 
565 
def ROOT6WorkAroundEnabled(id=None)
Definition: BaseTest.py:559
def GaudiTesting.BaseTest.sanitize_for_xml (   data)
Take a string with invalid ASCII/UTF characters and quote them so that the
string can be used in an XML text.

>>> sanitize_for_xml('this is \x1b')
'this is [NON-XML-CHAR-0x1B]'

Definition at line 17 of file BaseTest.py.

17 def sanitize_for_xml(data):
18  '''
19  Take a string with invalid ASCII/UTF characters and quote them so that the
20  string can be used in an XML text.
21 
22  >>> sanitize_for_xml('this is \x1b')
23  'this is [NON-XML-CHAR-0x1B]'
24  '''
25  bad_chars = re.compile(
26  u'[\x00-\x08\x0b\x0c\x0e-\x1F\uD800-\uDFFF\uFFFE\uFFFF]')
27 
28  def quote(match):
29  'helper function'
30  return ''.join('[NON-XML-CHAR-0x%2X]' % ord(c) for c in match.group())
31  return bad_chars.sub(quote, data)
32 
33 
def sanitize_for_xml(data)
Definition: BaseTest.py:17
def GaudiTesting.BaseTest.which (   executable)
Locates an executable in the executables path ($PATH) and returns the full
path to it.  An application is looked for with or without the '.exe' suffix.
If the executable cannot be found, None is returned

Definition at line 576 of file BaseTest.py.

576 def which(executable):
577  """
578  Locates an executable in the executables path ($PATH) and returns the full
579  path to it. An application is looked for with or without the '.exe' suffix.
580  If the executable cannot be found, None is returned
581  """
582  if os.path.isabs(executable):
583  if not os.path.exists(executable):
584  if executable.endswith('.exe'):
585  if os.path.exists(executable[:-4]):
586  return executable[:-4]
587  else:
588  head, executable = os.path.split(executable)
589  else:
590  return executable
591  for d in os.environ.get("PATH").split(os.pathsep):
592  fullpath = os.path.join(d, executable)
593  if os.path.exists(fullpath):
594  return fullpath
595  if executable.endswith('.exe'):
596  return which(executable[:-4])
597  return None
598 
599 
600 # -------------------------------------------------------------------------#
601 # ----------------------------- Result Classe -----------------------------#
602 # -------------------------------------------------------------------------#
def which(executable)
Definition: BaseTest.py:576

Variable Documentation

GaudiTesting.BaseTest.__processLine__
private

Definition at line 800 of file BaseTest.py.

GaudiTesting.BaseTest.h_count_re
Initial value:
1 = re.compile(
2  r"^(.*)SUCCESS\s+Booked (\d+) Histogram\(s\) :\s+([\s\w=-]*)")

Definition at line 1073 of file BaseTest.py.

GaudiTesting.BaseTest.lineSkipper

Definition at line 878 of file BaseTest.py.

GaudiTesting.BaseTest.maskPointers = RegexpReplacer("0x[0-9a-fA-F]{4,16}", "0x########")

Definition at line 795 of file BaseTest.py.

GaudiTesting.BaseTest.normalizeDate
Initial value:
2  "[0-2]?[0-9]:[0-5][0-9]:[0-5][0-9] [0-9]{4}[-/][01][0-9][-/][0-3][0-9][ A-Z]*",
3  "00:00:00 1970-01-01")

Definition at line 796 of file BaseTest.py.

GaudiTesting.BaseTest.normalizeEOL = FilePreprocessor()

Definition at line 799 of file BaseTest.py.

tuple GaudiTesting.BaseTest.normalizeExamples = maskPointers+normalizeDate

Definition at line 852 of file BaseTest.py.

GaudiTesting.BaseTest.regexps

Definition at line 957 of file BaseTest.py.

GaudiTesting.BaseTest.skipEmptyLines = FilePreprocessor()

Definition at line 802 of file BaseTest.py.