The Gaudi Framework  v32r0 (3325bb39)
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 1138 of file BaseTest.py.

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

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

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

Definition at line 1066 of file BaseTest.py.

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

Definition at line 1122 of file BaseTest.py.

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

Definition at line 1297 of file BaseTest.py.

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

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

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

Definition at line 1283 of file BaseTest.py.

1283 def PlatformIsNotSupported(self, context, result):
1284  platform = GetPlatform(self)
1285  unsupported = [
1286  re.compile(x) for x in [str(y).strip() for y in unsupported_platforms]
1287  if x
1288  ]
1289  for p_re in unsupported:
1290  if p_re.search(platform):
1291  result.SetOutcome(result.UNTESTED)
1292  result[result.CAUSE] = 'Platform not supported.'
1293  return True
1294  return False
1295 
1296 
def GetPlatform(self)
Definition: BaseTest.py:1297
def PlatformIsNotSupported(self, context, result)
Definition: BaseTest.py:1283
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 1134 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 1018 of file BaseTest.py.

GaudiTesting.BaseTest.skipEmptyLines = FilePreprocessor()

Definition at line 856 of file BaseTest.py.