The Gaudi Framework  v36r4 (0a924e98)
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 1226 of file BaseTest.py.

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

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

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

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

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

◆ findTTreeSummaries()

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

Definition at line 1156 of file BaseTest.py.

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

◆ getCmpFailingValues()

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

Definition at line 1211 of file BaseTest.py.

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

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

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

1397 def isWinPlatform(self):
1398  """
1399  Return True if the current platform is Windows.
1400 
1401  This function was needed because of the change in the CMTCONFIG format,
1402  from win32_vc71_dbg to i686-winxp-vc9-dbg.
1403  """
1404  platform = GetPlatform(self)
1405  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 1278 of file BaseTest.py.

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

◆ 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 1223 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 1098 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:1226
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:1211
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:1278
GaudiTesting.BaseTest.isWinPlatform
def isWinPlatform(self)
Definition: BaseTest.py:1397
GaudiTesting.BaseTest.which
def which(executable)
Definition: BaseTest.py:689
GaudiTesting.BaseTest.cmpTreesDicts
def cmpTreesDicts(reference, to_check, ignore=None)
Definition: BaseTest.py:1178
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:1346
GaudiTesting.BaseTest.findTTreeSummaries
def findTTreeSummaries(stdout)
Definition: BaseTest.py:1156
GaudiTesting.BaseTest.ROOT6WorkAroundEnabled
def ROOT6WorkAroundEnabled(id=None)
Definition: BaseTest.py:671
GaudiTesting.BaseTest.GetPlatform
def GetPlatform(self)
Definition: BaseTest.py:1369
Gaudi::Functional::details::zip::range
decltype(auto) range(Args &&... args)
Zips multiple containers together to form a single range.
Definition: FunctionalDetails.h:102