Gaudi Framework, version v20r4

Generated: 8 Jan 2009

GaudiTest::GaudiExeTest Class Reference

Inheritance diagram for GaudiTest::GaudiExeTest:

Inheritance graph
[legend]
Collaboration diagram for GaudiTest::GaudiExeTest:

Collaboration graph
[legend]

List of all members.


Detailed Description

Standard Gaudi test.

Definition at line 751 of file GaudiTest.py.


Public Member Functions

def PlatformIsNotSupported
def GetPlatform
def CheckTTreesSummaries
def CheckHistosSummaries
def ValidateWithReference
def ValidateOutput
def DumpEnvironment
def Run
def RunProgram

Public Attributes

 callable
 extra_args
 args_order
 program
 reference
 error_reference
 use_temp_dir
 timeout

Static Public Attributes

list arguments

Private Member Functions

def _expandReferenceFileName
def _find_program

Member Function Documentation

def GaudiTest::GaudiExeTest::PlatformIsNotSupported (   self,
  context,
  result 
)

Definition at line 868 of file GaudiTest.py.

00868                                                      :
00869         platform = self.GetPlatform()
00870         unsupported = [ re.compile(x)
00871                         for x in [ str(y).strip()
00872                                    for y in self.unsupported_platforms ]
00873                         if x
00874                        ]
00875         for p_re in unsupported:
00876             if p_re.search(platform):
00877                 result.SetOutcome(result.UNTESTED)
00878                 result[result.CAUSE] = 'Platform not supported.'
00879                 return True
00880         return False
00881     
    def GetPlatform(self):

def GaudiTest::GaudiExeTest::GetPlatform (   self  ) 

Return the platform Id defined in CMTCONFIG or SCRAM_ARCH.

Definition at line 882 of file GaudiTest.py.

00882                          :
00883         """
00884         Return the platform Id defined in CMTCONFIG or SCRAM_ARCH.
00885         """
00886         arch = "None"
00887         # check architecture name
00888         if "CMTCONFIG" in os.environ:
00889             arch = os.environ["CMTCONFIG"]
00890         elif "SCRAM_ARCH" in os.environ:
00891             arch = os.environ["SCRAM_ARCH"]
00892         return arch
00893     
    def _expandReferenceFileName(self, reffile):

def GaudiTest::GaudiExeTest::_expandReferenceFileName (   self,
  reffile 
) [private]

Definition at line 894 of file GaudiTest.py.

00894                                                :
00895         # if no file is passed, do nothing 
00896         if not reffile:
00897             return ""
00898         
00899         reference = os.path.normpath(os.path.expandvars(reffile))
00900         # old-style platform-specific reference name
00901         spec_ref = reference[:-3] + self.GetPlatform()[0:3] + reference[-3:]
00902         if os.path.isfile(spec_ref):
00903             reference = spec_ref
00904         else: # look for new-style platform specific reference files:
00905             # get all the files whose name start with the reference filename
00906             dirname, basename = os.path.split(reference)
00907             if not dirname: dirname = '.'
00908             head = basename + "."
00909             head_len = len(head)
00910             platform = self.GetPlatform()
00911             candidates = []
00912             for f in os.listdir(dirname):
00913                 if f.startswith(head) and platform.startswith(f[head_len:]):
00914                     candidates.append( (len(f) - head_len, f) )
00915             if candidates: # take the one with highest matching
00916                 candidates.sort()
00917                 reference = os.path.join(dirname, candidates[-1][1])
00918         return reference
00919         
    def CheckTTreesSummaries(self, stdout, result, causes,

def GaudiTest::GaudiExeTest::CheckTTreesSummaries (   self,
  stdout,
  result,
  causes,
  trees_dict = None,
  ignore = r"Basket|.*size|Compression" 
)

Compare the TTree summaries in stdout with the ones in trees_dict or in
the reference file. By default ignore the size, compression and basket
fields.
The presence of TTree summaries when none is expected is not a failure.

Definition at line 920 of file GaudiTest.py.

00922                                                                    :
00923         """
00924         Compare the TTree summaries in stdout with the ones in trees_dict or in
00925         the reference file. By default ignore the size, compression and basket
00926         fields.
00927         The presence of TTree summaries when none is expected is not a failure.
00928         """
00929         if trees_dict is None:
00930             reference = self._expandReferenceFileName(self.reference)
00931             # call the validator if the file exists
00932             if reference and os.path.isfile(reference):
00933                 trees_dict = findTTreeSummaries(open(reference).read())
00934             else:
00935                 trees_dict = {}
00936         
00937         from pprint import PrettyPrinter
00938         pp = PrettyPrinter()
00939         if trees_dict:
00940             result["GaudiTest.TTrees.expected"] = result.Quote(pp.pformat(trees_dict))        
00941             if ignore:
00942                 result["GaudiTest.TTrees.ignore"] = result.Quote(ignore)
00943         
00944         trees = findTTreeSummaries(stdout)
00945         failed = cmpTreesDicts(trees_dict, trees, ignore)
00946         if failed:
00947             causes.append("trees summaries")
00948             msg = "%s: %s != %s" % getCmpFailingValues(trees_dict, trees, failed)
00949             result["GaudiTest.TTrees.failure_on"] = result.Quote(msg)
00950             result["GaudiTest.TTrees.found"] = result.Quote(pp.pformat(trees))
00951         
00952         return causes
00953 
    def CheckHistosSummaries(self, stdout, result, causes,

def GaudiTest::GaudiExeTest::CheckHistosSummaries (   self,
  stdout,
  result,
  causes,
  dict = None,
  ignore = None 
)

Compare the TTree summaries in stdout with the ones in trees_dict or in
the reference file. By default ignore the size, compression and basket
fields.
The presence of TTree summaries when none is expected is not a failure.

Definition at line 954 of file GaudiTest.py.

00956                                            :
00957         """
00958         Compare the TTree summaries in stdout with the ones in trees_dict or in
00959         the reference file. By default ignore the size, compression and basket
00960         fields.
00961         The presence of TTree summaries when none is expected is not a failure.
00962         """
00963         if dict is None:
00964             reference = self._expandReferenceFileName(self.reference)
00965             # call the validator if the file exists
00966             if reference and os.path.isfile(reference):
00967                 dict = findHistosSummaries(open(reference).read())
00968             else:
00969                 dict = {}
00970         
00971         from pprint import PrettyPrinter
00972         pp = PrettyPrinter()
00973         if dict:
00974             result["GaudiTest.Histos.expected"] = result.Quote(pp.pformat(dict))        
00975             if ignore:
00976                 result["GaudiTest.Histos.ignore"] = result.Quote(ignore)
00977         
00978         histos = findHistosSummaries(stdout)
00979         failed = cmpTreesDicts(dict, histos, ignore)
00980         if failed:
00981             causes.append("histos summaries")
00982             msg = "%s: %s != %s" % getCmpFailingValues(dict, histos, failed)
00983             result["GaudiTest.Histos.failure_on"] = result.Quote(msg)
00984             result["GaudiTest.Histos.found"] = result.Quote(pp.pformat(histos))
00985         
00986         return causes
00987 
    def ValidateWithReference(self, stdout, stderr, result, causes, preproc = None):

def GaudiTest::GaudiExeTest::ValidateWithReference (   self,
  stdout,
  stderr,
  result,
  causes,
  preproc = None 
)

Default validation action: compare standard output and error to the
reference files.

Definition at line 988 of file GaudiTest.py.

00988                                                                                    :
00989         """
00990         Default validation action: compare standard output and error to the
00991         reference files.
00992         """
00993         # set the default output preprocessor
00994         if preproc is None:
00995             preproc = normalizeExamples
00996         # check standard output
00997         reference = self._expandReferenceFileName(self.reference)
00998         # call the validator if the file exists
00999         if reference and os.path.isfile(reference):
01000             result["GaudiTest.output_reference"] = reference
01001             causes += ReferenceFileValidator(reference,
01002                                              "standard output",
01003                                              "GaudiTest.output_diff",
01004                                              preproc = preproc)(stdout, result)
01005         
01006         # Compare TTree summaries
01007         causes = self.CheckTTreesSummaries(stdout, result, causes)
01008         causes = self.CheckHistosSummaries(stdout, result, causes)
01009         
01010         if causes: # Write a new reference file for stdout
01011             newref = open(reference + ".new","w")
01012             # sanitize newlines
01013             for l in stdout.splitlines():
01014                 newref.write(l.rstrip() + '\n')
01015             del newref # flush and close
01016         
01017         
01018         # check standard error
01019         reference = self._expandReferenceFileName(self.error_reference)
01020         # call the validator if we have a file to use
01021         if reference and os.path.isfile(reference):
01022             result["GaudiTest.error_reference"] = reference
01023             newcauses = ReferenceFileValidator(reference,
01024                                                "standard error",
01025                                                "GaudiTest.error_diff",
01026                                                preproc = preproc)(stderr, result)
01027             causes += newcauses
01028             if newcauses: # Write a new reference file for stdedd
01029                 newref = open(reference + ".new","w")
01030                 # sanitize newlines
01031                 for l in stderr.splitlines():
01032                     newref.write(l.rstrip() + '\n')
01033                 del newref # flush and close    
01034         else:
01035             causes += BasicOutputValidator(self.stderr,
01036                                            "standard error",
01037                                            "ExecTest.expected_stderr")(stderr, result)
01038         
01039         return causes
01040         
    def ValidateOutput(self, stdout, stderr, result):

def GaudiTest::GaudiExeTest::ValidateOutput (   self,
  stdout,
  stderr,
  result 
)

Definition at line 1041 of file GaudiTest.py.

01041                                                     :
01042         causes = []
01043         # if the test definition contains a custom validator, use it
01044         if self.validator.strip() != "":
01045             class CallWrapper(object):
01046                 """
01047                 Small wrapper class to dynamically bind some default arguments
01048                 to a callable.
01049                 """
01050                 def __init__(self, callable, extra_args = {}):
01051                     self.callable = callable
01052                     self.extra_args = extra_args
01053                     # get the list of names of positional arguments
01054                     from inspect import getargspec
01055                     self.args_order = getargspec(callable)[0]
01056                     # Remove "self" from the list of positional arguments
01057                     # since it is added automatically 
01058                     if self.args_order[0] == "self":
01059                         del self.args_order[0]
01060                 def __call__(self, *args, **kwargs):
01061                     # Check which positional arguments are used
01062                     positional = self.args_order[:len(args)]
01063                     
01064                     kwargs = dict(kwargs) # copy the arguments dictionary
01065                     for a in self.extra_args:
01066                         # use "extra_args" for the arguments not specified as
01067                         # positional or keyword
01068                         if a not in positional and a not in kwargs:
01069                             kwargs[a] = self.extra_args[a]
01070                     return apply(self.callable, args, kwargs)
01071             # local names to be exposed in the script 
01072             exported_symbols = {"self":self,
01073                                 "stdout":stdout,
01074                                 "stderr":stderr,
01075                                 "result":result,
01076                                 "causes":causes,
01077                                 "findReferenceBlock":
01078                                     CallWrapper(findReferenceBlock, {"stdout":stdout,
01079                                                                      "result":result,
01080                                                                      "causes":causes}),
01081                                 "validateWithReference":
01082                                     CallWrapper(self.ValidateWithReference, {"stdout":stdout,
01083                                                                              "stderr":stderr,
01084                                                                              "result":result,
01085                                                                              "causes":causes}),
01086                                 "countErrorLines":
01087                                     CallWrapper(countErrorLines, {"stdout":stdout,
01088                                                                   "result":result,
01089                                                                   "causes":causes}),
01090                                 "checkTTreesSummaries":
01091                                     CallWrapper(self.CheckTTreesSummaries, {"stdout":stdout,
01092                                                                             "result":result,
01093                                                                             "causes":causes}),
01094                                 "checkHistosSummaries":
01095                                     CallWrapper(self.CheckHistosSummaries, {"stdout":stdout,
01096                                                                             "result":result,
01097                                                                             "causes":causes}),
01098                                 
01099                                 }
01100             exec self.validator in globals(), exported_symbols
01101         else:
01102             self.ValidateWithReference(stdout, stderr, result, causes)
01103         
01104         return causes
01105     
    def DumpEnvironment(self, result):

def GaudiTest::GaudiExeTest::DumpEnvironment (   self,
  result 
)

Add the content of the environment to the result object.

Copied from the QMTest class of COOL.

Definition at line 1106 of file GaudiTest.py.

01106                                      :
01107         """
01108         Add the content of the environment to the result object.
01109         
01110         Copied from the QMTest class of COOL.
01111         """
01112         vars = os.environ.keys()
01113         vars.sort()
01114         result['GaudiTest.environment'] = \
01115             result.Quote('\n'.join(["%s=%s"%(v,os.environ[v]) for v in vars]))
01116 
    def _find_program(self,prog):

def GaudiTest::GaudiExeTest::_find_program (   self,
  prog 
) [private]

Definition at line 1117 of file GaudiTest.py.

01117                                 :
01118         # check if it is an absolute path or the file can be found
01119         # from the local directory, otherwise search for it in PATH
01120         if not os.path.isabs(prog) and not os.path.isfile(prog):
01121             for d in os.environ["PATH"].split(os.pathsep):
01122                 p = os.path.join(d,prog)
01123                 if os.path.isfile(p):
01124                     return p
01125         return prog
01126         
    def Run(self, context, result):

def GaudiTest::GaudiExeTest::Run (   self,
  context,
  result 
)

Run the test.

'context' -- A 'Context' giving run-time parameters to the
test.

'result' -- A 'Result' object.  The outcome will be
'Result.PASS' when this method is called.  The 'result' may be
modified by this method to indicate outcomes other than
'Result.PASS' or to add annotations.

Definition at line 1127 of file GaudiTest.py.

01127                                   :
01128         """Run the test.
01129 
01130         'context' -- A 'Context' giving run-time parameters to the
01131         test.
01132 
01133         'result' -- A 'Result' object.  The outcome will be
01134         'Result.PASS' when this method is called.  The 'result' may be
01135         modified by this method to indicate outcomes other than
01136         'Result.PASS' or to add annotations."""
01137         
01138         # Check if the platform is supported
01139         if self.PlatformIsNotSupported(context, result):
01140             return
01141         
01142         def rationalizepath(p):
01143             p = os.path.normpath(os.path.expandvars(p))
01144             if os.path.exists(p):
01145                 p = os.path.realpath(p)
01146             return p
01147         
01148         # Prepare program name and arguments (expanding variables, and converting to absolute) 
01149         if self.program:
01150             prog = rationalizepath(self.program)
01151         elif "GAUDIEXE" in os.environ:
01152             prog = os.environ["GAUDIEXE"]
01153         else:
01154             prog = "Gaudi.exe"
01155         self.program = prog
01156             
01157         dummy, prog_ext = os.path.splitext(prog)
01158         if prog_ext not in [ ".exe", ".py", ".bat" ] and self.GetPlatform()[0:3] == "win":
01159             prog += ".exe"
01160             prog_ext = ".exe"
01161             
01162         prog = self._find_program(prog)
01163         
01164         # Convert paths to absolute paths in arguments and reference files
01165         args = map(rationalizepath, self.args)
01166         self.reference = rationalizepath(self.reference)
01167         self.error_reference = rationalizepath(self.error_reference)
01168         
01169         
01170         # check if the user provided inline options
01171         tmpfile = None
01172         if self.options.strip():
01173             ext = ".opts"
01174             if re.search(r"from\s*Gaudi.Configuration\s*import\s*\*", self.options):
01175                 ext = ".py"
01176             tmpfile = TempFile(ext)
01177             tmpfile.writelines("\n".join(self.options.splitlines()))
01178             tmpfile.flush()
01179             args.append(tmpfile.name)
01180             result["GaudiTest.options"] = result.Quote(self.options)
01181         
01182         # if the program is a python file, execute it through python
01183         if prog_ext == ".py":
01184             args.insert(0,prog)
01185             if self.GetPlatform()[0:3] == "win":
01186                 prog = self._find_program("python.exe")
01187             else:
01188                 prog = self._find_program("python")
01189         
01190         # Change to the working directory if specified or to the default temporary
01191         origdir = os.getcwd()
01192         if self.workdir:
01193             os.chdir(str(os.path.normpath(os.path.expandvars(self.workdir))))
01194         elif "qmtest.tmpdir" in context and self.use_temp_dir == "true":
01195             os.chdir(context["qmtest.tmpdir"])
01196         
01197         if "QMTEST_IGNORE_TIMEOUT" not in os.environ:
01198             self.timeout = max(self.timeout,600)
01199         else:
01200             self.timeout = -1
01201         
01202         try:
01203             # Run the test
01204             self.RunProgram(prog, 
01205                             [ prog ] + args,
01206                             context, result)
01207             # Record the content of the enfironment for failing tests 
01208             if result.GetOutcome() not in [ result.PASS ]:
01209                 self.DumpEnvironment(result)
01210         finally:
01211             # revert to the original directory
01212             os.chdir(origdir)
01213         
    def RunProgram(self, program, arguments, context, result):

def GaudiTest::GaudiExeTest::RunProgram (   self,
  program,
  arguments,
  context,
  result 
)

Run the 'program'.

'program' -- The path to the program to run.

'arguments' -- A list of the arguments to the program.  This
list must contain a first argument corresponding to 'argv[0]'.

'context' -- A 'Context' giving run-time parameters to the
test.

'result' -- A 'Result' object.  The outcome will be
'Result.PASS' when this method is called.  The 'result' may be
modified by this method to indicate outcomes other than
'Result.PASS' or to add annotations.

@attention: This method has been copied from command.ExecTestBase
    (QMTest 2.3.0) and modified to keep stdout and stderr
    for tests that have been terminated by a signal.
    (Fundamental for debugging in the Application Area)

Definition at line 1214 of file GaudiTest.py.

01214                                                              :
01215         """Run the 'program'.
01216 
01217         'program' -- The path to the program to run.
01218 
01219         'arguments' -- A list of the arguments to the program.  This
01220         list must contain a first argument corresponding to 'argv[0]'.
01221 
01222         'context' -- A 'Context' giving run-time parameters to the
01223         test.
01224 
01225         'result' -- A 'Result' object.  The outcome will be
01226         'Result.PASS' when this method is called.  The 'result' may be
01227         modified by this method to indicate outcomes other than
01228         'Result.PASS' or to add annotations.
01229         
01230         @attention: This method has been copied from command.ExecTestBase
01231                     (QMTest 2.3.0) and modified to keep stdout and stderr
01232                     for tests that have been terminated by a signal.
01233                     (Fundamental for debugging in the Application Area)
01234         """
01235 
01236         # Construct the environment.
01237         environment = self.MakeEnvironment(context)
01238         # Create the executable.
01239         if self.timeout >= 0:
01240             timeout = self.timeout
01241         else:
01242             # If no timeout was specified, we sill run this process in a
01243             # separate process group and kill the entire process group
01244             # when the child is done executing.  That means that
01245             # orphaned child processes created by the test will be
01246             # cleaned up.
01247             timeout = -2
01248         e = qm.executable.Filter(self.stdin, timeout)
01249         # Run it.
01250         exit_status = e.Run(arguments, environment, path = program)
01251 
01252         # If the process terminated normally, check the outputs.
01253         if sys.platform == "win32" or os.WIFEXITED(exit_status):
01254             # There are no causes of failure yet.
01255             causes = []
01256             # The target program terminated normally.  Extract the
01257             # exit code, if this test checks it.
01258             if self.exit_code is None:
01259                 exit_code = None
01260             elif sys.platform == "win32":
01261                 exit_code = exit_status
01262             else:
01263                 exit_code = os.WEXITSTATUS(exit_status)
01264             # Get the output generated by the program.
01265             stdout = e.stdout
01266             stderr = e.stderr
01267             # Record the results.
01268             result["ExecTest.exit_code"] = str(exit_code)
01269             result["ExecTest.stdout"] = result.Quote(stdout)
01270             result["ExecTest.stderr"] = result.Quote(stderr)
01271             # Check to see if the exit code matches.
01272             if exit_code != self.exit_code:
01273                 causes.append("exit_code")
01274                 result["ExecTest.expected_exit_code"] \
01275                     = str(self.exit_code)
01276             # Validate the output.
01277             causes += self.ValidateOutput(stdout, stderr, result)
01278             # If anything went wrong, the test failed.
01279             if causes:
01280                 result.Fail("Unexpected %s." % string.join(causes, ", ")) 
01281         elif os.WIFSIGNALED(exit_status):
01282             # The target program terminated with a signal.  Construe
01283             # that as a test failure.
01284             signal_number = str(os.WTERMSIG(exit_status))
01285             result.Fail("Program terminated by signal.")
01286             result["ExecTest.signal_number"] = signal_number
01287             result["ExecTest.stdout"] = result.Quote(e.stdout)
01288             result["ExecTest.stderr"] = result.Quote(e.stderr)
01289         elif os.WIFSTOPPED(exit_status):
01290             # The target program was stopped.  Construe that as a
01291             # test failure.
01292             signal_number = str(os.WSTOPSIG(exit_status))
01293             result.Fail("Program stopped by signal.")
01294             result["ExecTest.signal_number"] = signal_number
01295             result["ExecTest.stdout"] = result.Quote(e.stdout)
01296             result["ExecTest.stderr"] = result.Quote(e.stderr)
01297         else:
01298             # The target program terminated abnormally in some other
01299             # manner.  (This shouldn't normally happen...)
01300             result.Fail("Program did not terminate normally.")
01301         
01302         # Marco Cl.: This is a special trick to fix a "problem" with the output
01303         # of gaudi jobs when they use colors
01304         esc = '\x1b'
01305         repr_esc = '\\x1b'
01306         result["ExecTest.stdout"] = result["ExecTest.stdout"].replace(esc,repr_esc)
01307         # TODO: (MCl) improve the hack for colors in standard output
01308         #             may be converting them to HTML tags
        #             may be converting them to HTML tags


Member Data Documentation

Definition at line 754 of file GaudiTest.py.

Definition at line 1051 of file GaudiTest.py.

Definition at line 1052 of file GaudiTest.py.

Definition at line 1055 of file GaudiTest.py.

Definition at line 1155 of file GaudiTest.py.

Definition at line 1166 of file GaudiTest.py.

Definition at line 1167 of file GaudiTest.py.

Definition at line 1194 of file GaudiTest.py.

Definition at line 1198 of file GaudiTest.py.


The documentation for this class was generated from the following file:

Generated at Thu Jan 8 17:54:00 2009 for Gaudi Framework, version v20r4 by Doxygen version 1.5.6 written by Dimitri van Heesch, © 1997-2004