diff options
author | Ralph Giles <ralph.giles@artifex.com> | 2007-03-16 22:22:43 +0000 |
---|---|---|
committer | Ralph Giles <ralph.giles@artifex.com> | 2007-03-16 22:22:43 +0000 |
commit | 7a125fde13b8515cdb81769ac00983a3a946c0fe (patch) | |
tree | 9e6668a7e6877a31bcdab940b6b2216c2905d05d /tools | |
parent | 073a95be38158f46827bac22b4e853b3e35e7eb3 (diff) |
Add command line option parsing to the regression script. It's a bit
hacky, but currently we support the following options:
--batch
Don't print interactive status as the job runs.
--update
Update the baselines for changed files, so a second run
with the same executable should be clean.
--exe
Executable to run the regression test on.
--testpath <path>
Path to search for the test files.
* Currently only one directory is supported *
defaults to ~/tests/
--test <pattern>
Wildcard string for the test files to check,
assuming the testpath is prefixed. This option
can occur multiple times. Defaults to something
general based on the value of --exe
This will be smarter in the future, so at some point
--test ps3cet will be equivalent to the current
--test ps/ps3cet/\*.ps
Also, general comment cleanup, and dispatch the jobs from the front
instead of the back of the list.
git-svn-id: http://svn.ghostscript.com/ghostpcl/trunk/ghostpcl@2803 06663e23-700e-0410-b217-a244a6096597
Diffstat (limited to 'tools')
-rw-r--r-- | tools/regress.py | 146 |
1 files changed, 115 insertions, 31 deletions
diff --git a/tools/regress.py b/tools/regress.py index e56e36de3..fb68cff8e 100644 --- a/tools/regress.py +++ b/tools/regress.py @@ -8,18 +8,86 @@ try: from mpi4py import MPI except ImportError: class DummyMPI: - 'a dummy MPI class for conditionals in a serial job' + '''A dummy MPI class for running serial jobs.''' size = 1 rank = 0 MPI = DummyMPI() class Conf: - 'class for holding various configuration parameters' - # output format, set to False for interactive - batch = False - # should we update the md5sum database to new values? - update = True + def __init__(self): + # set defaults + self.batch = False + self.update = False + self.verbose = False + self.testpath = os.path.join(os.environ['HOME'], 'tests') + #self.exe = './language_switch/obj/pspcl6' + self.exe = './bin/gs -q -I$HOME/fonts' + self.test = 'comparefiles' + + def parse(self, args): + '''Parse the command line for configuration switches + + For example: + conf = Conf() + conf.parse(sys.argv) + ''' + + for index in xrange(1,len(args)): + arg = args[index] + if arg[:2] == '--': + + # support generic '--opt=val' + sep = arg.find('=') + if sep > 0: + opt = arg[2:sep] + val = arg[sep+1:] + else: + opt = arg[2:] + + # for select options support '--opt val' + if opt in ('exe', 'test'): + try: + val = args[index+1] + except IndexError: + print 'Warning:', opt, 'requires a specific value.' + val = None + else: + # default to postitive boolean value + val = True + + if MPI.rank == 0: + print 'got option', opt, ' = ', val + + # for select options, accumulate the values + if opt in ('test'): + opt += 's' # pluralize collections + if not hasattr(self, opt): + self.__dict__[opt] = [] + self.__dict__[opt].append(val) + else: + # set an attribute on ourselves with the option value + self.__dict__[opt] = val + + # finally, set defaults for unset accumulating options + if not hasattr(self, 'tests'): + self.tests = [] + # guess appropriate defaults based on the executable + basename = os.path.basename(self.exe.split()[0]) + if basename.find('pcl') >= 0: + self.tests += ['pcl/pcl5cfts/fts.*', + 'pcl/pcl5efts/fts.*', + 'pcl/pcl5ccet/*.BIN'] + if basename.find('ps') >= 0 or basename.find('gs') >= 0: + self.tests += ['ps/ps3cet/*.PS'] + # run the normal comparefiles suite for now + self.tests = ['comparefiles/*.ps', + 'comparefiles/*.pdf', + 'comparfiles/*.ai'] + +# global configuration instance conf = Conf() +conf.parse(sys.argv) + # results of tests are stored as classes @@ -62,7 +130,8 @@ class SelfTest: self.result = OKResult() class SelfTestSuite: - 'generic class for running a collection of SelfTest instances' + '''Generic class for running a collection of SelfTest instances.''' + def __init__(self, stream=sys.stderr): self.stream = stream self.tests = [] @@ -70,8 +139,10 @@ class SelfTestSuite: self.errors = [] self.news = [] self.elapsed = 0.0 + def addTest(self, test): self.tests.append(test) + def addResult(self, test): if test: if not conf.batch: @@ -84,8 +155,9 @@ class SelfTestSuite: elif not isinstance(test.result, OKResult): # treat everything else as a failure self.fails.append(test) + def run(self): - 'run each test in sequence' + '''Run each test in sequence.''' starttime = time.time() tests = self.tests self.tests = [] @@ -94,6 +166,7 @@ class SelfTestSuite: self.addResult(test) self.elapsed = time.time() - starttime self.report() + def report(self): if not conf.batch: print '-'*72 @@ -114,20 +187,17 @@ class SelfTestSuite: print ' ' + test.description() print test.result.msg print - if not self.fails and not self.errors: + if not self.fails and not self.errors and not self.news: print 'PASSED all %d tests' % len(self.tests) if self.news: print '%d NEW files with no previous result' % len(self.news) print class MPITestSuite(SelfTestSuite): + '''Use MPI to run multiple tests in parallel.''' + def run(self): - '''use MPI to dispatch tests to worker nodes - each of which will run the run the actual tests - and return the result''' starttime = time.time() - # broadcast the accumulated tests to all nodes - self = MPI.COMM_WORLD.Bcast(self, 0) if MPI.rank > 0: # daughter nodes run requested tests test = None @@ -145,7 +215,7 @@ class MPITestSuite(SelfTestSuite): status = MPI.Status() test = MPI.COMM_WORLD.Recv(source=MPI.ANY_SOURCE, status=status) self.addResult(test) - MPI.COMM_WORLD.Send(tests.pop(), dest=status.source) + MPI.COMM_WORLD.Send(tests.pop(0), dest=status.source) # retrieve outstanding results and tell the nodes we're finished for node in xrange(1, MPI.size): test = MPI.COMM_WORLD.Recv(source=MPI.ANY_SOURCE) @@ -156,26 +226,34 @@ class MPITestSuite(SelfTestSuite): if MPI.rank == 0: self.report() +# specific code for our needs + class md5Test(SelfTest): - '''test class for running a file and comparing the output to an + '''Test class for running a file and comparing the output to an expected value.''' + def __init__(self, file, md5sum, dpi=300): SelfTest.__init__(self) self.file = file self.md5sum = md5sum self.dpi = dpi - self.exe = './language_switch/obj/pspcl6' - #self.exe = './bin/gs -q -I../fonts' - self.opts = "-dNOPAUSE -sDEVICE=ppmraw -r%d" % dpi + self.exe = conf.exe + self.opts = "-dQUIET -dNOPAUSE -dBATCH -K1000000" + self.opts += " -sDEVICE=ppmraw -r%d" % dpi self.opts += " -dSAFER -dBATCH" - self.psopts = '-dMaxBitmap=40000000 -dJOBSERVER ./lib/gs_cet.ps' + #self.psopts = '-dMaxBitmap=40000000 -dJOBSERVER ./lib/gs_cet.ps' + self.psopts = '-dMaxBitmap=30000000 -dNOOUTERSAVE -dJOBSERVER -c false 0 startjob pop -f' + def description(self): return 'Checking ' + self.file + def run(self): scratch = os.path.join('/tmp', os.path.basename(self.file) + '.md5') # add psopts if it's a postscript file if self.file[-3:].lower() == '.ps' or \ - self.file[-4:].lower() == '.eps': + self.file[-4:].lower() == '.eps' or \ + self.file[-4:].lower() == '.pdf' or \ + self.file[-3:].lower() == '.ai': cmd = '%s %s -sOutputFile="|md5sum>%s" %s - < %s ' % \ (self.exe, self.opts, scratch, self.psopts, self.file) else: @@ -205,9 +283,11 @@ class md5Test(SelfTest): class DB: '''class representing an md5 sum database''' + def __init__(self): self.store = None self.db = {} + def load(self, store='reg_baseline.txt'): self.store = store try: @@ -225,6 +305,7 @@ class DB: except IndexError: pass f.close() + def save(self, store=None): if not store: store = self.store @@ -233,15 +314,19 @@ class DB: for key in self.db.keys(): f.write(str(key) + ' ' + str(self.db[key]) + '\n') f.close() + + # provide a dictionary interface def __getitem__(self, key): try: value = self.db[key] except KeyError: value = None return value + def __setitem__(self, key, value): self.db[key] = value + def run_regression(): 'run normal set of regressions' from glob import glob @@ -252,29 +337,25 @@ def run_regression(): if MPI.rank == 0: db = DB() db.load() - testdir = '../tests/' - tests = ['pcl/pcl5cfts/fts.*', - 'pcl/pcl5efts/fts.*', - 'pcl/pcl5ccet/*.BIN', - 'ps/ps3cet/*.PS'] - pstests = ['ps/ps3fts/*.ps','ps/ps3cet/*.PS'] - for test in tests: - for file in glob(testdir + test): + for test in conf.tests: + for file in glob(os.path.join(conf.testpath,test)): suite.addTest(md5Test(file, db[file])) if MPI.size > 1: - print('running tests on %d nodes...' % MPI.size) + print 'running tests on %d nodes...' % MPI.size suite.run() if MPI.rank == 0: # update the database with new files and save for test in suite.news: db[test.file] = test.result.msg if conf.update: + if len(suite.fails): + print 'Updating baselines for the failed tests.' for test in suite.fails: db[test.file] = test.result.msg db.save() -# self test self tests +# self test routines for the self test classes class RandomTest(SelfTest): 'test class with random results for testing' @@ -306,6 +387,9 @@ def test_ourselves(): suite.addTest(RandomTest()) suite.run() + +# Do someting useful when executed directly + if __name__ == '__main__': #test_ourselves() run_regression() |