The Gaudi Framework  v36r10 (fc05264c)
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 38 of file BaseTest.py.

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

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

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

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

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

◆ dumpProcs()

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

Definition at line 70 of file BaseTest.py.

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

◆ findHistosSummaries()

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

Definition at line 1400 of file BaseTest.py.

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

◆ findTTreeSummaries()

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

Definition at line 1210 of file BaseTest.py.

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

◆ getCmpFailingValues()

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

Definition at line 1265 of file BaseTest.py.

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

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

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

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

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

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

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

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

◆ RationalizePath()

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

Definition at line 738 of file BaseTest.py.

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

◆ ROOT6WorkAroundEnabled()

def GaudiTesting.BaseTest.ROOT6WorkAroundEnabled (   id = None)

Definition at line 730 of file BaseTest.py.

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

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

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

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

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

Variable Documentation

◆ __processLine__

GaudiTesting.BaseTest.__processLine__
private

Definition at line 976 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 1277 of file BaseTest.py.

◆ lineSkipper

GaudiTesting.BaseTest.lineSkipper

Definition at line 1066 of file BaseTest.py.

◆ maskPointers

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

Definition at line 970 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 971 of file BaseTest.py.

◆ normalizeEOL

GaudiTesting.BaseTest.normalizeEOL = FilePreprocessor()

Definition at line 975 of file BaseTest.py.

◆ normalizeExamples

tuple GaudiTesting.BaseTest.normalizeExamples = maskPointers + normalizeDate

Definition at line 1026 of file BaseTest.py.

◆ regexps

GaudiTesting.BaseTest.regexps

Definition at line 1157 of file BaseTest.py.

◆ SKIP_RETURN_CODE

int GaudiTesting.BaseTest.SKIP_RETURN_CODE = 77

Definition at line 50 of file BaseTest.py.

◆ skipEmptyLines

GaudiTesting.BaseTest.skipEmptyLines = FilePreprocessor()

Definition at line 978 of file BaseTest.py.

MSG::hex
MsgStream & hex(MsgStream &log)
Definition: MsgStream.h:282
GaudiTesting.BaseTest.dumpProcs
def dumpProcs(name)
Definition: BaseTest.py:70
GaudiTesting.BaseTest._parseTTreeSummary
def _parseTTreeSummary(lines, pos)
Definition: BaseTest.py:1280
GaudiTesting.BaseTest.sanitize_for_xml
def sanitize_for_xml(data)
Definition: BaseTest.py:53
GaudiTesting.BaseTest.getCmpFailingValues
def getCmpFailingValues(reference, to_check, fail_path)
Definition: BaseTest.py:1265
GaudiTesting.BaseTest._new_backslashreplace_errors
def _new_backslashreplace_errors(exc)
Definition: BaseTest.py:38
GaudiTesting.BaseTest.kill_tree
def kill_tree(ppid, sig)
Definition: BaseTest.py:80
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:1332
GaudiTesting.BaseTest.isWinPlatform
def isWinPlatform(self)
Definition: BaseTest.py:1451
GaudiTesting.BaseTest.which
def which(executable)
Definition: BaseTest.py:748
GaudiTesting.BaseTest.cmpTreesDicts
def cmpTreesDicts(reference, to_check, ignore=None)
Definition: BaseTest.py:1232
GaudiTesting.BaseTest.RationalizePath
def RationalizePath(p)
Definition: BaseTest.py:738
gaudirun.type
type
Definition: gaudirun.py:160
GaudiTesting.BaseTest.findHistosSummaries
def findHistosSummaries(stdout)
Definition: BaseTest.py:1400
GaudiTesting.BaseTest.findTTreeSummaries
def findTTreeSummaries(stdout)
Definition: BaseTest.py:1210
GaudiTesting.BaseTest.ROOT6WorkAroundEnabled
def ROOT6WorkAroundEnabled(id=None)
Definition: BaseTest.py:730
GaudiTesting.BaseTest.GetPlatform
def GetPlatform(self)
Definition: BaseTest.py:1423
Gaudi::Functional::details::zip::range
decltype(auto) range(Args &&... args)
Zips multiple containers together to form a single range.
Definition: FunctionalDetails.h:102