The Gaudi Framework  v38r1p1 (ae26267b)
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
 
 normalizeTestSuite
 
 lineSkipper
 
list regexps
 
 normalizeExamples
 
 h_count_re
 

Function Documentation

◆ _new_backslashreplace_errors()

def GaudiTesting.BaseTest._new_backslashreplace_errors (   exc)
private

Definition at line 31 of file BaseTest.py.

32  if isinstance(exc, UnicodeDecodeError):
33  code = hex(ord(exc.object[exc.start]))
34  return ("\\" + code[1:], exc.start + 1)
35  else:
36  return backslashreplace_errors(exc)
37 

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

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

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

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

◆ dumpProcs()

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

Definition at line 63 of file BaseTest.py.

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

◆ findHistosSummaries()

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

Definition at line 1432 of file BaseTest.py.

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

◆ findTTreeSummaries()

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

Definition at line 1213 of file BaseTest.py.

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

◆ getCmpFailingValues()

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

Definition at line 1268 of file BaseTest.py.

1268 def getCmpFailingValues(reference, to_check, fail_path):
1269  c = to_check
1270  r = reference
1271  for k in fail_path:
1272  c = c.get(k, None)
1273  r = r.get(k, None)
1274  if c is None or r is None:
1275  break # one of the dictionaries is not deep enough
1276  return (fail_path, r, c)
1277 
1278 
1279 # 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 1455 of file BaseTest.py.

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

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

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

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

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

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

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

◆ RationalizePath()

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

Definition at line 729 of file BaseTest.py.

729 def RationalizePath(p):
730  """
731  Function used to normalize the used path
732  """
733  newPath = os.path.normpath(os.path.expandvars(p))
734  if os.path.exists(newPath):
735  p = os.path.realpath(newPath)
736  return p
737 
738 

◆ ROOT6WorkAroundEnabled()

def GaudiTesting.BaseTest.ROOT6WorkAroundEnabled (   id = None)

Definition at line 721 of file BaseTest.py.

721  def ROOT6WorkAroundEnabled(id=None):
722  # dummy implementation
723  return False
724 
725 
726 # --------------------------------- TOOLS ---------------------------------#
727 
728 

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

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

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

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

Variable Documentation

◆ __processLine__

GaudiTesting.BaseTest.__processLine__
private

Definition at line 965 of file BaseTest.py.

◆ h_count_re

GaudiTesting.BaseTest.h_count_re

Definition at line 1280 of file BaseTest.py.

◆ lineSkipper

GaudiTesting.BaseTest.lineSkipper

Definition at line 1054 of file BaseTest.py.

◆ maskPointers

GaudiTesting.BaseTest.maskPointers

Definition at line 959 of file BaseTest.py.

◆ normalizeDate

GaudiTesting.BaseTest.normalizeDate

Definition at line 960 of file BaseTest.py.

◆ normalizeEOL

GaudiTesting.BaseTest.normalizeEOL

Definition at line 964 of file BaseTest.py.

◆ normalizeExamples

GaudiTesting.BaseTest.normalizeExamples

Definition at line 1166 of file BaseTest.py.

◆ normalizeTestSuite

GaudiTesting.BaseTest.normalizeTestSuite

Definition at line 1015 of file BaseTest.py.

◆ regexps

list GaudiTesting.BaseTest.regexps

Definition at line 1096 of file BaseTest.py.

◆ SKIP_RETURN_CODE

GaudiTesting.BaseTest.SKIP_RETURN_CODE

Definition at line 43 of file BaseTest.py.

◆ skipEmptyLines

GaudiTesting.BaseTest.skipEmptyLines

Definition at line 967 of file BaseTest.py.

MSG::hex
MsgStream & hex(MsgStream &log)
Definition: MsgStream.h:282
GaudiTesting.BaseTest.dumpProcs
def dumpProcs(name)
Definition: BaseTest.py:63
GaudiTesting.BaseTest._parseTTreeSummary
def _parseTTreeSummary(lines, pos)
Definition: BaseTest.py:1283
GaudiTesting.BaseTest.sanitize_for_xml
def sanitize_for_xml(data)
Definition: BaseTest.py:46
GaudiTesting.BaseTest.getCmpFailingValues
def getCmpFailingValues(reference, to_check, fail_path)
Definition: BaseTest.py:1268
GaudiTesting.BaseTest._new_backslashreplace_errors
def _new_backslashreplace_errors(exc)
Definition: BaseTest.py:31
GaudiTesting.BaseTest.kill_tree
def kill_tree(ppid, sig)
Definition: BaseTest.py:73
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:1364
GaudiTesting.BaseTest.isWinPlatform
def isWinPlatform(self)
Definition: BaseTest.py:1483
GaudiTesting.BaseTest.which
def which(executable)
Definition: BaseTest.py:739
GaudiTesting.BaseTest.cmpTreesDicts
def cmpTreesDicts(reference, to_check, ignore=None)
Definition: BaseTest.py:1235
GaudiTesting.BaseTest.RationalizePath
def RationalizePath(p)
Definition: BaseTest.py:729
gaudirun.type
type
Definition: gaudirun.py:160
GaudiTesting.BaseTest.findHistosSummaries
def findHistosSummaries(stdout)
Definition: BaseTest.py:1432
GaudiTesting.BaseTest.findTTreeSummaries
def findTTreeSummaries(stdout)
Definition: BaseTest.py:1213
GaudiTesting.BaseTest.ROOT6WorkAroundEnabled
def ROOT6WorkAroundEnabled(id=None)
Definition: BaseTest.py:721
GaudiTesting.BaseTest.GetPlatform
def GetPlatform(self)
Definition: BaseTest.py:1455
Gaudi::Functional::details::zip::range
decltype(auto) range(Args &&... args)
Zips multiple containers together to form a single range.
Definition: details.h:98