Loading [MathJax]/extensions/tex2jax.js
The Gaudi Framework  v32r2 (46d42edc)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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 _new_backslashreplace_errors (exc)
 
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

◆ _new_backslashreplace_errors()

def GaudiTesting.BaseTest._new_backslashreplace_errors (   exc)
private

Definition at line 23 of file BaseTest.py.

24  if isinstance(exc, UnicodeDecodeError):
25  code = hex(ord(exc.object[exc.start]))
26  return (u'\\' + code[1:], exc.start + 1)
27  else:
28  return backslashreplace_errors(exc)
29 
MsgStream & hex(MsgStream &log)
Definition: MsgStream.h:271
def _new_backslashreplace_errors(exc)
Definition: BaseTest.py:23

◆ _parseTTreeSummary()

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 1160 of file BaseTest.py.

1160 def _parseTTreeSummary(lines, pos):
1161  """
1162  Parse the TTree summary table in lines, starting from pos.
1163  Returns a tuple with the dictionary with the digested informations and the
1164  position of the first line after the summary.
1165  """
1166  result = {}
1167  i = pos + 1 # first line is a sequence of '*'
1168  count = len(lines)
1169 
1170  def splitcols(l):
1171  return [f.strip() for f in l.strip("*\n").split(':', 2)]
1172 
1173  def parseblock(ll):
1174  r = {}
1175  cols = splitcols(ll[0])
1176  r["Name"], r["Title"] = cols[1:]
1177 
1178  cols = splitcols(ll[1])
1179  r["Entries"] = int(cols[1])
1180 
1181  sizes = cols[2].split()
1182  r["Total size"] = int(sizes[2])
1183  if sizes[-1] == "memory":
1184  r["File size"] = 0
1185  else:
1186  r["File size"] = int(sizes[-1])
1187 
1188  cols = splitcols(ll[2])
1189  sizes = cols[2].split()
1190  if cols[0] == "Baskets":
1191  r["Baskets"] = int(cols[1])
1192  r["Basket size"] = int(sizes[2])
1193  r["Compression"] = float(sizes[-1])
1194  return r
1195 
1196  if i < (count - 3) and lines[i].startswith("*Tree"):
1197  result = parseblock(lines[i:i + 3])
1198  result["Branches"] = {}
1199  i += 4
1200  while i < (count - 3) and lines[i].startswith("*Br"):
1201  if i < (count - 2) and lines[i].startswith("*Branch "):
1202  # skip branch header
1203  i += 3
1204  continue
1205  branch = parseblock(lines[i:i + 3])
1206  result["Branches"][branch["Name"]] = branch
1207  i += 4
1208 
1209  return (result, i)
1210 
1211 
def _parseTTreeSummary(lines, pos)
Definition: BaseTest.py:1160

◆ cmpTreesDicts()

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 1110 of file BaseTest.py.

1110 def cmpTreesDicts(reference, to_check, ignore=None):
1111  """
1112  Check that all the keys in reference are in to_check too, with the same value.
1113  If the value is a dict, the function is called recursively. to_check can
1114  contain more keys than reference, that will not be tested.
1115  The function returns at the first difference found.
1116  """
1117  fail_keys = []
1118  # filter the keys in the reference dictionary
1119  if ignore:
1120  ignore_re = re.compile(ignore)
1121  keys = [key for key in reference if not ignore_re.match(key)]
1122  else:
1123  keys = reference.keys()
1124  # loop over the keys (not ignored) in the reference dictionary
1125  for k in keys:
1126  if k in to_check: # the key must be in the dictionary to_check
1127  if (type(reference[k]) is dict) and (type(to_check[k]) is dict):
1128  # if both reference and to_check values are dictionaries,
1129  # recurse
1130  failed = fail_keys = cmpTreesDicts(reference[k], to_check[k],
1131  ignore)
1132  else:
1133  # compare the two values
1134  failed = to_check[k] != reference[k]
1135  else: # handle missing keys in the dictionary to check (i.e. failure)
1136  to_check[k] = None
1137  failed = True
1138  if failed:
1139  fail_keys.insert(0, k)
1140  break # exit from the loop at the first failure
1141  return fail_keys # return the list of keys bringing to the different values
1142 
1143 
def cmpTreesDicts(reference, to_check, ignore=None)
Definition: BaseTest.py:1110

◆ dumpProcs()

def GaudiTesting.BaseTest.dumpProcs (   name)
helper to debug GAUDI-1084, dump the list of processes

Definition at line 54 of file BaseTest.py.

54 def dumpProcs(name):
55  '''helper to debug GAUDI-1084, dump the list of processes'''
56  from getpass import getuser
57  if 'WORKSPACE' in os.environ:
58  p = Popen(['ps', '-fH', '-U', getuser()], stdout=PIPE)
59  with open(os.path.join(os.environ['WORKSPACE'], name), 'wb') as f:
60  f.write(p.communicate()[0])
61 
62 
def dumpProcs(name)
Definition: BaseTest.py:54

◆ findHistosSummaries()

def GaudiTesting.BaseTest.findHistosSummaries (   stdout)
    Scan stdout to find ROOT TTree summaries and digest them.

Definition at line 1282 of file BaseTest.py.

1282 def findHistosSummaries(stdout):
1283  """
1284  Scan stdout to find ROOT TTree summaries and digest them.
1285  """
1286  outlines = stdout.splitlines()
1287  nlines = len(outlines) - 1
1288  summaries = {}
1289  global h_count_re
1290 
1291  pos = 0
1292  while pos < nlines:
1293  summ = {}
1294  # find first line of block:
1295  match = h_count_re.search(outlines[pos])
1296  while pos < nlines and not match:
1297  pos += 1
1298  match = h_count_re.search(outlines[pos])
1299  if match:
1300  summ, pos = parseHistosSummary(outlines, pos)
1301  summaries.update(summ)
1302  return summaries
1303 
1304 
def findHistosSummaries(stdout)
Definition: BaseTest.py:1282
def parseHistosSummary(lines, pos)
Definition: BaseTest.py:1212

◆ findTTreeSummaries()

def GaudiTesting.BaseTest.findTTreeSummaries (   stdout)
    Scan stdout to find ROOT TTree summaries and digest them.

Definition at line 1088 of file BaseTest.py.

1088 def findTTreeSummaries(stdout):
1089  """
1090  Scan stdout to find ROOT TTree summaries and digest them.
1091  """
1092  stars = re.compile(r"^\*+$")
1093  outlines = stdout.splitlines()
1094  nlines = len(outlines)
1095  trees = {}
1096 
1097  i = 0
1098  while i < nlines: # loop over the output
1099  # look for
1100  while i < nlines and not stars.match(outlines[i]):
1101  i += 1
1102  if i < nlines:
1103  tree, i = _parseTTreeSummary(outlines, i)
1104  if tree:
1105  trees[tree["Name"]] = tree
1106 
1107  return trees
1108 
1109 
def _parseTTreeSummary(lines, pos)
Definition: BaseTest.py:1160
def findTTreeSummaries(stdout)
Definition: BaseTest.py:1088

◆ getCmpFailingValues()

def GaudiTesting.BaseTest.getCmpFailingValues (   reference,
  to_check,
  fail_path 
)

Definition at line 1144 of file BaseTest.py.

1144 def getCmpFailingValues(reference, to_check, fail_path):
1145  c = to_check
1146  r = reference
1147  for k in fail_path:
1148  c = c.get(k, None)
1149  r = r.get(k, None)
1150  if c is None or r is None:
1151  break # one of the dictionaries is not deep enough
1152  return (fail_path, r, c)
1153 
1154 
1155 # signature of the print-out of the histograms
def getCmpFailingValues(reference, to_check, fail_path)
Definition: BaseTest.py:1144

◆ GetPlatform()

def GaudiTesting.BaseTest.GetPlatform (   self)
    Return the platform Id defined in CMTCONFIG or SCRAM_ARCH.

Definition at line 1319 of file BaseTest.py.

1319 def GetPlatform(self):
1320  """
1321  Return the platform Id defined in CMTCONFIG or SCRAM_ARCH.
1322  """
1323  arch = "None"
1324  # check architecture name
1325  if "BINARY_TAG" in os.environ:
1326  arch = os.environ["BINARY_TAG"]
1327  elif "CMTCONFIG" in os.environ:
1328  arch = os.environ["CMTCONFIG"]
1329  elif "SCRAM_ARCH" in os.environ:
1330  arch = os.environ["SCRAM_ARCH"]
1331  return arch
1332 
1333 
def GetPlatform(self)
Definition: BaseTest.py:1319

◆ isWinPlatform()

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 1334 of file BaseTest.py.

1334 def isWinPlatform(self):
1335  """
1336  Return True if the current platform is Windows.
1337 
1338  This function was needed because of the change in the CMTCONFIG format,
1339  from win32_vc71_dbg to i686-winxp-vc9-dbg.
1340  """
1341  platform = GetPlatform(self)
1342  return "winxp" in platform or platform.startswith("win")
def GetPlatform(self)
Definition: BaseTest.py:1319
def isWinPlatform(self)
Definition: BaseTest.py:1334

◆ kill_tree()

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 63 of file BaseTest.py.

63 def kill_tree(ppid, sig):
64  '''
65  Send a signal to a process and all its child processes (starting from the
66  leaves).
67  '''
68  log = logging.getLogger('kill_tree')
69  ps_cmd = ['ps', '--no-headers', '-o', 'pid', '--ppid', str(ppid)]
70  get_children = Popen(ps_cmd, stdout=PIPE, stderr=PIPE)
71  children = map(int, get_children.communicate()[0].split())
72  for child in children:
73  kill_tree(child, sig)
74  try:
75  log.debug('killing process %d', ppid)
76  os.kill(ppid, sig)
77  except OSError as err:
78  if err.errno != 3: # No such process
79  raise
80  log.debug('no such process %d', ppid)
81 
82 
83 # -------------------------------------------------------------------------#
84 
85 
struct GAUDI_API map
Parametrisation class for map-like implementation.
def kill_tree(ppid, sig)
Definition: BaseTest.py:63

◆ parseHistosSummary()

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 1212 of file BaseTest.py.

1212 def parseHistosSummary(lines, pos):
1213  """
1214  Extract the histograms infos from the lines starting at pos.
1215  Returns the position of the first line after the summary block.
1216  """
1217  global h_count_re
1218  h_table_head = re.compile(
1219  r'SUCCESS\s+(1D|2D|3D|1D profile|2D profile) histograms in directory\s+"(\w*)"'
1220  )
1221  h_short_summ = re.compile(r"ID=([^\"]+)\s+\"([^\"]+)\"\s+(.*)")
1222 
1223  nlines = len(lines)
1224 
1225  # decode header
1226  m = h_count_re.search(lines[pos])
1227  name = m.group(1).strip()
1228  total = int(m.group(2))
1229  header = {}
1230  for k, v in [x.split("=") for x in m.group(3).split()]:
1231  header[k] = int(v)
1232  pos += 1
1233  header["Total"] = total
1234 
1235  summ = {}
1236  while pos < nlines:
1237  m = h_table_head.search(lines[pos])
1238  if m:
1239  t, d = m.groups(1) # type and directory
1240  t = t.replace(" profile", "Prof")
1241  pos += 1
1242  if pos < nlines:
1243  l = lines[pos]
1244  else:
1245  l = ""
1246  cont = {}
1247  if l.startswith(" | ID"):
1248  # table format
1249  titles = [x.strip() for x in l.split("|")][1:]
1250  pos += 1
1251  while pos < nlines and lines[pos].startswith(" |"):
1252  l = lines[pos]
1253  values = [x.strip() for x in l.split("|")][1:]
1254  hcont = {}
1255  for i in range(len(titles)):
1256  hcont[titles[i]] = values[i]
1257  cont[hcont["ID"]] = hcont
1258  pos += 1
1259  elif l.startswith(" ID="):
1260  while pos < nlines and lines[pos].startswith(" ID="):
1261  values = [
1262  x.strip()
1263  for x in h_short_summ.search(lines[pos]).groups()
1264  ]
1265  cont[values[0]] = values
1266  pos += 1
1267  else: # not interpreted
1268  raise RuntimeError(
1269  "Cannot understand line %d: '%s'" % (pos, l))
1270  if not d in summ:
1271  summ[d] = {}
1272  summ[d][t] = cont
1273  summ[d]["header"] = header
1274  else:
1275  break
1276  if not summ:
1277  # If the full table is not present, we use only the header
1278  summ[name] = {"header": header}
1279  return summ, pos
1280 
1281 
def parseHistosSummary(lines, pos)
Definition: BaseTest.py:1212
decltype(auto) range(Args &&... args)
Zips multiple containers together to form a single range.

◆ PlatformIsNotSupported()

def GaudiTesting.BaseTest.PlatformIsNotSupported (   self,
  context,
  result 
)

Definition at line 1305 of file BaseTest.py.

1305 def PlatformIsNotSupported(self, context, result):
1306  platform = GetPlatform(self)
1307  unsupported = [
1308  re.compile(x) for x in [str(y).strip() for y in unsupported_platforms]
1309  if x
1310  ]
1311  for p_re in unsupported:
1312  if p_re.search(platform):
1313  result.SetOutcome(result.UNTESTED)
1314  result[result.CAUSE] = 'Platform not supported.'
1315  return True
1316  return False
1317 
1318 
def GetPlatform(self)
Definition: BaseTest.py:1319
def PlatformIsNotSupported(self, context, result)
Definition: BaseTest.py:1305

◆ RationalizePath()

def GaudiTesting.BaseTest.RationalizePath (   p)
Function used to normalize the used path

Definition at line 645 of file BaseTest.py.

645 def RationalizePath(p):
646  """
647  Function used to normalize the used path
648  """
649  newPath = os.path.normpath(os.path.expandvars(p))
650  if os.path.exists(newPath):
651  p = os.path.realpath(newPath)
652  return p
653 
654 

◆ ROOT6WorkAroundEnabled()

def GaudiTesting.BaseTest.ROOT6WorkAroundEnabled (   id = None)

Definition at line 637 of file BaseTest.py.

637  def ROOT6WorkAroundEnabled(id=None):
638  # dummy implementation
639  return False
640 
641 
642 # --------------------------------- TOOLS ---------------------------------#
643 
644 
def ROOT6WorkAroundEnabled(id=None)
Definition: BaseTest.py:637

◆ sanitize_for_xml()

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 36 of file BaseTest.py.

36 def sanitize_for_xml(data):
37  '''
38  Take a string with invalid ASCII/UTF characters and quote them so that the
39  string can be used in an XML text.
40 
41  >>> sanitize_for_xml('this is \x1b')
42  'this is [NON-XML-CHAR-0x1B]'
43  '''
44  bad_chars = re.compile(
45  u'[\x00-\x08\x0b\x0c\x0e-\x1F\uD800-\uDFFF\uFFFE\uFFFF]')
46 
47  def quote(match):
48  'helper function'
49  return ''.join('[NON-XML-CHAR-0x%2X]' % ord(c) for c in match.group())
50 
51  return bad_chars.sub(quote, data)
52 
53 
def sanitize_for_xml(data)
Definition: BaseTest.py:36

◆ which()

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 655 of file BaseTest.py.

655 def which(executable):
656  """
657  Locates an executable in the executables path ($PATH) and returns the full
658  path to it. An application is looked for with or without the '.exe' suffix.
659  If the executable cannot be found, None is returned
660  """
661  if os.path.isabs(executable):
662  if not os.path.exists(executable):
663  if executable.endswith('.exe'):
664  if os.path.exists(executable[:-4]):
665  return executable[:-4]
666  else:
667  head, executable = os.path.split(executable)
668  else:
669  return executable
670  for d in os.environ.get("PATH").split(os.pathsep):
671  fullpath = os.path.join(d, executable)
672  if os.path.exists(fullpath):
673  return fullpath
674  if executable.endswith('.exe'):
675  return which(executable[:-4])
676  return None
677 
678 
679 # -------------------------------------------------------------------------#
680 # ----------------------------- Result Classe -----------------------------#
681 # -------------------------------------------------------------------------#
def which(executable)
Definition: BaseTest.py:655

Variable Documentation

◆ __processLine__

GaudiTesting.BaseTest.__processLine__
private

Definition at line 878 of file BaseTest.py.

◆ h_count_re

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

Definition at line 1156 of file BaseTest.py.

◆ lineSkipper

GaudiTesting.BaseTest.lineSkipper

Definition at line 957 of file BaseTest.py.

◆ maskPointers

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

Definition at line 873 of file BaseTest.py.

◆ normalizeDate

GaudiTesting.BaseTest.normalizeDate
Initial value:
1 = RegexpReplacer(
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 874 of file BaseTest.py.

◆ normalizeEOL

GaudiTesting.BaseTest.normalizeEOL = FilePreprocessor()

Definition at line 877 of file BaseTest.py.

◆ normalizeExamples

tuple GaudiTesting.BaseTest.normalizeExamples = maskPointers + normalizeDate

Definition at line 928 of file BaseTest.py.

◆ regexps

GaudiTesting.BaseTest.regexps

Definition at line 1040 of file BaseTest.py.

◆ skipEmptyLines

GaudiTesting.BaseTest.skipEmptyLines = FilePreprocessor()

Definition at line 880 of file BaseTest.py.