casa  $Rev:20696$
 All Classes Namespaces Files Functions Variables
testwrapper.py
Go to the documentation of this file.
00001 """ Class to wrap a test to use with unittest framework."""
00002 
00003 import os
00004 import commands
00005 import sys
00006 import shutil
00007 import inspect
00008 import re
00009 import string
00010 import traceback
00011 import casac
00012 import unittest
00013 
00014 PYVER = str(sys.version_info[0]) + "." + str(sys.version_info[1])
00015 
00016 AIPS_DIR = os.environ["CASAPATH"].split()[0]
00017 DATA_DIR = AIPS_DIR+'/data'
00018 
00019 SCRIPT_REPOS=AIPS_DIR + "/" + os.environ["CASAPATH"].split()[1] + '/python/' + PYVER + '/tests/'
00020 
00021 if not os.access(SCRIPT_REPOS, os.F_OK):
00022     if os.access(AIPS_DIR+'/lib64', os.F_OK):
00023         SCRIPT_REPOS = AIPS_DIR+'/lib64/python' + PYVER + '/tests/'
00024     elif os.access(AIPS_DIR+'/lib', os.F_OK):
00025         SCRIPT_REPOS = AIPS_DIR+'/lib/python' + PYVER + '/tests/'
00026     else:            #Mac release
00027         SCRIPT_REPOS = AIPS_DIR+'/Resources/python/tests/'
00028 
00029 class Helper():
00030     # This class is called when a test is not found. It will
00031     # raise an exception and make nose fail. This way, the not
00032     # found test will be counted as an error and won't be ignored.
00033     def __init__(self, name):
00034         self.tname = name
00035     
00036     def test_dummy(self):
00037         '''Helper function'''
00038         raise Exception, "Cannot find test %s"%self.tname
00039 
00040 class UnitTest:
00041     def __init__(self,testname=''):
00042         """Take the name of a test file (without .py), wrap it and run"""
00043         self.testname = testname
00044         self.workdir = testname+'_work'
00045         self.scriptdir = SCRIPT_REPOS       
00046         self.datadir = [DATA_DIR]
00047         self.dataFiles = []
00048     
00049     def funcdesc(self):
00050         '''Name of test for FunctionTestCase'''
00051         return 'Test '+self.testname
00052     
00053     def funcSetup(self):        
00054         """Copy data files to local working directory"""
00055         
00056         dataFiles = self.dataFiles
00057         print 'Searching for input data in %s'%(self.datadir)
00058         for datafile in dataFiles: 
00059             file = self.locatedata(datafile, self.datadir)
00060             #if data already exist, remove them
00061             if(file != ''):
00062                 os.system('rm -rf '+ self.workdir+'/'+datafile)
00063             if(os.path.isdir(file)):
00064                 shutil.copytree(file, self.workdir+'/'+datafile)
00065             if(os.path.isfile(file)):
00066                 shutil.copy(file, self.workdir+'/'+datafile)
00067         
00068     def funcTeardown(self):
00069         """Remove data files from working directory"""
00070         
00071         dataFiles = self.dataFiles
00072         for datafile in dataFiles:
00073             file = self.workdir+'/'+datafile
00074             os.system('rm -rf ' + file)
00075         
00076         self.dataFiles = []
00077 
00078     def getFuncTest(self):
00079         print '-------------- Unit Test for %s ---------------'%self.testname
00080         """Wrap a script using unittest"""
00081         testscript = self.searchscript(self.testname, self.scriptdir)
00082         
00083         # avoid creating a _work directory
00084         if (testscript == ""):
00085             return
00086 
00087         # copy test to local directory
00088         self.workdir = os.getcwd()
00089         self.getTest(testscript, self.testname,self.scriptdir, self.workdir)
00090 
00091         # import the test
00092         mytest = __import__(self.testname)
00093         reload(mytest)
00094 
00095         #get the data
00096         try:
00097             self.dataFiles = mytest.data()
00098         except:
00099             print 'No data needed or found'
00100               
00101         # Wrap the test, funcSetup and funcTeardown in a FunctionTestCase and return it
00102         testcase = (unittest.FunctionTestCase(mytest.run,setUp=self.funcSetup,
00103                                               tearDown=self.funcTeardown,
00104                                               description=self.funcdesc()))
00105         
00106         return testcase
00107 
00108 
00109     def getUnitTest(self,list=[]):
00110         """Set up a unit test script to run wit nose"""    
00111         print '-------------- Unit Test for %s ---------------'%self.testname
00112         if list:
00113             print 'List of specific tests %s'%(list)
00114             
00115         # search for script in repository
00116         testscript = self.searchscript(self.testname, self.scriptdir)
00117 
00118         if (testscript == ""):
00119             testlist = []
00120             # Create a dummy list and return it so that nose
00121             # includes this test in the list of erroneous tests
00122             # instead of ignoring it.
00123             t = unittest.FunctionTestCase(Helper(self.testname).test_dummy)
00124             return [t]
00125 
00126         # copy test to local directory
00127         self.workdir = os.getcwd()
00128         self.getTest(testscript, self.testname,self.scriptdir, self.workdir)
00129 
00130         # import the test
00131         mytest = __import__(self.testname)
00132         reload(mytest)
00133         
00134         # get the classes
00135         classes = mytest.suite()
00136         testlist = []
00137         
00138         # Check if specific tests/classes were requested
00139         if not list:
00140 #            print "no list"
00141             for c in classes:
00142                 for attr, value in c.__dict__.iteritems():                
00143 #                    print attr, " = ", value
00144                     if len(attr) >= len("test") and \
00145                         attr[:len("test")] == "test" : \
00146                         testlist.append(c(attr))
00147                         
00148         else:
00149             # verify if list contains classes and/or methods
00150             for input in list:
00151                 for c in classes:
00152 #                    print c
00153                     if self.isaclass(c,input):
00154 #                        print "it is a class"
00155                         # It is a class. Get all its methods
00156                         for attr, value in c.__dict__.iteritems():
00157                             if len(attr) >= len("test") and \
00158                                 attr[:len("test")] == "test" : \
00159                                 # append each test method to the list    
00160                                 testlist.append(c(attr))
00161                     else:
00162                         # maybe it is a method. Get only this one
00163 #                        print "maybe it is a method"
00164                         for attr, value in c.__dict__.iteritems():
00165                             if input == attr:
00166                                 testlist.append(c(attr))
00167                                                                                         
00168 #            for attr, value in c.__dict__.iteritems():
00169 #                print attr, value
00170 #                if list:
00171 #                    print 'There is a list'
00172 #                    for test in list:
00173 #                        print test
00174 #                        if test == attr:
00175 #                            testlist.append(c(attr))
00176 #                else:
00177 #                    print attr, " = ", value
00178 #                   if len(attr) >= len("test") and \
00179 #                        attr[:len("test")] == "test" : \
00180 ##                        attr.rfind('test') != -1 :
00181 #                        testlist.append(c(attr))
00182 #        print testlist
00183         return testlist
00184             
00185 
00186     def cleanup(self,workdir):
00187         # for safety, avoid removing the local directory
00188         if (workdir == '.'):
00189             workdir = '/tmp/utests'
00190         
00191         if os.path.isdir(workdir):
00192             print 'Cleaning up '+ workdir
00193             shutil.rmtree(workdir)
00194 
00195 
00196     def createDir(self, workdir):
00197         """Create a working directory"""
00198         if os.access(workdir, os.F_OK) is False:
00199             print workdir+' does not exist, creating it'
00200             os.makedirs(workdir)
00201 
00202 
00203     def locatedata(self, datafile, datadir):
00204         
00205         for repository in datadir :
00206 
00207             #Skip hidden directories
00208             filter_hidden = ' | grep -vE "^\\."  | grep -vE "/\\."'
00209             
00210             #See if find understands -L or -follow (depends on find version)
00211             (err, a) = commands.getstatusoutput('find -L ' + repository+'/ 1>/dev/null 2>&1')
00212             if not err:
00213                 findstr='find -L '+repository+'/ -name '+datafile+' -print 2>/dev/null' + filter_hidden
00214             else:
00215                 findstr='find '+repository+'/ -follow -name '+datafile+' -print 2>/dev/null' + filter_hidden
00216             # A '/' is appended to the directory name; otherwise sometimes find doesn't find.
00217             #Also, ignore error messages such as missing directory permissions
00218             
00219             (find_errorcode, a)=commands.getstatusoutput(findstr)   # stdout and stderr
00220             #if find_errorcode != 0:
00221             #    print >> sys.stderr, "%s failed: %s" % (findstr, a)
00222             retval=''
00223             b=['']
00224             if(a!=''):
00225                 b=string.split(a, '\n')
00226                 retval=b[len(b)-1]
00227                 if(len(b) > 1):
00228                     print 'More than 1 file found with name '+datafile
00229                 print 'Will use', retval
00230                 return retval
00231         raise Exception, 'Could not find datafile %s in the repository directories %s' \
00232               % (datafile, datadir)
00233  
00234 
00235     def searchscript(self, testname, scriptdir):
00236         """Search for the script"""
00237         print "Searching for script %s in %s" %(testname,scriptdir)                  
00238 #        TestName=string.lower(testname)
00239         TestName = testname
00240 
00241         theScript=''
00242         numOfScript=0
00243 
00244         # search for DIR/<name>.py
00245         if os.path.isdir(scriptdir):
00246             allScripts=os.listdir(scriptdir)
00247         else:
00248             allScripts=[]
00249 #        print "allScripts = ", allScripts
00250         for scr in allScripts:
00251 #            print scriptdir, scr, testname
00252             if (scr == TestName + '.py'):
00253                 theScript = scr
00254                 numOfScript += 1  
00255                       
00256         if numOfScript == 0:
00257 #            raise Exception, 'Could not find test %s' %TestName 
00258             print 'ERROR: Could not find test %s' %TestName
00259             return ""  
00260             
00261         if( numOfScript > 1) :
00262             print 'More than 1 scripts found for name '+TestName
00263             print 'Using the following one '+ theScript
00264             
00265         print "Found", theScript
00266         return theScript
00267 
00268     def getTest(self, testnamek, testName, scriptdir, workdir):
00269         print 'Copy the script to the working dir'
00270         if testnamek[0:6] == 'tests/':
00271             shutil.copy(scriptdir+'/'+testnamek,
00272                         workdir+'/'+testName+'.py')
00273         else:    
00274             shutil.copy(scriptdir+'/'+testnamek, \
00275                     workdir+'/')
00276 
00277     def isaclass(self,myclass,input):
00278         '''Check if input equals the class name'''
00279 #        print "input=%s myclass=%s"%(input,myclass.__name__)
00280         if input == myclass.__name__:
00281             return True
00282             
00283         return False
00284 
00285 
00286 class ExecTest(unittest.TestCase,UnitTest):
00287     """Wraps scripts to run with execfile"""
00288     
00289     def setup(self):
00290         self.workdir = self.testname+'_work'
00291         self.scriptdir = SCRIPT_REPOS       
00292         
00293         self.testscript = self.searchscript(self.testname,self.scriptdir)
00294         # avoid creating a _work directory
00295         if (self.testscript == ""):
00296             return
00297         
00298         # create a working directory
00299         self.cleanup(self.workdir)
00300         self.createDir(self.workdir)
00301         
00302         # copy test to workdir
00303         self.getTest(self.testscript, self.testname, self.scriptdir, self.workdir)
00304         thisDir = os.getcwd()
00305         os.chdir(self.workdir)    
00306            
00307     def testrun(self):
00308         #self.testname is defined in the calling function
00309         # run self.setup before calling this function
00310         """Run test with execfile"""
00311         
00312         # run the test
00313         a=inspect.stack()
00314         stacklevel=0
00315         for k in range(len(a)):
00316             if (string.find(a[k][1], 'ipython console') > 0):
00317                 stacklevel=k
00318                 break
00319         gl=sys._getframe(stacklevel).f_globals
00320         
00321         execfile(self.testscript, gl)   
00322         
00323