The Gaudi Framework  v38r0 (2143aa4c)
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 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 1275 of file BaseTest.py.

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

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

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

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

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

◆ findTTreeSummaries()

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

Definition at line 1205 of file BaseTest.py.

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

◆ getCmpFailingValues()

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

Definition at line 1260 of file BaseTest.py.

1260 def getCmpFailingValues(reference, to_check, fail_path):
1261  c = to_check
1262  r = reference
1263  for k in fail_path:
1264  c = c.get(k, None)
1265  r = r.get(k, None)
1266  if c is None or r is None:
1267  break # one of the dictionaries is not deep enough
1268  return (fail_path, r, c)
1269 
1270 
1271 # 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 1447 of file BaseTest.py.

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

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

1475 def isWinPlatform(self):
1476  """
1477  Return True if the current platform is Windows.
1478 
1479  This function was needed because of the change in the CMTCONFIG format,
1480  from win32_vc71_dbg to i686-winxp-vc9-dbg.
1481  """
1482  platform = GetPlatform(self)
1483  return "winxp" in platform or platform.startswith("win")
1484 
1485 

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

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

◆ 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 1272 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 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:1275
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:1260
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:1356
GaudiTesting.BaseTest.isWinPlatform
def isWinPlatform(self)
Definition: BaseTest.py:1475
GaudiTesting.BaseTest.which
def which(executable)
Definition: BaseTest.py:739
GaudiTesting.BaseTest.cmpTreesDicts
def cmpTreesDicts(reference, to_check, ignore=None)
Definition: BaseTest.py:1227
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:1424
GaudiTesting.BaseTest.findTTreeSummaries
def findTTreeSummaries(stdout)
Definition: BaseTest.py:1205
GaudiTesting.BaseTest.ROOT6WorkAroundEnabled
def ROOT6WorkAroundEnabled(id=None)
Definition: BaseTest.py:721
GaudiTesting.BaseTest.GetPlatform
def GetPlatform(self)
Definition: BaseTest.py:1447
Gaudi::Functional::details::zip::range
decltype(auto) range(Args &&... args)
Zips multiple containers together to form a single range.
Definition: details.h:98