The Gaudi Framework  v38r3 (c3fc9673)
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
 
 OUTPUT_LIMIT
 
 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 32 of file BaseTest.py.

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

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

1337 def _parseTTreeSummary(lines, pos):
1338  """
1339  Parse the TTree summary table in lines, starting from pos.
1340  Returns a tuple with the dictionary with the digested informations and the
1341  position of the first line after the summary.
1342  """
1343  result = {}
1344  i = pos + 1 # first line is a sequence of '*'
1345  count = len(lines)
1346 
1347  def splitcols(l):
1348  return [f.strip() for f in l.strip("*\n").split(":", 2)]
1349 
1350  def parseblock(ll):
1351  r = {}
1352  delta_i = 0
1353  cols = splitcols(ll[0])
1354 
1355  if len(ll) == 3:
1356  # default one line name/title
1357  r["Name"], r["Title"] = cols[1:]
1358  elif len(ll) == 4:
1359  # in case title is moved to next line due to too long name
1360  delta_i = 1
1361  r["Name"] = cols[1]
1362  r["Title"] = ll[1].strip("*\n").split("|")[1].strip()
1363  else:
1364  assert False
1365 
1366  cols = splitcols(ll[1 + delta_i])
1367  r["Entries"] = int(cols[1])
1368 
1369  sizes = cols[2].split()
1370  r["Total size"] = int(sizes[2])
1371  if sizes[-1] == "memory":
1372  r["File size"] = 0
1373  else:
1374  r["File size"] = int(sizes[-1])
1375 
1376  cols = splitcols(ll[2 + delta_i])
1377  sizes = cols[2].split()
1378  if cols[0] == "Baskets":
1379  r["Baskets"] = int(cols[1])
1380  r["Basket size"] = int(sizes[2])
1381  r["Compression"] = float(sizes[-1])
1382 
1383  return r
1384 
1385  def nextblock(lines, i):
1386  delta_i = 1
1387  dots = re.compile(r"^\.+$")
1388  stars = re.compile(r"^\*+$")
1389  count = len(lines)
1390  while (
1391  i + delta_i < count
1392  and not dots.match(lines[i + delta_i][1:-1])
1393  and not stars.match(lines[i + delta_i])
1394  ):
1395  delta_i += 1
1396  return i + delta_i
1397 
1398  if i < (count - 3) and lines[i].startswith("*Tree"):
1399  i_nextblock = nextblock(lines, i)
1400  result = parseblock(lines[i:i_nextblock])
1401  result["Branches"] = {}
1402  i = i_nextblock + 1
1403  while i < (count - 3) and lines[i].startswith("*Br"):
1404  if i < (count - 2) and lines[i].startswith("*Branch "):
1405  # skip branch header
1406  i += 3
1407  continue
1408  i_nextblock = nextblock(lines, i)
1409  if i_nextblock >= count:
1410  break
1411  branch = parseblock(lines[i:i_nextblock])
1412  result["Branches"][branch["Name"]] = branch
1413  i = i_nextblock + 1
1414 
1415  return (result, i)
1416 
1417 

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

1289 def cmpTreesDicts(reference, to_check, ignore=None):
1290  """
1291  Check that all the keys in reference are in to_check too, with the same value.
1292  If the value is a dict, the function is called recursively. to_check can
1293  contain more keys than reference, that will not be tested.
1294  The function returns at the first difference found.
1295  """
1296  fail_keys = []
1297  # filter the keys in the reference dictionary
1298  if ignore:
1299  ignore_re = re.compile(ignore)
1300  keys = [key for key in reference if not ignore_re.match(key)]
1301  else:
1302  keys = reference.keys()
1303  # loop over the keys (not ignored) in the reference dictionary
1304  for k in keys:
1305  if k in to_check: # the key must be in the dictionary to_check
1306  if isinstance(reference[k], dict) and isinstance(to_check[k], dict):
1307  # if both reference and to_check values are dictionaries,
1308  # recurse
1309  failed = fail_keys = cmpTreesDicts(reference[k], to_check[k], ignore)
1310  else:
1311  # compare the two values
1312  failed = to_check[k] != reference[k]
1313  else: # handle missing keys in the dictionary to check (i.e. failure)
1314  to_check[k] = None
1315  failed = True
1316  if failed:
1317  fail_keys.insert(0, k)
1318  break # exit from the loop at the first failure
1319  return fail_keys # return the list of keys bringing to the different values
1320 
1321 

◆ dumpProcs()

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

Definition at line 67 of file BaseTest.py.

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

◆ findHistosSummaries()

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

Definition at line 1486 of file BaseTest.py.

1486 def findHistosSummaries(stdout):
1487  """
1488  Scan stdout to find ROOT TTree summaries and digest them.
1489  """
1490  outlines = stdout.splitlines()
1491  nlines = len(outlines) - 1
1492  summaries = {}
1493  global h_count_re
1494 
1495  pos = 0
1496  while pos < nlines:
1497  summ = {}
1498  # find first line of block:
1499  match = h_count_re.search(outlines[pos])
1500  while pos < nlines and not match:
1501  pos += 1
1502  match = h_count_re.search(outlines[pos])
1503  if match:
1504  summ, pos = parseHistosSummary(outlines, pos)
1505  summaries.update(summ)
1506  return summaries
1507 
1508 

◆ findTTreeSummaries()

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

Definition at line 1267 of file BaseTest.py.

1267 def findTTreeSummaries(stdout):
1268  """
1269  Scan stdout to find ROOT TTree summaries and digest them.
1270  """
1271  stars = re.compile(r"^\*+$")
1272  outlines = stdout.splitlines()
1273  nlines = len(outlines)
1274  trees = {}
1275 
1276  i = 0
1277  while i < nlines: # loop over the output
1278  # look for
1279  while i < nlines and not stars.match(outlines[i]):
1280  i += 1
1281  if i < nlines:
1282  tree, i = _parseTTreeSummary(outlines, i)
1283  if tree:
1284  trees[tree["Name"]] = tree
1285 
1286  return trees
1287 
1288 

◆ getCmpFailingValues()

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

Definition at line 1322 of file BaseTest.py.

1322 def getCmpFailingValues(reference, to_check, fail_path):
1323  c = to_check
1324  r = reference
1325  for k in fail_path:
1326  c = c.get(k, None)
1327  r = r.get(k, None)
1328  if c is None or r is None:
1329  break # one of the dictionaries is not deep enough
1330  return (fail_path, r, c)
1331 
1332 
1333 # 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 1509 of file BaseTest.py.

1509 def GetPlatform(self):
1510  """
1511  Return the platform Id defined in CMTCONFIG or SCRAM_ARCH.
1512  """
1513  arch = "None"
1514  # check architecture name
1515  if "BINARY_TAG" in os.environ:
1516  arch = os.environ["BINARY_TAG"]
1517  elif "CMTCONFIG" in os.environ:
1518  arch = os.environ["CMTCONFIG"]
1519  elif "SCRAM_ARCH" in os.environ:
1520  arch = os.environ["SCRAM_ARCH"]
1521  elif os.environ.get("ENV_CMAKE_BUILD_TYPE", "") in (
1522  "Debug",
1523  "FastDebug",
1524  "Developer",
1525  ):
1526  arch = "dummy-dbg"
1527  elif os.environ.get("ENV_CMAKE_BUILD_TYPE", "") in (
1528  "Release",
1529  "MinSizeRel",
1530  "RelWithDebInfo",
1531  "",
1532  ): # RelWithDebInfo == -O2 -g -DNDEBUG
1533  arch = "dummy-opt"
1534  return arch
1535 
1536 

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

1537 def isWinPlatform(self):
1538  """
1539  Return True if the current platform is Windows.
1540 
1541  This function was needed because of the change in the CMTCONFIG format,
1542  from win32_vc71_dbg to i686-winxp-vc9-dbg.
1543  """
1544  platform = GetPlatform(self)
1545  return "winxp" in platform or platform.startswith("win")
1546 
1547 

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

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

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

1418 def parseHistosSummary(lines, pos):
1419  """
1420  Extract the histograms infos from the lines starting at pos.
1421  Returns the position of the first line after the summary block.
1422  """
1423  global h_count_re
1424  h_table_head = re.compile(
1425  r'SUCCESS\s+(1D|2D|3D|1D profile|2D profile) histograms in directory\s+"(\w*)"'
1426  )
1427  h_short_summ = re.compile(r"ID=([^\"]+)\s+\"([^\"]+)\"\s+(.*)")
1428 
1429  nlines = len(lines)
1430 
1431  # decode header
1432  m = h_count_re.search(lines[pos])
1433  name = m.group(1).strip()
1434  total = int(m.group(2))
1435  header = {}
1436  for k, v in [x.split("=") for x in m.group(3).split()]:
1437  header[k] = int(v)
1438  pos += 1
1439  header["Total"] = total
1440 
1441  summ = {}
1442  while pos < nlines:
1443  m = h_table_head.search(lines[pos])
1444  if m:
1445  t, d = m.groups(1) # type and directory
1446  t = t.replace(" profile", "Prof")
1447  pos += 1
1448  if pos < nlines:
1449  l = lines[pos]
1450  else:
1451  l = ""
1452  cont = {}
1453  if l.startswith(" | ID"):
1454  # table format
1455  titles = [x.strip() for x in l.split("|")][1:]
1456  pos += 1
1457  while pos < nlines and lines[pos].startswith(" |"):
1458  l = lines[pos]
1459  values = [x.strip() for x in l.split("|")][1:]
1460  hcont = {}
1461  for i in range(len(titles)):
1462  hcont[titles[i]] = values[i]
1463  cont[hcont["ID"]] = hcont
1464  pos += 1
1465  elif l.startswith(" ID="):
1466  while pos < nlines and lines[pos].startswith(" ID="):
1467  values = [
1468  x.strip() for x in h_short_summ.search(lines[pos]).groups()
1469  ]
1470  cont[values[0]] = values
1471  pos += 1
1472  else: # not interpreted
1473  raise RuntimeError("Cannot understand line %d: '%s'" % (pos, l))
1474  if d not in summ:
1475  summ[d] = {}
1476  summ[d][t] = cont
1477  summ[d]["header"] = header
1478  else:
1479  break
1480  if not summ:
1481  # If the full table is not present, we use only the header
1482  summ[name] = {"header": header}
1483  return summ, pos
1484 
1485 

◆ RationalizePath()

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

Definition at line 777 of file BaseTest.py.

777 def RationalizePath(p):
778  """
779  Function used to normalize the used path
780  """
781  newPath = os.path.normpath(os.path.expandvars(p))
782  if os.path.exists(newPath):
783  p = os.path.realpath(newPath)
784  return p
785 
786 

◆ ROOT6WorkAroundEnabled()

def GaudiTesting.BaseTest.ROOT6WorkAroundEnabled (   id = None)

Definition at line 769 of file BaseTest.py.

769  def ROOT6WorkAroundEnabled(id=None):
770  # dummy implementation
771  return False
772 
773 
774 # --------------------------------- TOOLS ---------------------------------#
775 
776 

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

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

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

787 def which(executable):
788  """
789  Locates an executable in the executables path ($PATH) and returns the full
790  path to it. An application is looked for with or without the '.exe' suffix.
791  If the executable cannot be found, None is returned
792  """
793  if os.path.isabs(executable):
794  if not os.path.isfile(executable):
795  if executable.endswith(".exe"):
796  if os.path.isfile(executable[:-4]):
797  return executable[:-4]
798  else:
799  executable = os.path.split(executable)[1]
800  else:
801  return executable
802  for d in os.environ.get("PATH").split(os.pathsep):
803  fullpath = os.path.join(d, executable)
804  if os.path.isfile(fullpath):
805  return fullpath
806  elif executable.endswith(".exe") and os.path.isfile(fullpath[:-4]):
807  return fullpath[:-4]
808  return None
809 
810 
811 # -------------------------------------------------------------------------#
812 # ----------------------------- Result Classe -----------------------------#
813 # -------------------------------------------------------------------------#
814 
815 

Variable Documentation

◆ __processLine__

GaudiTesting.BaseTest.__processLine__
private

Definition at line 1013 of file BaseTest.py.

◆ h_count_re

GaudiTesting.BaseTest.h_count_re

Definition at line 1334 of file BaseTest.py.

◆ lineSkipper

GaudiTesting.BaseTest.lineSkipper

Definition at line 1108 of file BaseTest.py.

◆ maskPointers

GaudiTesting.BaseTest.maskPointers

Definition at line 1007 of file BaseTest.py.

◆ normalizeDate

GaudiTesting.BaseTest.normalizeDate

Definition at line 1008 of file BaseTest.py.

◆ normalizeEOL

GaudiTesting.BaseTest.normalizeEOL

Definition at line 1012 of file BaseTest.py.

◆ normalizeExamples

GaudiTesting.BaseTest.normalizeExamples

Definition at line 1220 of file BaseTest.py.

◆ normalizeTestSuite

GaudiTesting.BaseTest.normalizeTestSuite

Definition at line 1063 of file BaseTest.py.

◆ OUTPUT_LIMIT

GaudiTesting.BaseTest.OUTPUT_LIMIT

Definition at line 47 of file BaseTest.py.

◆ regexps

list GaudiTesting.BaseTest.regexps

Definition at line 1150 of file BaseTest.py.

◆ SKIP_RETURN_CODE

GaudiTesting.BaseTest.SKIP_RETURN_CODE

Definition at line 44 of file BaseTest.py.

◆ skipEmptyLines

GaudiTesting.BaseTest.skipEmptyLines

Definition at line 1015 of file BaseTest.py.

MSG::hex
MsgStream & hex(MsgStream &log)
Definition: MsgStream.h:282
GaudiTesting.BaseTest.dumpProcs
def dumpProcs(name)
Definition: BaseTest.py:67
GaudiTesting.BaseTest._parseTTreeSummary
def _parseTTreeSummary(lines, pos)
Definition: BaseTest.py:1337
GaudiTesting.BaseTest.sanitize_for_xml
def sanitize_for_xml(data)
Definition: BaseTest.py:50
GaudiTesting.BaseTest.getCmpFailingValues
def getCmpFailingValues(reference, to_check, fail_path)
Definition: BaseTest.py:1322
GaudiTesting.BaseTest._new_backslashreplace_errors
def _new_backslashreplace_errors(exc)
Definition: BaseTest.py:32
GaudiTesting.BaseTest.kill_tree
def kill_tree(ppid, sig)
Definition: BaseTest.py:77
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:1418
GaudiTesting.BaseTest.isWinPlatform
def isWinPlatform(self)
Definition: BaseTest.py:1537
GaudiTesting.BaseTest.which
def which(executable)
Definition: BaseTest.py:787
GaudiTesting.BaseTest.cmpTreesDicts
def cmpTreesDicts(reference, to_check, ignore=None)
Definition: BaseTest.py:1289
GaudiTesting.BaseTest.RationalizePath
def RationalizePath(p)
Definition: BaseTest.py:777
GaudiTesting.BaseTest.findHistosSummaries
def findHistosSummaries(stdout)
Definition: BaseTest.py:1486
GaudiTesting.BaseTest.findTTreeSummaries
def findTTreeSummaries(stdout)
Definition: BaseTest.py:1267
GaudiTesting.BaseTest.ROOT6WorkAroundEnabled
def ROOT6WorkAroundEnabled(id=None)
Definition: BaseTest.py:769
GaudiTesting.BaseTest.GetPlatform
def GetPlatform(self)
Definition: BaseTest.py:1509
Gaudi::Functional::details::zip::range
decltype(auto) range(Args &&... args)
Zips multiple containers together to form a single range.
Definition: details.h:98