| # Gaudi Framework, version v21r8 |

Home |  | Generated: 17 Mar 2010

# GaudiTest Namespace Reference

## Classes
class | TemporaryEnvironment
class | TempDir
class | TempFile
class | CMT
class | BasicOutputValidator
class | FilePreprocessor
class | FilePreprocessorSequence
class | LineSkipper
class | BlockSkipper
class | RegexpReplacer
class | LineSorter
| Special preprocessor sorting the list of strings (whitespace separated) that follow a signature on a single line. More...
class | ReferenceFileValidator
class | GaudiFilterExecutable
class | GaudiExeTest
class | HTMLResultStream
## Functions
def | which
| Locates an executable in the executables path ($PATH) and returns the full path to it.
def | rationalizepath
def | findReferenceBlock
def | countErrorLines
def | _parseTTreeSummary
def | findTTreeSummaries
def | cmpTreesDicts
def | getCmpFailingValues
def | parseHistosSummary
def | findHistosSummaries
## Variables
string | __author__ = 'Marco Clemencic CERN/PH-LBC'
string | __version__ = "$Revision: 1.52 $"
string | __tag__ = "$Name: $"
tuple | maskPointers = RegexpReplacer("0x[0-9a-fA-F]{4,16}","0x########")
tuple | normalizeDate
tuple | normalizeEOL = FilePreprocessor()
tuple | skipEmptyLines = FilePreprocessor()
| normalizeExamples = maskPointers+normalizeDate
tuple | h_count_re = re.compile(r"^(.*)SUCCESS\s+Booked (\d+) Histogram\(s\) :\s+(.*)")

## Function Documentation

def GaudiTest::_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 614 of file GaudiTest.py.

    00614                                   :
    00615     """
    00616     Parse the TTree summary table in lines, starting from pos.
    00617     Returns a tuple with the dictionary with the digested informations and the
    00618     position of the first line after the summary.
    00619     """
    00620     result = {}
    00621     i = pos + 1 # first line is a sequence of '*'
    00622     count = len(lines)
    00623
    00624     splitcols = lambda l: [ f.strip() for f in l.strip("*\n").split(':',2) ]
    00625     def parseblock(ll):
    00626         r = {}
    00627         cols = splitcols(ll[0])
    00628         r["Name"], r["Title"] = cols[1:]
    00629
    00630         cols = splitcols(ll[1])
    00631         r["Entries"] = int(cols[1])
    00632
    00633         sizes = cols[2].split()
    00634         r["Total size"] = int(sizes[2])
    00635         if sizes[-1] == "memory":
    00636             r["File size"] = 0
    00637         else:
    00638             r["File size"] = int(sizes[-1])
    00639
    00640         cols = splitcols(ll[2])
    00641         sizes = cols[2].split()
    00642         if cols[0] == "Baskets":
    00643             r["Baskets"] = int(cols[1])
    00644             r["Basket size"] = int(sizes[2])
    00645         r["Compression"] = float(sizes[-1])
    00646         return r
    00647
    00648     if i < (count - 3) and lines[i].startswith("*Tree"):
    00649         result = parseblock(lines[i:i+3])
    00650         result["Branches"] = {}
    00651         i += 4
    00652         while i < (count - 3) and lines[i].startswith("*Br"):
    00653             branch = parseblock(lines[i:i+3])
    00654             result["Branches"][branch["Name"]] = branch
    00655             i += 4
    00656
    00657     return (result, i)
    00658
    def findTTreeSummaries(stdout):

def GaudiTest::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 680 of file GaudiTest.py.

    00680                                                      :
    00681     """
    00682     Check that all the keys in reference are in to_check too, with the same value.
    00683     If the value is a dict, the function is called recursively. to_check can
    00684     contain more keys than reference, that will not be tested.
    00685     The function returns at the first difference found.
    00686     """
    00687     fail_keys = []
    00688     # filter the keys in the reference dictionary
    00689     if ignore:
    00690         ignore_re = re.compile(ignore)
    00691         keys = [ key for key in reference if not ignore_re.match(key) ]
    00692     else:
    00693         keys = reference.keys()
    00694     # loop over the keys (not ignored) in the reference dictionary
    00695     for k in keys:
    00696         if k in to_check: # the key must be in the dictionary to_check
    00697             if (type(reference[k]) is dict) and (type(to_check[k]) is dict):
    00698                 # if both reference and to_check values are dictionaries, recurse
    00699                 failed = fail_keys = cmpTreesDicts(reference[k], to_check[k], ignore)
    00700             else:
    00701                 # compare the two values
    00702                 failed = to_check[k] != reference[k]
    00703         else: # handle missing keys in the dictionary to check (i.e. failure)
    00704             to_check[k] = None
    00705             failed = True
    00706         if failed:
    00707             fail_keys.insert(0, k)
    00708             break # exit from the loop at the first failure
    00709     return fail_keys # return the list of keys bringing to the different values
    00710
    def getCmpFailingValues(reference, to_check, fail_path):

def GaudiTest::countErrorLines | ( |  | expected = `{'ERROR':0`,
|  |  | FATAL |
| ) |  |  |

Definition at line 578 of file GaudiTest.py.

    00578                                {'ERROR':0, 'FATAL':0}, **kwargs):
    00579     """
    00580     Count the number of messages with required severity (by default ERROR and FATAL)
    00581     and check if their numbers match the expected ones (0 by default).
    00582     The dictionary "expected" can be used to tune the number of errors and fatals
    00583     allowed, or to limit the number of expected warnings etc.
    00584     """
    00585     stdout = kwargs["stdout"]
    00586     result = kwargs["result"]
    00587     causes = kwargs["causes"]
    00588
    00589     # prepare the dictionary to record the extracted lines
    00590     errors = {}
    00591     for sev in expected:
    00592         errors[sev] = []
    00593
    00594     outlines = stdout.splitlines()
    00595     from math import log10
    00596     fmt = "%%%dd - %%s" % (int(log10(len(outlines))+1))
    00597
    00598     linecount = 0
    00599     for l in outlines:
    00600         linecount += 1
    00601         words = l.split()
    00602         if len(words) >= 2 and words[1] in errors:
    00603             errors[words[1]].append(fmt%(linecount,l.rstrip()))
    00604
    00605     for e in errors:
    00606         if len(errors[e]) != expected[e]:
    00607             causes.append('%s(%d)'%(e,len(errors[e])))
    00608             result["GaudiTest.lines.%s"%e] = result.Quote('\n'.join(errors[e]))
    00609             result["GaudiTest.lines.%s.expected#"%e] = result.Quote(str(expected[e]))
    00610
    00611     return causes
    00612
    00613

def GaudiTest::findHistosSummaries | ( |  | stdout | ) |

    Scan stdout to find ROOT TTree summaries and digest them.

Definition at line 787 of file GaudiTest.py.

    00787                                :
    00788     """
    00789     Scan stdout to find ROOT TTree summaries and digest them.
    00790     """
    00791     outlines = stdout.splitlines()
    00792     nlines = len(outlines) - 1
    00793     summaries = {}
    00794     global h_count_re
    00795
    00796     pos = 0
    00797     while pos < nlines:
    00798         summ = {}
    00799         # find first line of block:
    00800         match = h_count_re.search(outlines[pos])
    00801         while pos < nlines and not match:
    00802             pos += 1
    00803             match = h_count_re.search(outlines[pos])
    00804         if match:
    00805             summ, pos = parseHistosSummary(outlines, pos)
    00806         summaries.update(summ)
    00807     return summaries
    00808
    class GaudiFilterExecutable(qm.executable.Filter):

def GaudiTest::findReferenceBlock | ( |  | reference,
|  |  | stdout,
|  |  | result,
|  |  | causes,
|  |  | signature_offset = `0`,
|  |  | signature = `None`,
|  |  | id = `None` |
| ) |  |  |

    Given a block of text, tries to find it in the output.
    The block had to be identified by a signature line. By default, the first
    line is used as signature, or the line pointed to by signature_offset. If
    signature_offset points outside the block, a signature line can be passed as
    signature argument. Note: if 'signature' is None (the default), a negative
    signature_offset is interpreted as index in a list (e.g. -1 means the last
    line), otherwise the it is interpreted as the number of lines before the
    first one of the block the signature must appear.
    The parameter 'id' allow to distinguish between different calls to this
    function in the same validation code.

Definition at line 531 of file GaudiTest.py.

    00532                                  :
    00533     """
    00534     Given a block of text, tries to find it in the output.
    00535     The block had to be identified by a signature line. By default, the first
    00536     line is used as signature, or the line pointed to by signature_offset. If
    00537     signature_offset points outside the block, a signature line can be passed as
    00538     signature argument. Note: if 'signature' is None (the default), a negative
    00539     signature_offset is interpreted as index in a list (e.g. -1 means the last
    00540     line), otherwise the it is interpreted as the number of lines before the
    00541     first one of the block the signature must appear.
    00542     The parameter 'id' allow to distinguish between different calls to this
    00543     function in the same validation code.
    00544     """
    00545     # split reference file, sanitize EOLs and remove empty lines
    00546     reflines = filter(None,map(lambda s: s.rstrip(), reference.splitlines()))
    00547     if not reflines:
    00548         raise RuntimeError("Empty (or null) reference")
    00549     # the same on standard output
    00550     outlines = filter(None,map(lambda s: s.rstrip(), stdout.splitlines()))
    00551
    00552     res_field = "GaudiTest.RefBlock"
    00553     if id:
    00554         res_field += "_%s" % id
    00555
    00556     if signature is None:
    00557         if signature_offset < 0:
    00558             signature_offset = len(reference)+signature_offset
    00559         signature = reflines[signature_offset]
    00560     # find the reference block in the output file
    00561     try:
    00562         pos = outlines.index(signature)
    00563         outlines = outlines[pos-signature_offset:pos+len(reflines)-signature_offset]
    00564         if reflines != outlines:
    00565             msg = "standard output"
    00566             # I do not want 2 messages in causes if teh function is called twice
    00567             if not msg in causes:
    00568                 causes.append(msg)
    00569             result[res_field + ".observed"] = result.Quote("\n".join(outlines))
    00570     except ValueError:
    00571         causes.append("missing signature")
    00572     result[res_field + ".signature"] = result.Quote(signature)
    00573     if len(reflines) > 1 or signature != reflines[0]:
    00574         result[res_field + ".expected"] = result.Quote("\n".join(reflines))
    00575
    00576     return causes
    00577
    def countErrorLines(expected = {'ERROR':0, 'FATAL':0}, **kwargs):

def GaudiTest::findTTreeSummaries | ( |  | stdout | ) |

    Scan stdout to find ROOT TTree summaries and digest them.

Definition at line 659 of file GaudiTest.py.

    00659                               :
    00660     """
    00661     Scan stdout to find ROOT TTree summaries and digest them.
    00662     """
    00663     stars = re.compile(r"^\*+$")
    00664     outlines = stdout.splitlines()
    00665     nlines = len(outlines)
    00666     trees = {}
    00667
    00668     i = 0
    00669     while i < nlines: #loop over the output
    00670         # look for
    00671         while i < nlines and not stars.match(outlines[i]):
    00672             i += 1
    00673         if i < nlines:
    00674             tree, i = _parseTTreeSummary(outlines, i)
    00675             if tree:
    00676                 trees[tree["Name"]] = tree
    00677
    00678     return trees
    00679
    def cmpTreesDicts(reference, to_check, ignore = None):

def GaudiTest::getCmpFailingValues | ( |  | reference,
|  |  | to_check,
|  |  | fail_path |
| ) |  |  |

Definition at line 711 of file GaudiTest.py.

    00711                                                        :
    00712     c = to_check
    00713     r = reference
    00714     for k in fail_path:
    00715         c = c.get(k,None)
    00716         r = r.get(k,None)
    00717         if c is None or r is None:
    00718             break # one of the dictionaries is not deep enough
    00719     return (fail_path, r, c)
    00720
    00721 # signature of the print-out of the histograms
    h_count_re = re.compile(r"^(.*)SUCCESS\s+Booked (\d+) Histogram\(s\) :\s+(.*)")

def GaudiTest::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 724 of file GaudiTest.py.

    00724                                   :
    00725     """
    00726     Extract the histograms infos from the lines starting at pos.
    00727     Returns the position of the first line after the summary block.
    00728     """
    00729     global h_count_re
    00730     h_table_head = re.compile(r'SUCCESS\s+List of booked (1D|2D|3D|1D profile|2D profile) histograms in directory\s+"(\w*)"')
    00731     h_short_summ = re.compile(r"ID=([^\"]+)\s+\"([^\"]+)\"\s+(.*)")
    00732
    00733     nlines = len(lines)
    00734
    00735     # decode header
    00736     m = h_count_re.search(lines[pos])
    00737     name = m.group(1).strip()
    00738     total = int(m.group(2))
    00739     header = {}
    00740     for k, v in [ x.split("=") for x in  m.group(3).split() ]:
    00741         header[k] = int(v)
    00742     pos += 1
    00743     header["Total"] = total
    00744
    00745     summ = {}
    00746     while pos < nlines:
    00747         m = h_table_head.search(lines[pos])
    00748         if m:
    00749             t, d = m.groups(1) # type and directory
    00750             t = t.replace(" profile", "Prof")
    00751             pos += 1
    00752             if pos < nlines:
    00753                 l = lines[pos]
    00754             else:
    00755                 l = ""
    00756             cont = {}
    00757             if l.startswith(" | ID"):
    00758                 # table format
    00759                 titles = [ x.strip() for x in l.split("|")][1:]
    00760                 pos += 1
    00761                 while pos < nlines and lines[pos].startswith(" |"):
    00762                     l = lines[pos]
    00763                     values = [ x.strip() for x in l.split("|")][1:]
    00764                     hcont = {}
    00765                     for i in range(len(titles)):
    00766                         hcont[titles[i]] = values[i]
    00767                     cont[hcont["ID"]] = hcont
    00768                     pos += 1
    00769             elif l.startswith(" ID="):
    00770                 while pos < nlines and lines[pos].startswith(" ID="):
    00771                     values = [ x.strip() for x in  h_short_summ.search(lines[pos]).groups() ]
    00772                     cont[values[0]] = values
    00773                     pos += 1
    00774             else: # not interpreted
    00775                 raise RuntimeError("Cannot understand line %d: '%s'" % (pos, l))
    00776             if not d in summ:
    00777                 summ[d] = {}
    00778             summ[d][t] = cont
    00779             summ[d]["header"] = header
    00780         else:
    00781             break
    00782     if not summ:
    00783         # If the full table is not present, we use only the header
    00784         summ[name] = {"header": header}
    00785     return summ, pos
    00786
    def findHistosSummaries(stdout):

def GaudiTest::rationalizepath | ( |  | p | ) |

Definition at line 272 of file GaudiTest.py.

    00272                       :
    00273     p = os.path.normpath(os.path.expandvars(p))
    00274     if os.path.exists(p):
    00275         p = os.path.realpath(p)
    00276     return p
    00277
    ########################################################################

def GaudiTest::which | ( |  | executable | ) |

Locates an executable in the executables path ($PATH) and returns the full path to it.

If the excutable cannot be found, None is returned

Definition at line 265 of file GaudiTest.py.

    00265                      :
    00266     for d in os.environ.get("PATH").split(os.pathsep):
    00267         fullpath = os.path.join(d,executable)
    00268         if os.path.exists(fullpath):
    00269             return fullpath
    00270     return None
    00271
    def rationalizepath(p):

## Variable Documentation

string GaudiTest::__author__ = 'Marco Clemencic CERN/PH-LBC'

Definition at line 5 of file GaudiTest.py.

string GaudiTest::__tag__ = "$Name: $"

Definition at line 7 of file GaudiTest.py.

string GaudiTest::__version__ = "$Revision: 1.52 $"

Definition at line 6 of file GaudiTest.py.

tuple GaudiTest::h_count_re = re.compile(r"^(.*)SUCCESS\s+Booked (\d+) Histogram\(s\) :\s+(.*)")

Definition at line 722 of file GaudiTest.py.

tuple GaudiTest::maskPointers = RegexpReplacer("0x[0-9a-fA-F]{4,16}","0x########")

Definition at line 407 of file GaudiTest.py.

tuple GaudiTest::normalizeDate

Initial value:

    RegexpReplacer("[0-2]?[0-9]:[0-5][0-9]:[0-5][0-9] [0-9]{4}[-/][01][0-9][-/][0-3][0-9] *(CES?T)?",
                                   "00:00:00 1970-01-01")

Definition at line 408 of file GaudiTest.py.

tuple GaudiTest::normalizeEOL = FilePreprocessor()

Definition at line 410 of file GaudiTest.py.

tuple GaudiTest::normalizeExamples = maskPointers+normalizeDate

Definition at line 433 of file GaudiTest.py.

tuple GaudiTest::skipEmptyLines = FilePreprocessor()

Definition at line 413 of file GaudiTest.py.