The Gaudi Framework  v36r9 (fd2bdac3)
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

int SKIP_RETURN_CODE = 77
 
 maskPointers = RegexpReplacer("0x[0-9a-fA-F]{4,16}", "0x########")
 
 normalizeDate
 
 normalizeEOL = FilePreprocessor()
 
 __processLine__
 
 skipEmptyLines = FilePreprocessor()
 
 normalizeExamples = maskPointers + normalizeDate
 
 lineSkipper
 
 regexps
 
 h_count_re = re.compile(r"^(.*)SUCCESS\s+Booked (\d+) Histogram\(s\) :\s+([\s\w=-]*)")
 

Function Documentation

◆ _new_backslashreplace_errors()

def GaudiTesting.BaseTest._new_backslashreplace_errors (   exc)
private

Definition at line 39 of file BaseTest.py.

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

◆ _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  cols = splitcols(ll[0])
1297  r["Name"], r["Title"] = cols[1:]
1298 
1299  cols = splitcols(ll[1])
1300  r["Entries"] = int(cols[1])
1301 
1302  sizes = cols[2].split()
1303  r["Total size"] = int(sizes[2])
1304  if sizes[-1] == "memory":
1305  r["File size"] = 0
1306  else:
1307  r["File size"] = int(sizes[-1])
1308 
1309  cols = splitcols(ll[2])
1310  sizes = cols[2].split()
1311  if cols[0] == "Baskets":
1312  r["Baskets"] = int(cols[1])
1313  r["Basket size"] = int(sizes[2])
1314  r["Compression"] = float(sizes[-1])
1315  return r
1316 
1317  if i < (count - 3) and lines[i].startswith("*Tree"):
1318  result = parseblock(lines[i : i + 3])
1319  result["Branches"] = {}
1320  i += 4
1321  while i < (count - 3) and lines[i].startswith("*Br"):
1322  if i < (count - 2) and lines[i].startswith("*Branch "):
1323  # skip branch header
1324  i += 3
1325  continue
1326  branch = parseblock(lines[i : i + 3])
1327  result["Branches"][branch["Name"]] = branch
1328  i += 4
1329 
1330  return (result, i)
1331 
1332 

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

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

◆ findHistosSummaries()

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

Definition at line 1401 of file BaseTest.py.

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

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

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

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

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

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

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

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

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

◆ RationalizePath()

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

Definition at line 739 of file BaseTest.py.

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

◆ ROOT6WorkAroundEnabled()

def GaudiTesting.BaseTest.ROOT6WorkAroundEnabled (   id = None)

Definition at line 731 of file BaseTest.py.

731  def ROOT6WorkAroundEnabled(id=None):
732  # dummy implementation
733  return False
734 
735 
736 # --------------------------------- TOOLS ---------------------------------#
737 
738 

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

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

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

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

Variable Documentation

◆ __processLine__

GaudiTesting.BaseTest.__processLine__
private

Definition at line 977 of file BaseTest.py.

◆ h_count_re

GaudiTesting.BaseTest.h_count_re = re.compile(r"^(.*)SUCCESS\s+Booked (\d+) Histogram\(s\) :\s+([\s\w=-]*)")

Definition at line 1278 of file BaseTest.py.

◆ lineSkipper

GaudiTesting.BaseTest.lineSkipper

Definition at line 1067 of file BaseTest.py.

◆ maskPointers

GaudiTesting.BaseTest.maskPointers = RegexpReplacer("0x[0-9a-fA-F]{4,16}", "0x########")

Definition at line 971 of file BaseTest.py.

◆ normalizeDate

GaudiTesting.BaseTest.normalizeDate
Initial value:
1 = RegexpReplacer(
2  "[0-2]?[0-9]:[0-5][0-9]:[0-5][0-9] [0-9]{4}[-/][01][0-9][-/][0-3][0-9][ A-Z]*",
3  "00:00:00 1970-01-01",
4 )

Definition at line 972 of file BaseTest.py.

◆ normalizeEOL

GaudiTesting.BaseTest.normalizeEOL = FilePreprocessor()

Definition at line 976 of file BaseTest.py.

◆ normalizeExamples

tuple GaudiTesting.BaseTest.normalizeExamples = maskPointers + normalizeDate

Definition at line 1027 of file BaseTest.py.

◆ regexps

GaudiTesting.BaseTest.regexps

Definition at line 1158 of file BaseTest.py.

◆ SKIP_RETURN_CODE

int GaudiTesting.BaseTest.SKIP_RETURN_CODE = 77

Definition at line 51 of file BaseTest.py.

◆ skipEmptyLines

GaudiTesting.BaseTest.skipEmptyLines = FilePreprocessor()

Definition at line 979 of file BaseTest.py.

MSG::hex
MsgStream & hex(MsgStream &log)
Definition: MsgStream.h:282
GaudiTesting.BaseTest.dumpProcs
def dumpProcs(name)
Definition: BaseTest.py:71
GaudiTesting.BaseTest._parseTTreeSummary
def _parseTTreeSummary(lines, pos)
Definition: BaseTest.py:1281
GaudiTesting.BaseTest.sanitize_for_xml
def sanitize_for_xml(data)
Definition: BaseTest.py:54
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:39
GaudiTesting.BaseTest.kill_tree
def kill_tree(ppid, sig)
Definition: BaseTest.py:81
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:1333
GaudiTesting.BaseTest.isWinPlatform
def isWinPlatform(self)
Definition: BaseTest.py:1452
GaudiTesting.BaseTest.which
def which(executable)
Definition: BaseTest.py:749
GaudiTesting.BaseTest.cmpTreesDicts
def cmpTreesDicts(reference, to_check, ignore=None)
Definition: BaseTest.py:1233
GaudiTesting.BaseTest.RationalizePath
def RationalizePath(p)
Definition: BaseTest.py:739
gaudirun.type
type
Definition: gaudirun.py:160
GaudiTesting.BaseTest.findHistosSummaries
def findHistosSummaries(stdout)
Definition: BaseTest.py:1401
GaudiTesting.BaseTest.findTTreeSummaries
def findTTreeSummaries(stdout)
Definition: BaseTest.py:1211
GaudiTesting.BaseTest.ROOT6WorkAroundEnabled
def ROOT6WorkAroundEnabled(id=None)
Definition: BaseTest.py:731
GaudiTesting.BaseTest.GetPlatform
def GetPlatform(self)
Definition: BaseTest.py:1424
Gaudi::Functional::details::zip::range
decltype(auto) range(Args &&... args)
Zips multiple containers together to form a single range.
Definition: FunctionalDetails.h:102