The Gaudi Framework  v36r6 (b1ee9983)
GaudiTesting.BaseTest Namespace Reference

Classes

class  BaseTest
 
class  BasicOutputValidator
 
class  BlockSkipper
 
class  FilePreprocessor
 
class  FilePreprocessorSequence
 
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 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 1227 of file BaseTest.py.

1227 def _parseTTreeSummary(lines, pos):
1228  """
1229  Parse the TTree summary table in lines, starting from pos.
1230  Returns a tuple with the dictionary with the digested informations and the
1231  position of the first line after the summary.
1232  """
1233  result = {}
1234  i = pos + 1 # first line is a sequence of '*'
1235  count = len(lines)
1236 
1237  def splitcols(l):
1238  return [f.strip() for f in l.strip("*\n").split(":", 2)]
1239 
1240  def parseblock(ll):
1241  r = {}
1242  cols = splitcols(ll[0])
1243  r["Name"], r["Title"] = cols[1:]
1244 
1245  cols = splitcols(ll[1])
1246  r["Entries"] = int(cols[1])
1247 
1248  sizes = cols[2].split()
1249  r["Total size"] = int(sizes[2])
1250  if sizes[-1] == "memory":
1251  r["File size"] = 0
1252  else:
1253  r["File size"] = int(sizes[-1])
1254 
1255  cols = splitcols(ll[2])
1256  sizes = cols[2].split()
1257  if cols[0] == "Baskets":
1258  r["Baskets"] = int(cols[1])
1259  r["Basket size"] = int(sizes[2])
1260  r["Compression"] = float(sizes[-1])
1261  return r
1262 
1263  if i < (count - 3) and lines[i].startswith("*Tree"):
1264  result = parseblock(lines[i : i + 3])
1265  result["Branches"] = {}
1266  i += 4
1267  while i < (count - 3) and lines[i].startswith("*Br"):
1268  if i < (count - 2) and lines[i].startswith("*Branch "):
1269  # skip branch header
1270  i += 3
1271  continue
1272  branch = parseblock(lines[i : i + 3])
1273  result["Branches"][branch["Name"]] = branch
1274  i += 4
1275 
1276  return (result, i)
1277 
1278 

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

1179 def cmpTreesDicts(reference, to_check, ignore=None):
1180  """
1181  Check that all the keys in reference are in to_check too, with the same value.
1182  If the value is a dict, the function is called recursively. to_check can
1183  contain more keys than reference, that will not be tested.
1184  The function returns at the first difference found.
1185  """
1186  fail_keys = []
1187  # filter the keys in the reference dictionary
1188  if ignore:
1189  ignore_re = re.compile(ignore)
1190  keys = [key for key in reference if not ignore_re.match(key)]
1191  else:
1192  keys = reference.keys()
1193  # loop over the keys (not ignored) in the reference dictionary
1194  for k in keys:
1195  if k in to_check: # the key must be in the dictionary to_check
1196  if (type(reference[k]) is dict) and (type(to_check[k]) is dict):
1197  # if both reference and to_check values are dictionaries,
1198  # recurse
1199  failed = fail_keys = cmpTreesDicts(reference[k], to_check[k], ignore)
1200  else:
1201  # compare the two values
1202  failed = to_check[k] != reference[k]
1203  else: # handle missing keys in the dictionary to check (i.e. failure)
1204  to_check[k] = None
1205  failed = True
1206  if failed:
1207  fail_keys.insert(0, k)
1208  break # exit from the loop at the first failure
1209  return fail_keys # return the list of keys bringing to the different values
1210 
1211 

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

1347 def findHistosSummaries(stdout):
1348  """
1349  Scan stdout to find ROOT TTree summaries and digest them.
1350  """
1351  outlines = stdout.splitlines()
1352  nlines = len(outlines) - 1
1353  summaries = {}
1354  global h_count_re
1355 
1356  pos = 0
1357  while pos < nlines:
1358  summ = {}
1359  # find first line of block:
1360  match = h_count_re.search(outlines[pos])
1361  while pos < nlines and not match:
1362  pos += 1
1363  match = h_count_re.search(outlines[pos])
1364  if match:
1365  summ, pos = parseHistosSummary(outlines, pos)
1366  summaries.update(summ)
1367  return summaries
1368 
1369 

◆ findTTreeSummaries()

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

Definition at line 1157 of file BaseTest.py.

1157 def findTTreeSummaries(stdout):
1158  """
1159  Scan stdout to find ROOT TTree summaries and digest them.
1160  """
1161  stars = re.compile(r"^\*+$")
1162  outlines = stdout.splitlines()
1163  nlines = len(outlines)
1164  trees = {}
1165 
1166  i = 0
1167  while i < nlines: # loop over the output
1168  # look for
1169  while i < nlines and not stars.match(outlines[i]):
1170  i += 1
1171  if i < nlines:
1172  tree, i = _parseTTreeSummary(outlines, i)
1173  if tree:
1174  trees[tree["Name"]] = tree
1175 
1176  return trees
1177 
1178 

◆ getCmpFailingValues()

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

Definition at line 1212 of file BaseTest.py.

1212 def getCmpFailingValues(reference, to_check, fail_path):
1213  c = to_check
1214  r = reference
1215  for k in fail_path:
1216  c = c.get(k, None)
1217  r = r.get(k, None)
1218  if c is None or r is None:
1219  break # one of the dictionaries is not deep enough
1220  return (fail_path, r, c)
1221 
1222 
1223 # 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 1370 of file BaseTest.py.

1370 def GetPlatform(self):
1371  """
1372  Return the platform Id defined in CMTCONFIG or SCRAM_ARCH.
1373  """
1374  arch = "None"
1375  # check architecture name
1376  if "BINARY_TAG" in os.environ:
1377  arch = os.environ["BINARY_TAG"]
1378  elif "CMTCONFIG" in os.environ:
1379  arch = os.environ["CMTCONFIG"]
1380  elif "SCRAM_ARCH" in os.environ:
1381  arch = os.environ["SCRAM_ARCH"]
1382  elif os.environ.get("ENV_CMAKE_BUILD_TYPE", "") in (
1383  "Debug",
1384  "FastDebug",
1385  "Developer",
1386  ):
1387  arch = "dummy-dbg"
1388  elif os.environ.get("ENV_CMAKE_BUILD_TYPE", "") in (
1389  "Release",
1390  "MinSizeRel",
1391  "RelWithDebInfo",
1392  "",
1393  ): # RelWithDebInfo == -O2 -g -DNDEBUG
1394  arch = "dummy-opt"
1395  return arch
1396 
1397 

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

1398 def isWinPlatform(self):
1399  """
1400  Return True if the current platform is Windows.
1401 
1402  This function was needed because of the change in the CMTCONFIG format,
1403  from win32_vc71_dbg to i686-winxp-vc9-dbg.
1404  """
1405  platform = GetPlatform(self)
1406  return "winxp" in platform or platform.startswith("win")

◆ 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  get_children = Popen(ps_cmd, stdout=PIPE, stderr=PIPE)
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 1279 of file BaseTest.py.

1279 def parseHistosSummary(lines, pos):
1280  """
1281  Extract the histograms infos from the lines starting at pos.
1282  Returns the position of the first line after the summary block.
1283  """
1284  global h_count_re
1285  h_table_head = re.compile(
1286  r'SUCCESS\s+(1D|2D|3D|1D profile|2D profile) histograms in directory\s+"(\w*)"'
1287  )
1288  h_short_summ = re.compile(r"ID=([^\"]+)\s+\"([^\"]+)\"\s+(.*)")
1289 
1290  nlines = len(lines)
1291 
1292  # decode header
1293  m = h_count_re.search(lines[pos])
1294  name = m.group(1).strip()
1295  total = int(m.group(2))
1296  header = {}
1297  for k, v in [x.split("=") for x in m.group(3).split()]:
1298  header[k] = int(v)
1299  pos += 1
1300  header["Total"] = total
1301 
1302  summ = {}
1303  while pos < nlines:
1304  m = h_table_head.search(lines[pos])
1305  if m:
1306  t, d = m.groups(1) # type and directory
1307  t = t.replace(" profile", "Prof")
1308  pos += 1
1309  if pos < nlines:
1310  l = lines[pos]
1311  else:
1312  l = ""
1313  cont = {}
1314  if l.startswith(" | ID"):
1315  # table format
1316  titles = [x.strip() for x in l.split("|")][1:]
1317  pos += 1
1318  while pos < nlines and lines[pos].startswith(" |"):
1319  l = lines[pos]
1320  values = [x.strip() for x in l.split("|")][1:]
1321  hcont = {}
1322  for i in range(len(titles)):
1323  hcont[titles[i]] = values[i]
1324  cont[hcont["ID"]] = hcont
1325  pos += 1
1326  elif l.startswith(" ID="):
1327  while pos < nlines and lines[pos].startswith(" ID="):
1328  values = [
1329  x.strip() for x in h_short_summ.search(lines[pos]).groups()
1330  ]
1331  cont[values[0]] = values
1332  pos += 1
1333  else: # not interpreted
1334  raise RuntimeError("Cannot understand line %d: '%s'" % (pos, l))
1335  if not d in summ:
1336  summ[d] = {}
1337  summ[d][t] = cont
1338  summ[d]["header"] = header
1339  else:
1340  break
1341  if not summ:
1342  # If the full table is not present, we use only the header
1343  summ[name] = {"header": header}
1344  return summ, pos
1345 
1346 

◆ RationalizePath()

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

Definition at line 679 of file BaseTest.py.

679 def RationalizePath(p):
680  """
681  Function used to normalize the used path
682  """
683  newPath = os.path.normpath(os.path.expandvars(p))
684  if os.path.exists(newPath):
685  p = os.path.realpath(newPath)
686  return p
687 
688 

◆ ROOT6WorkAroundEnabled()

def GaudiTesting.BaseTest.ROOT6WorkAroundEnabled (   id = None)

Definition at line 671 of file BaseTest.py.

671  def ROOT6WorkAroundEnabled(id=None):
672  # dummy implementation
673  return False
674 
675 
676 # --------------------------------- TOOLS ---------------------------------#
677 
678 

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

689 def which(executable):
690  """
691  Locates an executable in the executables path ($PATH) and returns the full
692  path to it. An application is looked for with or without the '.exe' suffix.
693  If the executable cannot be found, None is returned
694  """
695  if os.path.isabs(executable):
696  if not os.path.isfile(executable):
697  if executable.endswith(".exe"):
698  if os.path.isfile(executable[:-4]):
699  return executable[:-4]
700  else:
701  executable = os.path.split(executable)[1]
702  else:
703  return executable
704  for d in os.environ.get("PATH").split(os.pathsep):
705  fullpath = os.path.join(d, executable)
706  if os.path.isfile(fullpath):
707  return fullpath
708  elif executable.endswith(".exe") and os.path.isfile(fullpath[:-4]):
709  return fullpath[:-4]
710  return None
711 
712 
713 # -------------------------------------------------------------------------#
714 # ----------------------------- Result Classe -----------------------------#
715 # -------------------------------------------------------------------------#

Variable Documentation

◆ __processLine__

GaudiTesting.BaseTest.__processLine__
private

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

◆ lineSkipper

GaudiTesting.BaseTest.lineSkipper

Definition at line 1007 of file BaseTest.py.

◆ maskPointers

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

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

◆ normalizeEOL

GaudiTesting.BaseTest.normalizeEOL = FilePreprocessor()

Definition at line 916 of file BaseTest.py.

◆ normalizeExamples

tuple GaudiTesting.BaseTest.normalizeExamples = maskPointers + normalizeDate

Definition at line 967 of file BaseTest.py.

◆ regexps

GaudiTesting.BaseTest.regexps

Definition at line 1099 of file BaseTest.py.

◆ SKIP_RETURN_CODE

int GaudiTesting.BaseTest.SKIP_RETURN_CODE = 77

Definition at line 49 of file BaseTest.py.

◆ skipEmptyLines

GaudiTesting.BaseTest.skipEmptyLines = FilePreprocessor()

Definition at line 919 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:1227
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:1212
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:1279
GaudiTesting.BaseTest.isWinPlatform
def isWinPlatform(self)
Definition: BaseTest.py:1398
GaudiTesting.BaseTest.which
def which(executable)
Definition: BaseTest.py:689
GaudiTesting.BaseTest.cmpTreesDicts
def cmpTreesDicts(reference, to_check, ignore=None)
Definition: BaseTest.py:1179
GaudiTesting.BaseTest.RationalizePath
def RationalizePath(p)
Definition: BaseTest.py:679
gaudirun.type
type
Definition: gaudirun.py:160
GaudiTesting.BaseTest.findHistosSummaries
def findHistosSummaries(stdout)
Definition: BaseTest.py:1347
GaudiTesting.BaseTest.findTTreeSummaries
def findTTreeSummaries(stdout)
Definition: BaseTest.py:1157
GaudiTesting.BaseTest.ROOT6WorkAroundEnabled
def ROOT6WorkAroundEnabled(id=None)
Definition: BaseTest.py:671
GaudiTesting.BaseTest.GetPlatform
def GetPlatform(self)
Definition: BaseTest.py:1370
Gaudi::Functional::details::zip::range
decltype(auto) range(Args &&... args)
Zips multiple containers together to form a single range.
Definition: FunctionalDetails.h:102