Gaudi Framework, version v21r4

Home   Generated: 7 Sep 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 949 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 1066 of file GaudiTest.py.

01066                                                      :
01067         platform = self.GetPlatform()
01068         unsupported = [ re.compile(x)
01069                         for x in [ str(y).strip()
01070                                    for y in self.unsupported_platforms ]
01071                         if x
01072                        ]
01073         for p_re in unsupported:
01074             if p_re.search(platform):
01075                 result.SetOutcome(result.UNTESTED)
01076                 result[result.CAUSE] = 'Platform not supported.'
01077                 return True
01078         return False
01079     
    def GetPlatform(self):

def GaudiTest::GaudiExeTest::GetPlatform (   self  ) 

Return the platform Id defined in CMTCONFIG or SCRAM_ARCH.

Definition at line 1080 of file GaudiTest.py.

01080                          :
01081         """
01082         Return the platform Id defined in CMTCONFIG or SCRAM_ARCH.
01083         """
01084         arch = "None"
01085         # check architecture name
01086         if "CMTCONFIG" in os.environ:
01087             arch = os.environ["CMTCONFIG"]
01088         elif "SCRAM_ARCH" in os.environ:
01089             arch = os.environ["SCRAM_ARCH"]
01090         return arch
01091     
    def _expandReferenceFileName(self, reffile):

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

Definition at line 1092 of file GaudiTest.py.

01092                                                :
01093         # if no file is passed, do nothing 
01094         if not reffile:
01095             return ""
01096         
01097         reference = os.path.normpath(os.path.expandvars(reffile))
01098         # old-style platform-specific reference name
01099         spec_ref = reference[:-3] + self.GetPlatform()[0:3] + reference[-3:]
01100         if os.path.isfile(spec_ref):
01101             reference = spec_ref
01102         else: # look for new-style platform specific reference files:
01103             # get all the files whose name start with the reference filename
01104             dirname, basename = os.path.split(reference)
01105             if not dirname: dirname = '.'
01106             head = basename + "."
01107             head_len = len(head)
01108             platform = self.GetPlatform()
01109             candidates = []
01110             for f in os.listdir(dirname):
01111                 if f.startswith(head) and platform.startswith(f[head_len:]):
01112                     candidates.append( (len(f) - head_len, f) )
01113             if candidates: # take the one with highest matching
01114                 candidates.sort()
01115                 reference = os.path.join(dirname, candidates[-1][1])
01116         return reference
01117         
    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 1118 of file GaudiTest.py.

01120                                                                    :
01121         """
01122         Compare the TTree summaries in stdout with the ones in trees_dict or in
01123         the reference file. By default ignore the size, compression and basket
01124         fields.
01125         The presence of TTree summaries when none is expected is not a failure.
01126         """
01127         if trees_dict is None:
01128             reference = self._expandReferenceFileName(self.reference)
01129             # call the validator if the file exists
01130             if reference and os.path.isfile(reference):
01131                 trees_dict = findTTreeSummaries(open(reference).read())
01132             else:
01133                 trees_dict = {}
01134         
01135         from pprint import PrettyPrinter
01136         pp = PrettyPrinter()
01137         if trees_dict:
01138             result["GaudiTest.TTrees.expected"] = result.Quote(pp.pformat(trees_dict))        
01139             if ignore:
01140                 result["GaudiTest.TTrees.ignore"] = result.Quote(ignore)
01141         
01142         trees = findTTreeSummaries(stdout)
01143         failed = cmpTreesDicts(trees_dict, trees, ignore)
01144         if failed:
01145             causes.append("trees summaries")
01146             msg = "%s: %s != %s" % getCmpFailingValues(trees_dict, trees, failed)
01147             result["GaudiTest.TTrees.failure_on"] = result.Quote(msg)
01148             result["GaudiTest.TTrees.found"] = result.Quote(pp.pformat(trees))
01149         
01150         return causes
01151 
    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 1152 of file GaudiTest.py.

01154                                            :
01155         """
01156         Compare the TTree summaries in stdout with the ones in trees_dict or in
01157         the reference file. By default ignore the size, compression and basket
01158         fields.
01159         The presence of TTree summaries when none is expected is not a failure.
01160         """
01161         if dict is None:
01162             reference = self._expandReferenceFileName(self.reference)
01163             # call the validator if the file exists
01164             if reference and os.path.isfile(reference):
01165                 dict = findHistosSummaries(open(reference).read())
01166             else:
01167                 dict = {}
01168         
01169         from pprint import PrettyPrinter
01170         pp = PrettyPrinter()
01171         if dict:
01172             result["GaudiTest.Histos.expected"] = result.Quote(pp.pformat(dict))        
01173             if ignore:
01174                 result["GaudiTest.Histos.ignore"] = result.Quote(ignore)
01175         
01176         histos = findHistosSummaries(stdout)
01177         failed = cmpTreesDicts(dict, histos, ignore)
01178         if failed:
01179             causes.append("histos summaries")
01180             msg = "%s: %s != %s" % getCmpFailingValues(dict, histos, failed)
01181             result["GaudiTest.Histos.failure_on"] = result.Quote(msg)
01182             result["GaudiTest.Histos.found"] = result.Quote(pp.pformat(histos))
01183         
01184         return causes
01185 
    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 1186 of file GaudiTest.py.

01186                                                                                    :
01187         """
01188         Default validation action: compare standard output and error to the
01189         reference files.
01190         """
01191         # set the default output preprocessor
01192         if preproc is None:
01193             preproc = normalizeExamples
01194         # check standard output
01195         reference = self._expandReferenceFileName(self.reference)
01196         # call the validator if the file exists
01197         if reference and os.path.isfile(reference):
01198             result["GaudiTest.output_reference"] = reference
01199             causes += ReferenceFileValidator(reference,
01200                                              "standard output",
01201                                              "GaudiTest.output_diff",
01202                                              preproc = preproc)(stdout, result)
01203         
01204         # Compare TTree summaries
01205         causes = self.CheckTTreesSummaries(stdout, result, causes)
01206         causes = self.CheckHistosSummaries(stdout, result, causes)
01207         
01208         if causes: # Write a new reference file for stdout
01209             newref = open(reference + ".new","w")
01210             # sanitize newlines
01211             for l in stdout.splitlines():
01212                 newref.write(l.rstrip() + '\n')
01213             del newref # flush and close
01214         
01215         
01216         # check standard error
01217         reference = self._expandReferenceFileName(self.error_reference)
01218         # call the validator if we have a file to use
01219         if reference and os.path.isfile(reference):
01220             result["GaudiTest.error_reference"] = reference
01221             newcauses = ReferenceFileValidator(reference,
01222                                                "standard error",
01223                                                "GaudiTest.error_diff",
01224                                                preproc = preproc)(stderr, result)
01225             causes += newcauses
01226             if newcauses: # Write a new reference file for stdedd
01227                 newref = open(reference + ".new","w")
01228                 # sanitize newlines
01229                 for l in stderr.splitlines():
01230                     newref.write(l.rstrip() + '\n')
01231                 del newref # flush and close    
01232         else:
01233             causes += BasicOutputValidator(self.stderr,
01234                                            "standard error",
01235                                            "ExecTest.expected_stderr")(stderr, result)
01236         
01237         return causes
01238         
    def ValidateOutput(self, stdout, stderr, result):

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

Definition at line 1239 of file GaudiTest.py.

01239                                                     :
01240         causes = []
01241         # if the test definition contains a custom validator, use it
01242         if self.validator.strip() != "":
01243             class CallWrapper(object):
01244                 """
01245                 Small wrapper class to dynamically bind some default arguments
01246                 to a callable.
01247                 """
01248                 def __init__(self, callable, extra_args = {}):
01249                     self.callable = callable
01250                     self.extra_args = extra_args
01251                     # get the list of names of positional arguments
01252                     from inspect import getargspec
01253                     self.args_order = getargspec(callable)[0]
01254                     # Remove "self" from the list of positional arguments
01255                     # since it is added automatically 
01256                     if self.args_order[0] == "self":
01257                         del self.args_order[0]
01258                 def __call__(self, *args, **kwargs):
01259                     # Check which positional arguments are used
01260                     positional = self.args_order[:len(args)]
01261                     
01262                     kwargs = dict(kwargs) # copy the arguments dictionary
01263                     for a in self.extra_args:
01264                         # use "extra_args" for the arguments not specified as
01265                         # positional or keyword
01266                         if a not in positional and a not in kwargs:
01267                             kwargs[a] = self.extra_args[a]
01268                     return apply(self.callable, args, kwargs)
01269             # local names to be exposed in the script 
01270             exported_symbols = {"self":self,
01271                                 "stdout":stdout,
01272                                 "stderr":stderr,
01273                                 "result":result,
01274                                 "causes":causes,
01275                                 "findReferenceBlock":
01276                                     CallWrapper(findReferenceBlock, {"stdout":stdout,
01277                                                                      "result":result,
01278                                                                      "causes":causes}),
01279                                 "validateWithReference":
01280                                     CallWrapper(self.ValidateWithReference, {"stdout":stdout,
01281                                                                              "stderr":stderr,
01282                                                                              "result":result,
01283                                                                              "causes":causes}),
01284                                 "countErrorLines":
01285                                     CallWrapper(countErrorLines, {"stdout":stdout,
01286                                                                   "result":result,
01287                                                                   "causes":causes}),
01288                                 "checkTTreesSummaries":
01289                                     CallWrapper(self.CheckTTreesSummaries, {"stdout":stdout,
01290                                                                             "result":result,
01291                                                                             "causes":causes}),
01292                                 "checkHistosSummaries":
01293                                     CallWrapper(self.CheckHistosSummaries, {"stdout":stdout,
01294                                                                             "result":result,
01295                                                                             "causes":causes}),
01296                                 
01297                                 }
01298             exec self.validator in globals(), exported_symbols
01299         else:
01300             self.ValidateWithReference(stdout, stderr, result, causes)
01301         
01302         return causes
01303     
    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 1304 of file GaudiTest.py.

01304                                      :
01305         """
01306         Add the content of the environment to the result object.
01307         
01308         Copied from the QMTest class of COOL.
01309         """
01310         vars = os.environ.keys()
01311         vars.sort()
01312         result['GaudiTest.environment'] = \
01313             result.Quote('\n'.join(["%s=%s"%(v,os.environ[v]) for v in vars]))
01314 
    def _find_program(self,prog):

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

Definition at line 1315 of file GaudiTest.py.

01315                                 :
01316         # check if it is an absolute path or the file can be found
01317         # from the local directory, otherwise search for it in PATH
01318         if not os.path.isabs(prog) and not os.path.isfile(prog):
01319             for d in os.environ["PATH"].split(os.pathsep):
01320                 p = os.path.join(d,prog)
01321                 if os.path.isfile(p):
01322                     return p
01323         return prog
01324         
    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 1325 of file GaudiTest.py.

01325                                   :
01326         """Run the test.
01327 
01328         'context' -- A 'Context' giving run-time parameters to the
01329         test.
01330 
01331         'result' -- A 'Result' object.  The outcome will be
01332         'Result.PASS' when this method is called.  The 'result' may be
01333         modified by this method to indicate outcomes other than
01334         'Result.PASS' or to add annotations."""
01335         
01336         # Check if the platform is supported
01337         if self.PlatformIsNotSupported(context, result):
01338             return
01339         
01340         def rationalizepath(p):
01341             p = os.path.normpath(os.path.expandvars(p))
01342             if os.path.exists(p):
01343                 p = os.path.realpath(p)
01344             return p
01345         
01346         # Prepare program name and arguments (expanding variables, and converting to absolute) 
01347         if self.program:
01348             prog = rationalizepath(self.program)
01349         elif "GAUDIEXE" in os.environ:
01350             prog = os.environ["GAUDIEXE"]
01351         else:
01352             prog = "Gaudi.exe"
01353         self.program = prog
01354             
01355         dummy, prog_ext = os.path.splitext(prog)
01356         if prog_ext not in [ ".exe", ".py", ".bat" ] and self.GetPlatform()[0:3] == "win":
01357             prog += ".exe"
01358             prog_ext = ".exe"
01359             
01360         prog = self._find_program(prog)
01361         
01362         # Convert paths to absolute paths in arguments and reference files
01363         args = map(rationalizepath, self.args)
01364         self.reference = rationalizepath(self.reference)
01365         self.error_reference = rationalizepath(self.error_reference)
01366         
01367         
01368         # check if the user provided inline options
01369         tmpfile = None
01370         if self.options.strip():
01371             ext = ".opts"
01372             if re.search(r"from\s*Gaudi.Configuration\s*import\s*\*", self.options):
01373                 ext = ".py"
01374             tmpfile = TempFile(ext)
01375             tmpfile.writelines("\n".join(self.options.splitlines()))
01376             tmpfile.flush()
01377             args.append(tmpfile.name)
01378             result["GaudiTest.options"] = result.Quote(self.options)
01379         
01380         # if the program is a python file, execute it through python
01381         if prog_ext == ".py":
01382             args.insert(0,prog)
01383             if self.GetPlatform()[0:3] == "win":
01384                 prog = self._find_program("python.exe")
01385             else:
01386                 prog = self._find_program("python")
01387         
01388         # Change to the working directory if specified or to the default temporary
01389         origdir = os.getcwd()
01390         if self.workdir:
01391             os.chdir(str(os.path.normpath(os.path.expandvars(self.workdir))))
01392         elif "qmtest.tmpdir" in context and self.use_temp_dir == "true":
01393             os.chdir(context["qmtest.tmpdir"])
01394         
01395         if "QMTEST_IGNORE_TIMEOUT" not in os.environ:
01396             self.timeout = max(self.timeout,600)
01397         else:
01398             self.timeout = -1
01399         
01400         try:
01401             # Run the test
01402             self.RunProgram(prog, 
01403                             [ prog ] + args,
01404                             context, result)
01405             # Record the content of the enfironment for failing tests 
01406             if result.GetOutcome() not in [ result.PASS ]:
01407                 self.DumpEnvironment(result)
01408         finally:
01409             # revert to the original directory
01410             os.chdir(origdir)
01411         
    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 1412 of file GaudiTest.py.

01412                                                              :
01413         """Run the 'program'.
01414 
01415         'program' -- The path to the program to run.
01416 
01417         'arguments' -- A list of the arguments to the program.  This
01418         list must contain a first argument corresponding to 'argv[0]'.
01419 
01420         'context' -- A 'Context' giving run-time parameters to the
01421         test.
01422 
01423         'result' -- A 'Result' object.  The outcome will be
01424         'Result.PASS' when this method is called.  The 'result' may be
01425         modified by this method to indicate outcomes other than
01426         'Result.PASS' or to add annotations.
01427         
01428         @attention: This method has been copied from command.ExecTestBase
01429                     (QMTest 2.3.0) and modified to keep stdout and stderr
01430                     for tests that have been terminated by a signal.
01431                     (Fundamental for debugging in the Application Area)
01432         """
01433 
01434         # Construct the environment.
01435         environment = self.MakeEnvironment(context)
01436         # Create the executable.
01437         if self.timeout >= 0:
01438             timeout = self.timeout
01439         else:
01440             # If no timeout was specified, we sill run this process in a
01441             # separate process group and kill the entire process group
01442             # when the child is done executing.  That means that
01443             # orphaned child processes created by the test will be
01444             # cleaned up.
01445             timeout = -2
01446         e = GaudiFilterExecutable(self.stdin, timeout)
01447         # Run it.
01448         exit_status = e.Run(arguments, environment, path = program)
01449         # Get the stack trace from the temporary file (if present)
01450         if e.stack_trace_file and os.path.exists(e.stack_trace_file):
01451             stack_trace = open(e.stack_trace_file).read()
01452             os.remove(e.stack_trace_file)
01453         else:
01454             stack_trace = None
01455         if stack_trace:
01456             result["ExecTest.stack_trace"] = result.Quote(stack_trace)
01457 
01458         # If the process terminated normally, check the outputs.
01459         if sys.platform == "win32" or os.WIFEXITED(exit_status):
01460             # There are no causes of failure yet.
01461             causes = []
01462             # The target program terminated normally.  Extract the
01463             # exit code, if this test checks it.
01464             if self.exit_code is None:
01465                 exit_code = None
01466             elif sys.platform == "win32":
01467                 exit_code = exit_status
01468             else:
01469                 exit_code = os.WEXITSTATUS(exit_status)
01470             # Get the output generated by the program.
01471             stdout = e.stdout
01472             stderr = e.stderr
01473             # Record the results.
01474             result["ExecTest.exit_code"] = str(exit_code)
01475             result["ExecTest.stdout"] = result.Quote(stdout)
01476             result["ExecTest.stderr"] = result.Quote(stderr)
01477             # Check to see if the exit code matches.
01478             if exit_code != self.exit_code:
01479                 causes.append("exit_code")
01480                 result["ExecTest.expected_exit_code"] \
01481                     = str(self.exit_code)
01482             # Validate the output.
01483             causes += self.ValidateOutput(stdout, stderr, result)
01484             # If anything went wrong, the test failed.
01485             if causes:
01486                 result.Fail("Unexpected %s." % string.join(causes, ", ")) 
01487         elif os.WIFSIGNALED(exit_status):
01488             # The target program terminated with a signal.  Construe
01489             # that as a test failure.
01490             signal_number = str(os.WTERMSIG(exit_status))
01491             result.Fail("Program terminated by signal.")
01492             result["ExecTest.signal_number"] = signal_number
01493             result["ExecTest.stdout"] = result.Quote(e.stdout)
01494             result["ExecTest.stderr"] = result.Quote(e.stderr)
01495         elif os.WIFSTOPPED(exit_status):
01496             # The target program was stopped.  Construe that as a
01497             # test failure.
01498             signal_number = str(os.WSTOPSIG(exit_status))
01499             result.Fail("Program stopped by signal.")
01500             result["ExecTest.signal_number"] = signal_number
01501             result["ExecTest.stdout"] = result.Quote(e.stdout)
01502             result["ExecTest.stderr"] = result.Quote(e.stderr)
01503         else:
01504             # The target program terminated abnormally in some other
01505             # manner.  (This shouldn't normally happen...)
01506             result.Fail("Program did not terminate normally.")
01507         
01508         # Marco Cl.: This is a special trick to fix a "problem" with the output
01509         # of gaudi jobs when they use colors
01510         esc = '\x1b'
01511         repr_esc = '\\x1b'
01512         result["ExecTest.stdout"] = result["ExecTest.stdout"].replace(esc,repr_esc)
01513         # TODO: (MCl) improve the hack for colors in standard output
01514         #             may be converting them to HTML tags
        #             may be converting them to HTML tags


Member Data Documentation

Definition at line 952 of file GaudiTest.py.

Definition at line 1249 of file GaudiTest.py.

Definition at line 1250 of file GaudiTest.py.

Definition at line 1253 of file GaudiTest.py.

Definition at line 1353 of file GaudiTest.py.

Definition at line 1364 of file GaudiTest.py.

Definition at line 1365 of file GaudiTest.py.

Definition at line 1392 of file GaudiTest.py.

Definition at line 1396 of file GaudiTest.py.


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

Generated at Mon Sep 7 18:26:48 2009 for Gaudi Framework, version v21r4 by Doxygen version 1.5.6 written by Dimitri van Heesch, © 1997-2004