The Gaudi Framework  v33r1 (b1225454)
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 PlatformIsNotSupported (self, context, result)
 
def GetPlatform (self)
 
def isWinPlatform (self)
 

Variables

 maskPointers = RegexpReplacer("0x[0-9a-fA-F]{4,16}", "0x########")
 
 normalizeDate
 
 normalizeEOL = FilePreprocessor()
 
 __processLine__
 
 skipEmptyLines = FilePreprocessor()
 
 normalizeExamples = maskPointers + normalizeDate
 
 lineSkipper
 
 regexps
 
 h_count_re
 

Function Documentation

◆ _new_backslashreplace_errors()

def GaudiTesting.BaseTest._new_backslashreplace_errors (   exc)
private

Definition at line 33 of file BaseTest.py.

34  if isinstance(exc, UnicodeDecodeError):
35  code = hex(ord(exc.object[exc.start]))
36  return (u'\\' + code[1:], exc.start + 1)
37  else:
38  return backslashreplace_errors(exc)
39 
MsgStream & hex(MsgStream &log)
Definition: MsgStream.h:281
def _new_backslashreplace_errors(exc)
Definition: BaseTest.py:33

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

1175 def _parseTTreeSummary(lines, pos):
1176  """
1177  Parse the TTree summary table in lines, starting from pos.
1178  Returns a tuple with the dictionary with the digested informations and the
1179  position of the first line after the summary.
1180  """
1181  result = {}
1182  i = pos + 1 # first line is a sequence of '*'
1183  count = len(lines)
1184 
1185  def splitcols(l):
1186  return [f.strip() for f in l.strip("*\n").split(':', 2)]
1187 
1188  def parseblock(ll):
1189  r = {}
1190  cols = splitcols(ll[0])
1191  r["Name"], r["Title"] = cols[1:]
1192 
1193  cols = splitcols(ll[1])
1194  r["Entries"] = int(cols[1])
1195 
1196  sizes = cols[2].split()
1197  r["Total size"] = int(sizes[2])
1198  if sizes[-1] == "memory":
1199  r["File size"] = 0
1200  else:
1201  r["File size"] = int(sizes[-1])
1202 
1203  cols = splitcols(ll[2])
1204  sizes = cols[2].split()
1205  if cols[0] == "Baskets":
1206  r["Baskets"] = int(cols[1])
1207  r["Basket size"] = int(sizes[2])
1208  r["Compression"] = float(sizes[-1])
1209  return r
1210 
1211  if i < (count - 3) and lines[i].startswith("*Tree"):
1212  result = parseblock(lines[i:i + 3])
1213  result["Branches"] = {}
1214  i += 4
1215  while i < (count - 3) and lines[i].startswith("*Br"):
1216  if i < (count - 2) and lines[i].startswith("*Branch "):
1217  # skip branch header
1218  i += 3
1219  continue
1220  branch = parseblock(lines[i:i + 3])
1221  result["Branches"][branch["Name"]] = branch
1222  i += 4
1223 
1224  return (result, i)
1225 
1226 
def _parseTTreeSummary(lines, pos)
Definition: BaseTest.py:1175

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

1125 def cmpTreesDicts(reference, to_check, ignore=None):
1126  """
1127  Check that all the keys in reference are in to_check too, with the same value.
1128  If the value is a dict, the function is called recursively. to_check can
1129  contain more keys than reference, that will not be tested.
1130  The function returns at the first difference found.
1131  """
1132  fail_keys = []
1133  # filter the keys in the reference dictionary
1134  if ignore:
1135  ignore_re = re.compile(ignore)
1136  keys = [key for key in reference if not ignore_re.match(key)]
1137  else:
1138  keys = reference.keys()
1139  # loop over the keys (not ignored) in the reference dictionary
1140  for k in keys:
1141  if k in to_check: # the key must be in the dictionary to_check
1142  if (type(reference[k]) is dict) and (type(to_check[k]) is dict):
1143  # if both reference and to_check values are dictionaries,
1144  # recurse
1145  failed = fail_keys = cmpTreesDicts(reference[k], to_check[k],
1146  ignore)
1147  else:
1148  # compare the two values
1149  failed = to_check[k] != reference[k]
1150  else: # handle missing keys in the dictionary to check (i.e. failure)
1151  to_check[k] = None
1152  failed = True
1153  if failed:
1154  fail_keys.insert(0, k)
1155  break # exit from the loop at the first failure
1156  return fail_keys # return the list of keys bringing to the different values
1157 
1158 
def cmpTreesDicts(reference, to_check, ignore=None)
Definition: BaseTest.py:1125

◆ dumpProcs()

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

Definition at line 64 of file BaseTest.py.

64 def dumpProcs(name):
65  '''helper to debug GAUDI-1084, dump the list of processes'''
66  from getpass import getuser
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 
def dumpProcs(name)
Definition: BaseTest.py:64

◆ findHistosSummaries()

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

Definition at line 1297 of file BaseTest.py.

1297 def findHistosSummaries(stdout):
1298  """
1299  Scan stdout to find ROOT TTree summaries and digest them.
1300  """
1301  outlines = stdout.splitlines()
1302  nlines = len(outlines) - 1
1303  summaries = {}
1304  global h_count_re
1305 
1306  pos = 0
1307  while pos < nlines:
1308  summ = {}
1309  # find first line of block:
1310  match = h_count_re.search(outlines[pos])
1311  while pos < nlines and not match:
1312  pos += 1
1313  match = h_count_re.search(outlines[pos])
1314  if match:
1315  summ, pos = parseHistosSummary(outlines, pos)
1316  summaries.update(summ)
1317  return summaries
1318 
1319 
def findHistosSummaries(stdout)
Definition: BaseTest.py:1297
def parseHistosSummary(lines, pos)
Definition: BaseTest.py:1227

◆ findTTreeSummaries()

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

Definition at line 1103 of file BaseTest.py.

1103 def findTTreeSummaries(stdout):
1104  """
1105  Scan stdout to find ROOT TTree summaries and digest them.
1106  """
1107  stars = re.compile(r"^\*+$")
1108  outlines = stdout.splitlines()
1109  nlines = len(outlines)
1110  trees = {}
1111 
1112  i = 0
1113  while i < nlines: # loop over the output
1114  # look for
1115  while i < nlines and not stars.match(outlines[i]):
1116  i += 1
1117  if i < nlines:
1118  tree, i = _parseTTreeSummary(outlines, i)
1119  if tree:
1120  trees[tree["Name"]] = tree
1121 
1122  return trees
1123 
1124 
def _parseTTreeSummary(lines, pos)
Definition: BaseTest.py:1175
def findTTreeSummaries(stdout)
Definition: BaseTest.py:1103

◆ getCmpFailingValues()

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

Definition at line 1159 of file BaseTest.py.

1159 def getCmpFailingValues(reference, to_check, fail_path):
1160  c = to_check
1161  r = reference
1162  for k in fail_path:
1163  c = c.get(k, None)
1164  r = r.get(k, None)
1165  if c is None or r is None:
1166  break # one of the dictionaries is not deep enough
1167  return (fail_path, r, c)
1168 
1169 
1170 # signature of the print-out of the histograms
def getCmpFailingValues(reference, to_check, fail_path)
Definition: BaseTest.py:1159

◆ GetPlatform()

def GaudiTesting.BaseTest.GetPlatform (   self)
    Return the platform Id defined in CMTCONFIG or SCRAM_ARCH.

Definition at line 1334 of file BaseTest.py.

1334 def GetPlatform(self):
1335  """
1336  Return the platform Id defined in CMTCONFIG or SCRAM_ARCH.
1337  """
1338  arch = "None"
1339  # check architecture name
1340  if "BINARY_TAG" in os.environ:
1341  arch = os.environ["BINARY_TAG"]
1342  elif "CMTCONFIG" in os.environ:
1343  arch = os.environ["CMTCONFIG"]
1344  elif "SCRAM_ARCH" in os.environ:
1345  arch = os.environ["SCRAM_ARCH"]
1346  return arch
1347 
1348 
def GetPlatform(self)
Definition: BaseTest.py:1334

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

1349 def isWinPlatform(self):
1350  """
1351  Return True if the current platform is Windows.
1352 
1353  This function was needed because of the change in the CMTCONFIG format,
1354  from win32_vc71_dbg to i686-winxp-vc9-dbg.
1355  """
1356  platform = GetPlatform(self)
1357  return "winxp" in platform or platform.startswith("win")
def GetPlatform(self)
Definition: BaseTest.py:1334
def isWinPlatform(self)
Definition: BaseTest.py:1349

◆ 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  get_children = Popen(ps_cmd, stdout=PIPE, stderr=PIPE)
81  children = map(int, get_children.communicate()[0].split())
82  for child in children:
83  kill_tree(child, sig)
84  try:
85  log.debug('killing process %d', ppid)
86  os.kill(ppid, sig)
87  except OSError as err:
88  if err.errno != 3: # No such process
89  raise
90  log.debug('no such process %d', ppid)
91 
92 
93 # -------------------------------------------------------------------------#
94 
95 
struct GAUDI_API map
Parametrisation class for map-like implementation.
def kill_tree(ppid, sig)
Definition: BaseTest.py:73

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

1227 def parseHistosSummary(lines, pos):
1228  """
1229  Extract the histograms infos from the lines starting at pos.
1230  Returns the position of the first line after the summary block.
1231  """
1232  global h_count_re
1233  h_table_head = re.compile(
1234  r'SUCCESS\s+(1D|2D|3D|1D profile|2D profile) histograms in directory\s+"(\w*)"'
1235  )
1236  h_short_summ = re.compile(r"ID=([^\"]+)\s+\"([^\"]+)\"\s+(.*)")
1237 
1238  nlines = len(lines)
1239 
1240  # decode header
1241  m = h_count_re.search(lines[pos])
1242  name = m.group(1).strip()
1243  total = int(m.group(2))
1244  header = {}
1245  for k, v in [x.split("=") for x in m.group(3).split()]:
1246  header[k] = int(v)
1247  pos += 1
1248  header["Total"] = total
1249 
1250  summ = {}
1251  while pos < nlines:
1252  m = h_table_head.search(lines[pos])
1253  if m:
1254  t, d = m.groups(1) # type and directory
1255  t = t.replace(" profile", "Prof")
1256  pos += 1
1257  if pos < nlines:
1258  l = lines[pos]
1259  else:
1260  l = ""
1261  cont = {}
1262  if l.startswith(" | ID"):
1263  # table format
1264  titles = [x.strip() for x in l.split("|")][1:]
1265  pos += 1
1266  while pos < nlines and lines[pos].startswith(" |"):
1267  l = lines[pos]
1268  values = [x.strip() for x in l.split("|")][1:]
1269  hcont = {}
1270  for i in range(len(titles)):
1271  hcont[titles[i]] = values[i]
1272  cont[hcont["ID"]] = hcont
1273  pos += 1
1274  elif l.startswith(" ID="):
1275  while pos < nlines and lines[pos].startswith(" ID="):
1276  values = [
1277  x.strip()
1278  for x in h_short_summ.search(lines[pos]).groups()
1279  ]
1280  cont[values[0]] = values
1281  pos += 1
1282  else: # not interpreted
1283  raise RuntimeError(
1284  "Cannot understand line %d: '%s'" % (pos, l))
1285  if not d in summ:
1286  summ[d] = {}
1287  summ[d][t] = cont
1288  summ[d]["header"] = header
1289  else:
1290  break
1291  if not summ:
1292  # If the full table is not present, we use only the header
1293  summ[name] = {"header": header}
1294  return summ, pos
1295 
1296 
def parseHistosSummary(lines, pos)
Definition: BaseTest.py:1227
decltype(auto) range(Args &&... args)
Zips multiple containers together to form a single range.

◆ PlatformIsNotSupported()

def GaudiTesting.BaseTest.PlatformIsNotSupported (   self,
  context,
  result 
)

Definition at line 1320 of file BaseTest.py.

1320 def PlatformIsNotSupported(self, context, result):
1321  platform = GetPlatform(self)
1322  unsupported = [
1323  re.compile(x) for x in [str(y).strip() for y in unsupported_platforms]
1324  if x
1325  ]
1326  for p_re in unsupported:
1327  if p_re.search(platform):
1328  result.SetOutcome(result.UNTESTED)
1329  result[result.CAUSE] = 'Platform not supported.'
1330  return True
1331  return False
1332 
1333 
def GetPlatform(self)
Definition: BaseTest.py:1334
def PlatformIsNotSupported(self, context, result)
Definition: BaseTest.py:1320

◆ RationalizePath()

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

Definition at line 655 of file BaseTest.py.

655 def RationalizePath(p):
656  """
657  Function used to normalize the used path
658  """
659  newPath = os.path.normpath(os.path.expandvars(p))
660  if os.path.exists(newPath):
661  p = os.path.realpath(newPath)
662  return p
663 
664 

◆ ROOT6WorkAroundEnabled()

def GaudiTesting.BaseTest.ROOT6WorkAroundEnabled (   id = None)

Definition at line 647 of file BaseTest.py.

647  def ROOT6WorkAroundEnabled(id=None):
648  # dummy implementation
649  return False
650 
651 
652 # --------------------------------- TOOLS ---------------------------------#
653 
654 
def ROOT6WorkAroundEnabled(id=None)
Definition: BaseTest.py:647

◆ 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(
55  u'[\x00-\x08\x0b\x0c\x0e-\x1F\uD800-\uDFFF\uFFFE\uFFFF]')
56 
57  def quote(match):
58  'helper function'
59  return ''.join('[NON-XML-CHAR-0x%2X]' % ord(c) for c in match.group())
60 
61  return bad_chars.sub(quote, data)
62 
63 
def sanitize_for_xml(data)
Definition: BaseTest.py:46

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

665 def which(executable):
666  """
667  Locates an executable in the executables path ($PATH) and returns the full
668  path to it. An application is looked for with or without the '.exe' suffix.
669  If the executable cannot be found, None is returned
670  """
671  if os.path.isabs(executable):
672  if not os.path.exists(executable):
673  if executable.endswith('.exe'):
674  if os.path.exists(executable[:-4]):
675  return executable[:-4]
676  else:
677  head, executable = os.path.split(executable)
678  else:
679  return executable
680  for d in os.environ.get("PATH").split(os.pathsep):
681  fullpath = os.path.join(d, executable)
682  if os.path.exists(fullpath):
683  return fullpath
684  if executable.endswith('.exe'):
685  return which(executable[:-4])
686  return None
687 
688 
689 # -------------------------------------------------------------------------#
690 # ----------------------------- Result Classe -----------------------------#
691 # -------------------------------------------------------------------------#
def which(executable)
Definition: BaseTest.py:665

Variable Documentation

◆ __processLine__

GaudiTesting.BaseTest.__processLine__
private

Definition at line 888 of file BaseTest.py.

◆ h_count_re

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

Definition at line 1171 of file BaseTest.py.

◆ lineSkipper

GaudiTesting.BaseTest.lineSkipper

Definition at line 969 of file BaseTest.py.

◆ maskPointers

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

Definition at line 883 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")

Definition at line 884 of file BaseTest.py.

◆ normalizeEOL

GaudiTesting.BaseTest.normalizeEOL = FilePreprocessor()

Definition at line 887 of file BaseTest.py.

◆ normalizeExamples

tuple GaudiTesting.BaseTest.normalizeExamples = maskPointers + normalizeDate

Definition at line 938 of file BaseTest.py.

◆ regexps

GaudiTesting.BaseTest.regexps

Definition at line 1055 of file BaseTest.py.

◆ skipEmptyLines

GaudiTesting.BaseTest.skipEmptyLines = FilePreprocessor()

Definition at line 890 of file BaseTest.py.