The Gaudi Framework  v31r0 (aeb156f0)
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 1136 of file BaseTest.py.

1136 def _parseTTreeSummary(lines, pos):
1137  """
1138  Parse the TTree summary table in lines, starting from pos.
1139  Returns a tuple with the dictionary with the digested informations and the
1140  position of the first line after the summary.
1141  """
1142  result = {}
1143  i = pos + 1 # first line is a sequence of '*'
1144  count = len(lines)
1145 
1146  def splitcols(l):
1147  return [f.strip() for f in l.strip("*\n").split(':', 2)]
1148 
1149  def parseblock(ll):
1150  r = {}
1151  cols = splitcols(ll[0])
1152  r["Name"], r["Title"] = cols[1:]
1153 
1154  cols = splitcols(ll[1])
1155  r["Entries"] = int(cols[1])
1156 
1157  sizes = cols[2].split()
1158  r["Total size"] = int(sizes[2])
1159  if sizes[-1] == "memory":
1160  r["File size"] = 0
1161  else:
1162  r["File size"] = int(sizes[-1])
1163 
1164  cols = splitcols(ll[2])
1165  sizes = cols[2].split()
1166  if cols[0] == "Baskets":
1167  r["Baskets"] = int(cols[1])
1168  r["Basket size"] = int(sizes[2])
1169  r["Compression"] = float(sizes[-1])
1170  return r
1171 
1172  if i < (count - 3) and lines[i].startswith("*Tree"):
1173  result = parseblock(lines[i:i + 3])
1174  result["Branches"] = {}
1175  i += 4
1176  while i < (count - 3) and lines[i].startswith("*Br"):
1177  if i < (count - 2) and lines[i].startswith("*Branch "):
1178  # skip branch header
1179  i += 3
1180  continue
1181  branch = parseblock(lines[i:i + 3])
1182  result["Branches"][branch["Name"]] = branch
1183  i += 4
1184 
1185  return (result, i)
1186 
1187 
def _parseTTreeSummary(lines, pos)
Definition: BaseTest.py:1136
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 1086 of file BaseTest.py.

1086 def cmpTreesDicts(reference, to_check, ignore=None):
1087  """
1088  Check that all the keys in reference are in to_check too, with the same value.
1089  If the value is a dict, the function is called recursively. to_check can
1090  contain more keys than reference, that will not be tested.
1091  The function returns at the first difference found.
1092  """
1093  fail_keys = []
1094  # filter the keys in the reference dictionary
1095  if ignore:
1096  ignore_re = re.compile(ignore)
1097  keys = [key for key in reference if not ignore_re.match(key)]
1098  else:
1099  keys = reference.keys()
1100  # loop over the keys (not ignored) in the reference dictionary
1101  for k in keys:
1102  if k in to_check: # the key must be in the dictionary to_check
1103  if (type(reference[k]) is dict) and (type(to_check[k]) is dict):
1104  # if both reference and to_check values are dictionaries,
1105  # recurse
1106  failed = fail_keys = cmpTreesDicts(reference[k], to_check[k],
1107  ignore)
1108  else:
1109  # compare the two values
1110  failed = to_check[k] != reference[k]
1111  else: # handle missing keys in the dictionary to check (i.e. failure)
1112  to_check[k] = None
1113  failed = True
1114  if failed:
1115  fail_keys.insert(0, k)
1116  break # exit from the loop at the first failure
1117  return fail_keys # return the list of keys bringing to the different values
1118 
1119 
def cmpTreesDicts(reference, to_check, ignore=None)
Definition: BaseTest.py:1086
def GaudiTesting.BaseTest.dumpProcs (   name)
helper to debug GAUDI-1084, dump the list of processes

Definition at line 35 of file BaseTest.py.

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

Definition at line 1258 of file BaseTest.py.

1259  """
1260  Scan stdout to find ROOT TTree summaries and digest them.
1261  """
1262  outlines = stdout.splitlines()
1263  nlines = len(outlines) - 1
1264  summaries = {}
1265  global h_count_re
1266 
1267  pos = 0
1268  while pos < nlines:
1269  summ = {}
1270  # find first line of block:
1271  match = h_count_re.search(outlines[pos])
1272  while pos < nlines and not match:
1273  pos += 1
1274  match = h_count_re.search(outlines[pos])
1275  if match:
1276  summ, pos = parseHistosSummary(outlines, pos)
1277  summaries.update(summ)
1278  return summaries
1279 
1280 
def findHistosSummaries(stdout)
Definition: BaseTest.py:1258
def parseHistosSummary(lines, pos)
Definition: BaseTest.py:1188
def GaudiTesting.BaseTest.findTTreeSummaries (   stdout)
    Scan stdout to find ROOT TTree summaries and digest them.

Definition at line 1064 of file BaseTest.py.

1065  """
1066  Scan stdout to find ROOT TTree summaries and digest them.
1067  """
1068  stars = re.compile(r"^\*+$")
1069  outlines = stdout.splitlines()
1070  nlines = len(outlines)
1071  trees = {}
1072 
1073  i = 0
1074  while i < nlines: # loop over the output
1075  # look for
1076  while i < nlines and not stars.match(outlines[i]):
1077  i += 1
1078  if i < nlines:
1079  tree, i = _parseTTreeSummary(outlines, i)
1080  if tree:
1081  trees[tree["Name"]] = tree
1082 
1083  return trees
1084 
1085 
def _parseTTreeSummary(lines, pos)
Definition: BaseTest.py:1136
def findTTreeSummaries(stdout)
Definition: BaseTest.py:1064
def GaudiTesting.BaseTest.getCmpFailingValues (   reference,
  to_check,
  fail_path 
)

Definition at line 1120 of file BaseTest.py.

1120 def getCmpFailingValues(reference, to_check, fail_path):
1121  c = to_check
1122  r = reference
1123  for k in fail_path:
1124  c = c.get(k, None)
1125  r = r.get(k, None)
1126  if c is None or r is None:
1127  break # one of the dictionaries is not deep enough
1128  return (fail_path, r, c)
1129 
1130 
1131 # signature of the print-out of the histograms
def getCmpFailingValues(reference, to_check, fail_path)
Definition: BaseTest.py:1120
def GaudiTesting.BaseTest.GetPlatform (   self)
    Return the platform Id defined in CMTCONFIG or SCRAM_ARCH.

Definition at line 1295 of file BaseTest.py.

1295 def GetPlatform(self):
1296  """
1297  Return the platform Id defined in CMTCONFIG or SCRAM_ARCH.
1298  """
1299  arch = "None"
1300  # check architecture name
1301  if "BINARY_TAG" in os.environ:
1302  arch = os.environ["BINARY_TAG"]
1303  elif "CMTCONFIG" in os.environ:
1304  arch = os.environ["CMTCONFIG"]
1305  elif "SCRAM_ARCH" in os.environ:
1306  arch = os.environ["SCRAM_ARCH"]
1307  return arch
1308 
1309 
def GetPlatform(self)
Definition: BaseTest.py:1295
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 1310 of file BaseTest.py.

1310 def isWinPlatform(self):
1311  """
1312  Return True if the current platform is Windows.
1313 
1314  This function was needed because of the change in the CMTCONFIG format,
1315  from win32_vc71_dbg to i686-winxp-vc9-dbg.
1316  """
1317  platform = GetPlatform(self)
1318  return "winxp" in platform or platform.startswith("win")
1319 
def GetPlatform(self)
Definition: BaseTest.py:1295
def isWinPlatform(self)
Definition: BaseTest.py:1310
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 44 of file BaseTest.py.

44 def kill_tree(ppid, sig):
45  '''
46  Send a signal to a process and all its child processes (starting from the
47  leaves).
48  '''
49  log = logging.getLogger('kill_tree')
50  ps_cmd = ['ps', '--no-headers', '-o', 'pid', '--ppid', str(ppid)]
51  get_children = Popen(ps_cmd, stdout=PIPE, stderr=PIPE)
52  children = map(int, get_children.communicate()[0].split())
53  for child in children:
54  kill_tree(child, sig)
55  try:
56  log.debug('killing process %d', ppid)
57  os.kill(ppid, sig)
58  except OSError, err:
59  if err.errno != 3: # No such process
60  raise
61  log.debug('no such process %d', ppid)
62 
63 
64 # -------------------------------------------------------------------------#
65 
66 
struct GAUDI_API map
Parametrisation class for map-like implementation.
def kill_tree(ppid, sig)
Definition: BaseTest.py:44
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 1188 of file BaseTest.py.

1188 def parseHistosSummary(lines, pos):
1189  """
1190  Extract the histograms infos from the lines starting at pos.
1191  Returns the position of the first line after the summary block.
1192  """
1193  global h_count_re
1194  h_table_head = re.compile(
1195  r'SUCCESS\s+(1D|2D|3D|1D profile|2D profile) histograms in directory\s+"(\w*)"'
1196  )
1197  h_short_summ = re.compile(r"ID=([^\"]+)\s+\"([^\"]+)\"\s+(.*)")
1198 
1199  nlines = len(lines)
1200 
1201  # decode header
1202  m = h_count_re.search(lines[pos])
1203  name = m.group(1).strip()
1204  total = int(m.group(2))
1205  header = {}
1206  for k, v in [x.split("=") for x in m.group(3).split()]:
1207  header[k] = int(v)
1208  pos += 1
1209  header["Total"] = total
1210 
1211  summ = {}
1212  while pos < nlines:
1213  m = h_table_head.search(lines[pos])
1214  if m:
1215  t, d = m.groups(1) # type and directory
1216  t = t.replace(" profile", "Prof")
1217  pos += 1
1218  if pos < nlines:
1219  l = lines[pos]
1220  else:
1221  l = ""
1222  cont = {}
1223  if l.startswith(" | ID"):
1224  # table format
1225  titles = [x.strip() for x in l.split("|")][1:]
1226  pos += 1
1227  while pos < nlines and lines[pos].startswith(" |"):
1228  l = lines[pos]
1229  values = [x.strip() for x in l.split("|")][1:]
1230  hcont = {}
1231  for i in range(len(titles)):
1232  hcont[titles[i]] = values[i]
1233  cont[hcont["ID"]] = hcont
1234  pos += 1
1235  elif l.startswith(" ID="):
1236  while pos < nlines and lines[pos].startswith(" ID="):
1237  values = [
1238  x.strip()
1239  for x in h_short_summ.search(lines[pos]).groups()
1240  ]
1241  cont[values[0]] = values
1242  pos += 1
1243  else: # not interpreted
1244  raise RuntimeError(
1245  "Cannot understand line %d: '%s'" % (pos, l))
1246  if not d in summ:
1247  summ[d] = {}
1248  summ[d][t] = cont
1249  summ[d]["header"] = header
1250  else:
1251  break
1252  if not summ:
1253  # If the full table is not present, we use only the header
1254  summ[name] = {"header": header}
1255  return summ, pos
1256 
1257 
decltype(auto) range(Args &&...args)
Zips multiple containers together to form a single range.
def parseHistosSummary(lines, pos)
Definition: BaseTest.py:1188
def GaudiTesting.BaseTest.PlatformIsNotSupported (   self,
  context,
  result 
)

Definition at line 1281 of file BaseTest.py.

1281 def PlatformIsNotSupported(self, context, result):
1282  platform = GetPlatform(self)
1283  unsupported = [
1284  re.compile(x) for x in [str(y).strip() for y in unsupported_platforms]
1285  if x
1286  ]
1287  for p_re in unsupported:
1288  if p_re.search(platform):
1289  result.SetOutcome(result.UNTESTED)
1290  result[result.CAUSE] = 'Platform not supported.'
1291  return True
1292  return False
1293 
1294 
def GetPlatform(self)
Definition: BaseTest.py:1295
def PlatformIsNotSupported(self, context, result)
Definition: BaseTest.py:1281
def GaudiTesting.BaseTest.RationalizePath (   p)
Function used to normalize the used path

Definition at line 622 of file BaseTest.py.

623  """
624  Function used to normalize the used path
625  """
626  newPath = os.path.normpath(os.path.expandvars(p))
627  if os.path.exists(newPath):
628  p = os.path.realpath(newPath)
629  return p
630 
631 
def GaudiTesting.BaseTest.ROOT6WorkAroundEnabled (   id = None)

Definition at line 614 of file BaseTest.py.

615  # dummy implementation
616  return False
617 
618 
619 # --------------------------------- TOOLS ---------------------------------#
620 
621 
def ROOT6WorkAroundEnabled(id=None)
Definition: BaseTest.py:614
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 
32  return bad_chars.sub(quote, data)
33 
34 
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 632 of file BaseTest.py.

632 def which(executable):
633  """
634  Locates an executable in the executables path ($PATH) and returns the full
635  path to it. An application is looked for with or without the '.exe' suffix.
636  If the executable cannot be found, None is returned
637  """
638  if os.path.isabs(executable):
639  if not os.path.exists(executable):
640  if executable.endswith('.exe'):
641  if os.path.exists(executable[:-4]):
642  return executable[:-4]
643  else:
644  head, executable = os.path.split(executable)
645  else:
646  return executable
647  for d in os.environ.get("PATH").split(os.pathsep):
648  fullpath = os.path.join(d, executable)
649  if os.path.exists(fullpath):
650  return fullpath
651  if executable.endswith('.exe'):
652  return which(executable[:-4])
653  return None
654 
655 
656 # -------------------------------------------------------------------------#
657 # ----------------------------- Result Classe -----------------------------#
658 # -------------------------------------------------------------------------#
def which(executable)
Definition: BaseTest.py:632

Variable Documentation

GaudiTesting.BaseTest.__processLine__
private

Definition at line 854 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 1132 of file BaseTest.py.

GaudiTesting.BaseTest.lineSkipper

Definition at line 933 of file BaseTest.py.

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

Definition at line 849 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 850 of file BaseTest.py.

GaudiTesting.BaseTest.normalizeEOL = FilePreprocessor()

Definition at line 853 of file BaseTest.py.

tuple GaudiTesting.BaseTest.normalizeExamples = maskPointers+normalizeDate

Definition at line 904 of file BaseTest.py.

GaudiTesting.BaseTest.regexps

Definition at line 1016 of file BaseTest.py.

GaudiTesting.BaseTest.skipEmptyLines = FilePreprocessor()

Definition at line 856 of file BaseTest.py.