The Gaudi Framework  v36r16 (ea80daf8)
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 1284 of file BaseTest.py.

1284 def _parseTTreeSummary(lines, pos):
1285  """
1286  Parse the TTree summary table in lines, starting from pos.
1287  Returns a tuple with the dictionary with the digested informations and the
1288  position of the first line after the summary.
1289  """
1290  result = {}
1291  i = pos + 1 # first line is a sequence of '*'
1292  count = len(lines)
1293 
1294  def splitcols(l):
1295  return [f.strip() for f in l.strip("*\n").split(":", 2)]
1296 
1297  def parseblock(ll):
1298  r = {}
1299  cols = splitcols(ll[0])
1300  r["Name"], r["Title"] = cols[1:]
1301 
1302  cols = splitcols(ll[1])
1303  r["Entries"] = int(cols[1])
1304 
1305  sizes = cols[2].split()
1306  r["Total size"] = int(sizes[2])
1307  if sizes[-1] == "memory":
1308  r["File size"] = 0
1309  else:
1310  r["File size"] = int(sizes[-1])
1311 
1312  cols = splitcols(ll[2])
1313  sizes = cols[2].split()
1314  if cols[0] == "Baskets":
1315  r["Baskets"] = int(cols[1])
1316  r["Basket size"] = int(sizes[2])
1317  r["Compression"] = float(sizes[-1])
1318  return r
1319 
1320  if i < (count - 3) and lines[i].startswith("*Tree"):
1321  result = parseblock(lines[i : i + 3])
1322  result["Branches"] = {}
1323  i += 4
1324  while i < (count - 3) and lines[i].startswith("*Br"):
1325  if i < (count - 2) and lines[i].startswith("*Branch "):
1326  # skip branch header
1327  i += 3
1328  continue
1329  branch = parseblock(lines[i : i + 3])
1330  result["Branches"][branch["Name"]] = branch
1331  i += 4
1332 
1333  return (result, i)
1334 
1335 

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

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

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

1404 def findHistosSummaries(stdout):
1405  """
1406  Scan stdout to find ROOT TTree summaries and digest them.
1407  """
1408  outlines = stdout.splitlines()
1409  nlines = len(outlines) - 1
1410  summaries = {}
1411  global h_count_re
1412 
1413  pos = 0
1414  while pos < nlines:
1415  summ = {}
1416  # find first line of block:
1417  match = h_count_re.search(outlines[pos])
1418  while pos < nlines and not match:
1419  pos += 1
1420  match = h_count_re.search(outlines[pos])
1421  if match:
1422  summ, pos = parseHistosSummary(outlines, pos)
1423  summaries.update(summ)
1424  return summaries
1425 
1426 

◆ findTTreeSummaries()

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

Definition at line 1214 of file BaseTest.py.

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

◆ getCmpFailingValues()

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

Definition at line 1269 of file BaseTest.py.

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

1427 def GetPlatform(self):
1428  """
1429  Return the platform Id defined in CMTCONFIG or SCRAM_ARCH.
1430  """
1431  arch = "None"
1432  # check architecture name
1433  if "BINARY_TAG" in os.environ:
1434  arch = os.environ["BINARY_TAG"]
1435  elif "CMTCONFIG" in os.environ:
1436  arch = os.environ["CMTCONFIG"]
1437  elif "SCRAM_ARCH" in os.environ:
1438  arch = os.environ["SCRAM_ARCH"]
1439  elif os.environ.get("ENV_CMAKE_BUILD_TYPE", "") in (
1440  "Debug",
1441  "FastDebug",
1442  "Developer",
1443  ):
1444  arch = "dummy-dbg"
1445  elif os.environ.get("ENV_CMAKE_BUILD_TYPE", "") in (
1446  "Release",
1447  "MinSizeRel",
1448  "RelWithDebInfo",
1449  "",
1450  ): # RelWithDebInfo == -O2 -g -DNDEBUG
1451  arch = "dummy-opt"
1452  return arch
1453 
1454 

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

1455 def isWinPlatform(self):
1456  """
1457  Return True if the current platform is Windows.
1458 
1459  This function was needed because of the change in the CMTCONFIG format,
1460  from win32_vc71_dbg to i686-winxp-vc9-dbg.
1461  """
1462  platform = GetPlatform(self)
1463  return "winxp" in platform or platform.startswith("win")
1464 
1465 

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

1336 def parseHistosSummary(lines, pos):
1337  """
1338  Extract the histograms infos from the lines starting at pos.
1339  Returns the position of the first line after the summary block.
1340  """
1341  global h_count_re
1342  h_table_head = re.compile(
1343  r'SUCCESS\s+(1D|2D|3D|1D profile|2D profile) histograms in directory\s+"(\w*)"'
1344  )
1345  h_short_summ = re.compile(r"ID=([^\"]+)\s+\"([^\"]+)\"\s+(.*)")
1346 
1347  nlines = len(lines)
1348 
1349  # decode header
1350  m = h_count_re.search(lines[pos])
1351  name = m.group(1).strip()
1352  total = int(m.group(2))
1353  header = {}
1354  for k, v in [x.split("=") for x in m.group(3).split()]:
1355  header[k] = int(v)
1356  pos += 1
1357  header["Total"] = total
1358 
1359  summ = {}
1360  while pos < nlines:
1361  m = h_table_head.search(lines[pos])
1362  if m:
1363  t, d = m.groups(1) # type and directory
1364  t = t.replace(" profile", "Prof")
1365  pos += 1
1366  if pos < nlines:
1367  l = lines[pos]
1368  else:
1369  l = ""
1370  cont = {}
1371  if l.startswith(" | ID"):
1372  # table format
1373  titles = [x.strip() for x in l.split("|")][1:]
1374  pos += 1
1375  while pos < nlines and lines[pos].startswith(" |"):
1376  l = lines[pos]
1377  values = [x.strip() for x in l.split("|")][1:]
1378  hcont = {}
1379  for i in range(len(titles)):
1380  hcont[titles[i]] = values[i]
1381  cont[hcont["ID"]] = hcont
1382  pos += 1
1383  elif l.startswith(" ID="):
1384  while pos < nlines and lines[pos].startswith(" ID="):
1385  values = [
1386  x.strip() for x in h_short_summ.search(lines[pos]).groups()
1387  ]
1388  cont[values[0]] = values
1389  pos += 1
1390  else: # not interpreted
1391  raise RuntimeError("Cannot understand line %d: '%s'" % (pos, l))
1392  if d not in summ:
1393  summ[d] = {}
1394  summ[d][t] = cont
1395  summ[d]["header"] = header
1396  else:
1397  break
1398  if not summ:
1399  # If the full table is not present, we use only the header
1400  summ[name] = {"header": header}
1401  return summ, pos
1402 
1403 

◆ RationalizePath()

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

Definition at line 736 of file BaseTest.py.

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

◆ ROOT6WorkAroundEnabled()

def GaudiTesting.BaseTest.ROOT6WorkAroundEnabled (   id = None)

Definition at line 728 of file BaseTest.py.

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

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

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

Variable Documentation

◆ __processLine__

GaudiTesting.BaseTest.__processLine__
private

Definition at line 973 of file BaseTest.py.

◆ h_count_re

GaudiTesting.BaseTest.h_count_re

Definition at line 1281 of file BaseTest.py.

◆ lineSkipper

GaudiTesting.BaseTest.lineSkipper

Definition at line 1063 of file BaseTest.py.

◆ maskPointers

GaudiTesting.BaseTest.maskPointers

Definition at line 967 of file BaseTest.py.

◆ normalizeDate

GaudiTesting.BaseTest.normalizeDate

Definition at line 968 of file BaseTest.py.

◆ normalizeEOL

GaudiTesting.BaseTest.normalizeEOL

Definition at line 972 of file BaseTest.py.

◆ normalizeExamples

GaudiTesting.BaseTest.normalizeExamples

Definition at line 1023 of file BaseTest.py.

◆ regexps

list GaudiTesting.BaseTest.regexps

Definition at line 1105 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 975 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:1284
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:1269
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:1336
GaudiTesting.BaseTest.isWinPlatform
def isWinPlatform(self)
Definition: BaseTest.py:1455
GaudiTesting.BaseTest.which
def which(executable)
Definition: BaseTest.py:746
GaudiTesting.BaseTest.cmpTreesDicts
def cmpTreesDicts(reference, to_check, ignore=None)
Definition: BaseTest.py:1236
GaudiTesting.BaseTest.RationalizePath
def RationalizePath(p)
Definition: BaseTest.py:736
gaudirun.type
type
Definition: gaudirun.py:162
GaudiTesting.BaseTest.findHistosSummaries
def findHistosSummaries(stdout)
Definition: BaseTest.py:1404
GaudiTesting.BaseTest.findTTreeSummaries
def findTTreeSummaries(stdout)
Definition: BaseTest.py:1214
GaudiTesting.BaseTest.ROOT6WorkAroundEnabled
def ROOT6WorkAroundEnabled(id=None)
Definition: BaseTest.py:728
GaudiTesting.BaseTest.GetPlatform
def GetPlatform(self)
Definition: BaseTest.py:1427
Gaudi::Functional::details::zip::range
decltype(auto) range(Args &&... args)
Zips multiple containers together to form a single range.
Definition: FunctionalDetails.h:102