The Gaudi Framework  v37r1 (a7f61348)
GaudiTesting.BaseTest Namespace Reference

Classes

class  BaseTest
 
class  BasicOutputValidator
 
class  BlockSkipper
 
class  FilePreprocessor
 
class  FilePreprocessorSequence
 
class  JSONOutputValidator
 
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 GetPlatform (self)
 
def isWinPlatform (self)
 

Variables

 SKIP_RETURN_CODE
 
 maskPointers
 
 normalizeDate
 
 normalizeEOL
 
 __processLine__
 
 skipEmptyLines
 
 normalizeExamples
 
 lineSkipper
 
list regexps
 
 h_count_re
 

Function Documentation

◆ _new_backslashreplace_errors()

def GaudiTesting.BaseTest._new_backslashreplace_errors (   exc)
private

Definition at line 37 of file BaseTest.py.

38  if isinstance(exc, UnicodeDecodeError):
39  code = hex(ord(exc.object[exc.start]))
40  return ("\\" + code[1:], exc.start + 1)
41  else:
42  return backslashreplace_errors(exc)
43 

◆ _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 1281 of file BaseTest.py.

1281 def _parseTTreeSummary(lines, pos):
1282  """
1283  Parse the TTree summary table in lines, starting from pos.
1284  Returns a tuple with the dictionary with the digested informations and the
1285  position of the first line after the summary.
1286  """
1287  result = {}
1288  i = pos + 1 # first line is a sequence of '*'
1289  count = len(lines)
1290 
1291  def splitcols(l):
1292  return [f.strip() for f in l.strip("*\n").split(":", 2)]
1293 
1294  def parseblock(ll):
1295  r = {}
1296  delta_i = 0
1297  cols = splitcols(ll[0])
1298 
1299  if len(ll) == 3:
1300  # default one line name/title
1301  r["Name"], r["Title"] = cols[1:]
1302  elif len(ll) == 4:
1303  # in case title is moved to next line due to too long name
1304  delta_i = 1
1305  r["Name"] = cols[1]
1306  r["Title"] = ll[1].strip("*\n").split("|")[1].strip()
1307  else:
1308  assert False
1309 
1310  cols = splitcols(ll[1 + delta_i])
1311  r["Entries"] = int(cols[1])
1312 
1313  sizes = cols[2].split()
1314  r["Total size"] = int(sizes[2])
1315  if sizes[-1] == "memory":
1316  r["File size"] = 0
1317  else:
1318  r["File size"] = int(sizes[-1])
1319 
1320  cols = splitcols(ll[2 + delta_i])
1321  sizes = cols[2].split()
1322  if cols[0] == "Baskets":
1323  r["Baskets"] = int(cols[1])
1324  r["Basket size"] = int(sizes[2])
1325  r["Compression"] = float(sizes[-1])
1326 
1327  return r
1328 
1329  def nextblock(lines, i):
1330  delta_i = 1
1331  dots = re.compile(r"^\.+$")
1332  stars = re.compile(r"^\*+$")
1333  count = len(lines)
1334  while (
1335  i + delta_i < count
1336  and not dots.match(lines[i + delta_i][1:-1])
1337  and not stars.match(lines[i + delta_i])
1338  ):
1339  delta_i += 1
1340  return i + delta_i
1341 
1342  if i < (count - 3) and lines[i].startswith("*Tree"):
1343  i_nextblock = nextblock(lines, i)
1344  result = parseblock(lines[i:i_nextblock])
1345  result["Branches"] = {}
1346  i = i_nextblock + 1
1347  while i < (count - 3) and lines[i].startswith("*Br"):
1348  if i < (count - 2) and lines[i].startswith("*Branch "):
1349  # skip branch header
1350  i += 3
1351  continue
1352  i_nextblock = nextblock(lines, i)
1353  if i_nextblock >= count:
1354  break
1355  branch = parseblock(lines[i:i_nextblock])
1356  result["Branches"][branch["Name"]] = branch
1357  i = i_nextblock + 1
1358 
1359  return (result, i)
1360 
1361 

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

1233 def cmpTreesDicts(reference, to_check, ignore=None):
1234  """
1235  Check that all the keys in reference are in to_check too, with the same value.
1236  If the value is a dict, the function is called recursively. to_check can
1237  contain more keys than reference, that will not be tested.
1238  The function returns at the first difference found.
1239  """
1240  fail_keys = []
1241  # filter the keys in the reference dictionary
1242  if ignore:
1243  ignore_re = re.compile(ignore)
1244  keys = [key for key in reference if not ignore_re.match(key)]
1245  else:
1246  keys = reference.keys()
1247  # loop over the keys (not ignored) in the reference dictionary
1248  for k in keys:
1249  if k in to_check: # the key must be in the dictionary to_check
1250  if (type(reference[k]) is dict) and (type(to_check[k]) is dict):
1251  # if both reference and to_check values are dictionaries,
1252  # recurse
1253  failed = fail_keys = cmpTreesDicts(reference[k], to_check[k], ignore)
1254  else:
1255  # compare the two values
1256  failed = to_check[k] != reference[k]
1257  else: # handle missing keys in the dictionary to check (i.e. failure)
1258  to_check[k] = None
1259  failed = True
1260  if failed:
1261  fail_keys.insert(0, k)
1262  break # exit from the loop at the first failure
1263  return fail_keys # return the list of keys bringing to the different values
1264 
1265 

◆ dumpProcs()

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

Definition at line 69 of file BaseTest.py.

69 def dumpProcs(name):
70  """helper to debug GAUDI-1084, dump the list of processes"""
71  from getpass import getuser
72 
73  if "WORKSPACE" in os.environ:
74  p = Popen(["ps", "-fH", "-U", getuser()], stdout=PIPE)
75  with open(os.path.join(os.environ["WORKSPACE"], name), "wb") as f:
76  f.write(p.communicate()[0])
77 
78 

◆ findHistosSummaries()

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

Definition at line 1430 of file BaseTest.py.

1430 def findHistosSummaries(stdout):
1431  """
1432  Scan stdout to find ROOT TTree summaries and digest them.
1433  """
1434  outlines = stdout.splitlines()
1435  nlines = len(outlines) - 1
1436  summaries = {}
1437  global h_count_re
1438 
1439  pos = 0
1440  while pos < nlines:
1441  summ = {}
1442  # find first line of block:
1443  match = h_count_re.search(outlines[pos])
1444  while pos < nlines and not match:
1445  pos += 1
1446  match = h_count_re.search(outlines[pos])
1447  if match:
1448  summ, pos = parseHistosSummary(outlines, pos)
1449  summaries.update(summ)
1450  return summaries
1451 
1452 

◆ findTTreeSummaries()

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

Definition at line 1211 of file BaseTest.py.

1211 def findTTreeSummaries(stdout):
1212  """
1213  Scan stdout to find ROOT TTree summaries and digest them.
1214  """
1215  stars = re.compile(r"^\*+$")
1216  outlines = stdout.splitlines()
1217  nlines = len(outlines)
1218  trees = {}
1219 
1220  i = 0
1221  while i < nlines: # loop over the output
1222  # look for
1223  while i < nlines and not stars.match(outlines[i]):
1224  i += 1
1225  if i < nlines:
1226  tree, i = _parseTTreeSummary(outlines, i)
1227  if tree:
1228  trees[tree["Name"]] = tree
1229 
1230  return trees
1231 
1232 

◆ getCmpFailingValues()

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

Definition at line 1266 of file BaseTest.py.

1266 def getCmpFailingValues(reference, to_check, fail_path):
1267  c = to_check
1268  r = reference
1269  for k in fail_path:
1270  c = c.get(k, None)
1271  r = r.get(k, None)
1272  if c is None or r is None:
1273  break # one of the dictionaries is not deep enough
1274  return (fail_path, r, c)
1275 
1276 
1277 # signature of the print-out of the histograms

◆ GetPlatform()

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

Definition at line 1453 of file BaseTest.py.

1453 def GetPlatform(self):
1454  """
1455  Return the platform Id defined in CMTCONFIG or SCRAM_ARCH.
1456  """
1457  arch = "None"
1458  # check architecture name
1459  if "BINARY_TAG" in os.environ:
1460  arch = os.environ["BINARY_TAG"]
1461  elif "CMTCONFIG" in os.environ:
1462  arch = os.environ["CMTCONFIG"]
1463  elif "SCRAM_ARCH" in os.environ:
1464  arch = os.environ["SCRAM_ARCH"]
1465  elif os.environ.get("ENV_CMAKE_BUILD_TYPE", "") in (
1466  "Debug",
1467  "FastDebug",
1468  "Developer",
1469  ):
1470  arch = "dummy-dbg"
1471  elif os.environ.get("ENV_CMAKE_BUILD_TYPE", "") in (
1472  "Release",
1473  "MinSizeRel",
1474  "RelWithDebInfo",
1475  "",
1476  ): # RelWithDebInfo == -O2 -g -DNDEBUG
1477  arch = "dummy-opt"
1478  return arch
1479 
1480 

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

1481 def isWinPlatform(self):
1482  """
1483  Return True if the current platform is Windows.
1484 
1485  This function was needed because of the change in the CMTCONFIG format,
1486  from win32_vc71_dbg to i686-winxp-vc9-dbg.
1487  """
1488  platform = GetPlatform(self)
1489  return "winxp" in platform or platform.startswith("win")
1490 
1491 

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

79 def kill_tree(ppid, sig):
80  """
81  Send a signal to a process and all its child processes (starting from the
82  leaves).
83  """
84  log = logging.getLogger("kill_tree")
85  ps_cmd = ["ps", "--no-headers", "-o", "pid", "--ppid", str(ppid)]
86  # Note: start in a clean env to avoid a freeze with libasan.so
87  # See https://sourceware.org/bugzilla/show_bug.cgi?id=27653
88  get_children = Popen(ps_cmd, stdout=PIPE, stderr=PIPE, env={})
89  children = map(int, get_children.communicate()[0].split())
90  for child in children:
91  kill_tree(child, sig)
92  try:
93  log.debug("killing process %d", ppid)
94  os.kill(ppid, sig)
95  except OSError as err:
96  if err.errno != 3: # No such process
97  raise
98  log.debug("no such process %d", ppid)
99 
100 
101 # -------------------------------------------------------------------------#
102 
103 

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

1362 def parseHistosSummary(lines, pos):
1363  """
1364  Extract the histograms infos from the lines starting at pos.
1365  Returns the position of the first line after the summary block.
1366  """
1367  global h_count_re
1368  h_table_head = re.compile(
1369  r'SUCCESS\s+(1D|2D|3D|1D profile|2D profile) histograms in directory\s+"(\w*)"'
1370  )
1371  h_short_summ = re.compile(r"ID=([^\"]+)\s+\"([^\"]+)\"\s+(.*)")
1372 
1373  nlines = len(lines)
1374 
1375  # decode header
1376  m = h_count_re.search(lines[pos])
1377  name = m.group(1).strip()
1378  total = int(m.group(2))
1379  header = {}
1380  for k, v in [x.split("=") for x in m.group(3).split()]:
1381  header[k] = int(v)
1382  pos += 1
1383  header["Total"] = total
1384 
1385  summ = {}
1386  while pos < nlines:
1387  m = h_table_head.search(lines[pos])
1388  if m:
1389  t, d = m.groups(1) # type and directory
1390  t = t.replace(" profile", "Prof")
1391  pos += 1
1392  if pos < nlines:
1393  l = lines[pos]
1394  else:
1395  l = ""
1396  cont = {}
1397  if l.startswith(" | ID"):
1398  # table format
1399  titles = [x.strip() for x in l.split("|")][1:]
1400  pos += 1
1401  while pos < nlines and lines[pos].startswith(" |"):
1402  l = lines[pos]
1403  values = [x.strip() for x in l.split("|")][1:]
1404  hcont = {}
1405  for i in range(len(titles)):
1406  hcont[titles[i]] = values[i]
1407  cont[hcont["ID"]] = hcont
1408  pos += 1
1409  elif l.startswith(" ID="):
1410  while pos < nlines and lines[pos].startswith(" ID="):
1411  values = [
1412  x.strip() for x in h_short_summ.search(lines[pos]).groups()
1413  ]
1414  cont[values[0]] = values
1415  pos += 1
1416  else: # not interpreted
1417  raise RuntimeError("Cannot understand line %d: '%s'" % (pos, l))
1418  if d not in summ:
1419  summ[d] = {}
1420  summ[d][t] = cont
1421  summ[d]["header"] = header
1422  else:
1423  break
1424  if not summ:
1425  # If the full table is not present, we use only the header
1426  summ[name] = {"header": header}
1427  return summ, pos
1428 
1429 

◆ RationalizePath()

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

Definition at line 735 of file BaseTest.py.

735 def RationalizePath(p):
736  """
737  Function used to normalize the used path
738  """
739  newPath = os.path.normpath(os.path.expandvars(p))
740  if os.path.exists(newPath):
741  p = os.path.realpath(newPath)
742  return p
743 
744 

◆ ROOT6WorkAroundEnabled()

def GaudiTesting.BaseTest.ROOT6WorkAroundEnabled (   id = None)

Definition at line 727 of file BaseTest.py.

727  def ROOT6WorkAroundEnabled(id=None):
728  # dummy implementation
729  return False
730 
731 
732 # --------------------------------- TOOLS ---------------------------------#
733 
734 

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

52 def sanitize_for_xml(data):
53  """
54  Take a string with invalid ASCII/UTF characters and quote them so that the
55  string can be used in an XML text.
56 
57  >>> sanitize_for_xml('this is \x1b')
58  'this is [NON-XML-CHAR-0x1B]'
59  """
60  bad_chars = re.compile("[\x00-\x08\x0b\x0c\x0e-\x1F\uD800-\uDFFF\uFFFE\uFFFF]")
61 
62  def quote(match):
63  "helper function"
64  return "".join("[NON-XML-CHAR-0x%2X]" % ord(c) for c in match.group())
65 
66  return bad_chars.sub(quote, data)
67 
68 

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

745 def which(executable):
746  """
747  Locates an executable in the executables path ($PATH) and returns the full
748  path to it. An application is looked for with or without the '.exe' suffix.
749  If the executable cannot be found, None is returned
750  """
751  if os.path.isabs(executable):
752  if not os.path.isfile(executable):
753  if executable.endswith(".exe"):
754  if os.path.isfile(executable[:-4]):
755  return executable[:-4]
756  else:
757  executable = os.path.split(executable)[1]
758  else:
759  return executable
760  for d in os.environ.get("PATH").split(os.pathsep):
761  fullpath = os.path.join(d, executable)
762  if os.path.isfile(fullpath):
763  return fullpath
764  elif executable.endswith(".exe") and os.path.isfile(fullpath[:-4]):
765  return fullpath[:-4]
766  return None
767 
768 
769 # -------------------------------------------------------------------------#
770 # ----------------------------- Result Classe -----------------------------#
771 # -------------------------------------------------------------------------#
772 
773 

Variable Documentation

◆ __processLine__

GaudiTesting.BaseTest.__processLine__
private

Definition at line 971 of file BaseTest.py.

◆ h_count_re

GaudiTesting.BaseTest.h_count_re

Definition at line 1278 of file BaseTest.py.

◆ lineSkipper

GaudiTesting.BaseTest.lineSkipper

Definition at line 1060 of file BaseTest.py.

◆ maskPointers

GaudiTesting.BaseTest.maskPointers

Definition at line 965 of file BaseTest.py.

◆ normalizeDate

GaudiTesting.BaseTest.normalizeDate

Definition at line 966 of file BaseTest.py.

◆ normalizeEOL

GaudiTesting.BaseTest.normalizeEOL

Definition at line 970 of file BaseTest.py.

◆ normalizeExamples

GaudiTesting.BaseTest.normalizeExamples

Definition at line 1021 of file BaseTest.py.

◆ regexps

list GaudiTesting.BaseTest.regexps

Definition at line 1102 of file BaseTest.py.

◆ SKIP_RETURN_CODE

GaudiTesting.BaseTest.SKIP_RETURN_CODE

Definition at line 49 of file BaseTest.py.

◆ skipEmptyLines

GaudiTesting.BaseTest.skipEmptyLines

Definition at line 973 of file BaseTest.py.

MSG::hex
MsgStream & hex(MsgStream &log)
Definition: MsgStream.h:282
GaudiTesting.BaseTest.dumpProcs
def dumpProcs(name)
Definition: BaseTest.py:69
GaudiTesting.BaseTest._parseTTreeSummary
def _parseTTreeSummary(lines, pos)
Definition: BaseTest.py:1281
GaudiTesting.BaseTest.sanitize_for_xml
def sanitize_for_xml(data)
Definition: BaseTest.py:52
GaudiTesting.BaseTest.getCmpFailingValues
def getCmpFailingValues(reference, to_check, fail_path)
Definition: BaseTest.py:1266
GaudiTesting.BaseTest._new_backslashreplace_errors
def _new_backslashreplace_errors(exc)
Definition: BaseTest.py:37
GaudiTesting.BaseTest.kill_tree
def kill_tree(ppid, sig)
Definition: BaseTest.py:79
Containers::map
struct GAUDI_API map
Parametrisation class for map-like implementation.
Definition: KeyedObjectManager.h:35
GaudiTesting.BaseTest.parseHistosSummary
def parseHistosSummary(lines, pos)
Definition: BaseTest.py:1362
GaudiTesting.BaseTest.isWinPlatform
def isWinPlatform(self)
Definition: BaseTest.py:1481
GaudiTesting.BaseTest.which
def which(executable)
Definition: BaseTest.py:745
GaudiTesting.BaseTest.cmpTreesDicts
def cmpTreesDicts(reference, to_check, ignore=None)
Definition: BaseTest.py:1233
GaudiTesting.BaseTest.RationalizePath
def RationalizePath(p)
Definition: BaseTest.py:735
gaudirun.type
type
Definition: gaudirun.py:162
GaudiTesting.BaseTest.findHistosSummaries
def findHistosSummaries(stdout)
Definition: BaseTest.py:1430
GaudiTesting.BaseTest.findTTreeSummaries
def findTTreeSummaries(stdout)
Definition: BaseTest.py:1211
GaudiTesting.BaseTest.ROOT6WorkAroundEnabled
def ROOT6WorkAroundEnabled(id=None)
Definition: BaseTest.py:727
GaudiTesting.BaseTest.GetPlatform
def GetPlatform(self)
Definition: BaseTest.py:1453
Gaudi::Functional::details::zip::range
decltype(auto) range(Args &&... args)
Zips multiple containers together to form a single range.
Definition: details.h:98