[GRASS-SVN] r61125 - sandbox/wenzeslaus/gunittest
svn_grass at osgeo.org
svn_grass at osgeo.org
Wed Jul 2 13:21:06 PDT 2014
Author: wenzeslaus
Date: 2014-07-02 13:21:05 -0700 (Wed, 02 Jul 2014)
New Revision: 61125
Modified:
sandbox/wenzeslaus/gunittest/case.py
sandbox/wenzeslaus/gunittest/main.py
Log:
gunittest: invoking function converted to class
Modified: sandbox/wenzeslaus/gunittest/case.py
===================================================================
--- sandbox/wenzeslaus/gunittest/case.py 2014-07-02 19:02:12 UTC (rev 61124)
+++ sandbox/wenzeslaus/gunittest/case.py 2014-07-02 20:21:05 UTC (rev 61125)
@@ -40,7 +40,8 @@
"""Use temporary region instead of the standard one for this process.
If you use this method, you have to call it in `setUp()` and call
- `del_temp_region()` in `tearDown()`.
+ `del_temp_region()` in `tearDown()`. By this you ensure that each test
+ method will have its own region and will not influece others.
Copies the current region to a temporary region with
"g.region save=", then sets WIND_OVERRIDE to refer to that region.
@@ -93,6 +94,7 @@
# (note that we don't need precision for strings and usually for integers)
# TODO: auto-determine precision based on the map type
# TODO: we can have also more general function without the subset reference
+ # TODO: implement this also for PyGRASS Module
def assertCommandKeyValue(self, module, parameters, reference, sep,
precision=None, msg=None):
if isinstance(reference, basestring):
Modified: sandbox/wenzeslaus/gunittest/main.py
===================================================================
--- sandbox/wenzeslaus/gunittest/main.py 2014-07-02 19:02:12 UTC (rev 61124)
+++ sandbox/wenzeslaus/gunittest/main.py 2014-07-02 20:21:05 UTC (rev 61125)
@@ -3,6 +3,9 @@
import os
import sys
import shutil
+import errno
+import string
+import subprocess
from unittest.main import TestProgram, USAGE_AS_MAIN
TestProgram.USAGE = USAGE_AS_MAIN
@@ -46,7 +49,7 @@
buffer=buffer_stdout_stderr)
-def main():
+def test():
"""Run a test of a module.
"""
import coverage
@@ -61,7 +64,8 @@
sys.exit(not program.result.wasSuccessful())
-test = main
+# TODO: test or main? test looks more general
+main = test
def discovery():
@@ -84,97 +88,151 @@
sys.exit(not program.result.wasSuccessful())
+# TODO: move these to utils or even somewhere more general
def ensure_dir(directory):
+ """Create all directories in the given path if needed."""
if not os.path.exists(directory):
os.makedirs(directory)
-def recursive_runs():
- grass_location = 'nc'
- # here should never be the same as start_dir, it leads to confusing (and dangerous) dir tree
- results_root = 'testresults'
- import subprocess
- modules = discover_modules(start_dir='.',
- file_pattern=GrassTestLoader.files_in_testsuite,
- skip_dirs=GrassTestLoader.skip_dirs,
- testsuite_dir=GrassTestLoader.testsuite_dir,
- grass_location=grass_location,
- all_locations_value=GrassTestLoader.all_tests_value,
- universal_location_value=GrassTestLoader.universal_tests_value,
- import_modules=False)
- ensure_dir(os.path.abspath(results_root))
- main_index = open(os.path.join(results_root, 'index.html'), 'w')
- main_index.write('<html><body>'
- '<ul>')
- for module in modules:
- cwd = os.path.join(results_root, module.tested_dir, module.name)
- ensure_dir(os.path.abspath(cwd))
+def silent_rmtree(filename):
+ """Remove the file but do nothing if file does not exist."""
+ try:
+ os.remove(filename)
+ except OSError as e:
+ # errno.ENOENT is "No such file or directory"
+ # re-raise if a different error occured
+ if e.errno != errno.ENOENT:
+ raise
- env = os.environ.copy()
- # using path.sep but also / and \ for cases when it is confused
- # (namely the case of Unix path on MS Windows)
- # replace . to get rid of unclean path
- # TODO: clean paths
- dir_as_name = module.tested_dir.replace('.', '_').replace('/', '_').replace('\\', '_').replace(os.path.sep, '_')
- mapset = dir_as_name + '_' + module.name
- location = 'nc_spm_08_grass7_tests'
- gisdbase = gcore.gisenv()['GISDBASE']
- assert gisdbase
- gisrc = gsetup.write_gisrc(gisdbase, location, mapset)
- env['GISRC'] = gisrc
- # TODO: use grass module to do this?
- mapset_dir = os.path.join(gisdbase, location, mapset)
- # TODO: perhaps remove dir if exists
- os.mkdir(mapset_dir)
- # TODO: default region in mapset will be what?
- # copy WIND file from PERMANENT
- # TODO: this should be a function in grass.script (used also in gis_set.py, PyGRASS alos has its way with Mapset)
- # TODO: are premisions an issue here?
- shutil.copy(os.path.join(gisdbase, location, 'PERMANENT', 'WIND'),
- os.path.join(mapset_dir))
- # TODO: we don't do any HTML escaping, use txt file
- stdout = open(os.path.join(cwd, 'stdout.html'), 'w')
- stderr = open(os.path.join(cwd, 'stderr.html'), 'w')
- stdout.write('<html><body><h1>%s</h1><pre>' % (module.name + ' stdout'))
- stderr.write('<html><body><h1>%s</h1><pre>' % (module.name + ' stderr'))
- stdout.flush() # we need to flush to write our changes before stdout
- stderr.flush()
+class GrassTestFilesInvoker(object):
- # TODO: we might clean the directory here before test if non-empty
- p = subprocess.Popen([sys.executable, module.abs_file_path],
- cwd=cwd, env=env,
- stdout=stdout, stderr=stderr)
- returncode = p.wait()
- stdout.flush()
- stderr.flush()
- stdout.write('</pre></body></html>')
- stderr.write('</pre></body></html>')
- file_index_path = os.path.join(cwd, 'index.html')
- if returncode:
- sys.stderr.write('{d}/{m} failed (see {f})\n'.format(d=module.tested_dir,
- m=module.name,
- f=file_index_path))
- main_index.write('<li><a href="{d}/{m}/index.html">{d}/{m}</a>'.format(d=module.tested_dir, m=module.name))
- file_index = open(file_index_path, 'w')
- file_index.write('<html><body>'
- '<ul>'
- '<li><a href="stdout.html">standard output (stdout)</a>'
- '<li><a href="stderr.html">standard error output (stderr)</a>'
- '<li><a href="testcodecoverage/index.html">code coverage</a>'
- '</ul>'
+ # TODO: it is not clear what clean_outputs mean, if should be split
+ # std stream, random outputs, saved results, profiling
+ # not stdout and stderr if they contain test results
+ # we can also save only failed tests, or generate only if assert fails
+ def __init__(self, start_dir,
+ clean_mapsets=True, clean_outputs=True, clean_before=True,
+ testsuite_dir='testsuite'):
+ """
+
+ :param bool clean_mapsets: if the mapsets should be removed
+ :param bool clean_outputs: unclear: random tests outputs, saved images from maps, profiling
+ :param bool clean_before: if mapsets, outputs, and results
+ should be removed before the tests start
+ (advantageous when the previous run left everything behind)
+ """
+ self.start_dir = start_dir
+ self.clean_mapsets = clean_mapsets
+ self.clean_outputs = clean_outputs
+ self.clean_before = clean_before
+ self.testsuite_dir = testsuite_dir
+
+ def run_in_location(self, gisdbase, location, location_shortcut,
+ results_dir):
+ if os.path.abspath(results_dir) == os.path.abspath(self.start_dir):
+ raise RuntimeError("Results root directory should not be the same"
+ " as discovery start directory")
+
+ import datetime
+ main_start_time = datetime.datetime.now()
+
+ # TODO: move constants out of loader class or even module
+ modules = discover_modules(start_dir=self.start_dir,
+ grass_location=location_shortcut,
+ file_pattern=GrassTestLoader.files_in_testsuite,
+ skip_dirs=GrassTestLoader.skip_dirs,
+ testsuite_dir=GrassTestLoader.testsuite_dir,
+ all_locations_value=GrassTestLoader.all_tests_value,
+ universal_location_value=GrassTestLoader.universal_tests_value,
+ import_modules=False)
+ # TODO: no directory cleaning (self.clean_before)? now cleaned by caller
+ ensure_dir(os.path.abspath(results_dir))
+ main_index = open(os.path.join(results_dir, 'index.html'), 'w')
+ main_index.write('<html><body>'
+ '<h1>Test results</h1>'
+ '{time:%Y-%m-%d %H:%M:%S}'
+ '<ul>'.format(time=main_start_time))
+ for module in modules:
+ cwd = os.path.join(results_dir, module.tested_dir, module.name)
+ ensure_dir(os.path.abspath(cwd))
+ # TODO: put this to constructor and copy here again
+ env = os.environ.copy()
+ # using path.sep but also / and \ for cases when it is confused
+ # (namely the case of Unix path on MS Windows)
+ # replace . to get rid of unclean path
+ # TODO: clean paths
+ dir_as_name = module.tested_dir.translate(string.maketrans('./\\', '___'))
+ #dir_as_name = module.tested_dir.replace('.', '_').replace('/', '_').replace('\\', '_').replace(os.path.sep, '_')
+ mapset = dir_as_name + '_' + module.name
+ location = location
+ gisrc = gsetup.write_gisrc(gisdbase, location, mapset)
+ env['GISRC'] = gisrc
+ # TODO: use grass module to do this?
+ mapset_dir = os.path.join(gisdbase, location, mapset)
+ # TODO: perhaps remove dir if exists
+ if self.clean_before:
+ silent_rmtree(mapset_dir)
+ os.mkdir(mapset_dir)
+ # TODO: default region in mapset will be what?
+ # copy WIND file from PERMANENT
+ # TODO: this should be a function in grass.script (used also in gis_set.py, PyGRASS alos has its way with Mapset)
+ # TODO: are premisions an issue here?
+ shutil.copy(os.path.join(gisdbase, location, 'PERMANENT', 'WIND'),
+ os.path.join(mapset_dir))
+
+ # TODO: we don't do any HTML escaping, use txt file
+ stdout = open(os.path.join(cwd, 'stdout.html'), 'w')
+ stderr = open(os.path.join(cwd, 'stderr.html'), 'w')
+ stdout.write('<html><body><h1>%s</h1><pre>' % (module.name + ' stdout'))
+ stderr.write('<html><body><h1>%s</h1><pre>' % (module.name + ' stderr'))
+ stdout.flush() # we need to flush to write our changes before stdout
+ stderr.flush()
+
+ # TODO: we might clean the directory here before test if non-empty
+ p = subprocess.Popen([sys.executable, module.abs_file_path],
+ cwd=cwd, env=env,
+ stdout=stdout, stderr=stderr)
+ returncode = p.wait()
+ stdout.flush()
+ stderr.flush()
+ stdout.write('</pre></body></html>')
+ stderr.write('</pre></body></html>')
+ file_index_path = os.path.join(cwd, 'index.html')
+ if returncode:
+ sys.stderr.write('{d}/{m} failed (see {f})\n'.format(d=module.tested_dir,
+ m=module.name,
+ f=file_index_path))
+ main_index.write('<li><a href="{d}/{m}/index.html">{d}/{m}</a>'.format(d=module.tested_dir, m=module.name))
+ file_index = open(file_index_path, 'w')
+ file_index.write('<html><body>'
+ '<ul>'
+ '<li><a href="stdout.html">standard output (stdout)</a>'
+ '<li><a href="stderr.html">standard error output (stderr)</a>'
+ '<li><a href="testcodecoverage/index.html">code coverage</a>'
+ '</ul>'
+ '</body></html>')
+ stdout.close()
+ stderr.close()
+ file_index.close()
+ # TODO: add some try-except or with for better error handling
+ os.remove(gisrc)
+ # TODO: only if clean up
+ if self.clean_mapsets:
+ shutil.rmtree(mapset_dir)
+
+ main_index.write('</ul>'
'</body></html>')
- stdout.close()
- stderr.close()
- file_index.close()
- os.remove(gisrc)
- # TODO: only if clean up
- shutil.rmtree(mapset_dir)
+ main_index.close()
- main_index.write('</ul>'
- '</body></html>')
- main_index.close()
+if __name__ == '__main__':
+ gisdbase = gcore.gisenv()['GISDBASE']
+ assert gisdbase
+ results_dir = 'testresults'
+ shutil.rmtree(results_dir) # TODO: too brute force?
-if __name__ == '__main__':
- recursive_runs()
+ invoker = GrassTestFilesInvoker(start_dir='.')
+ invoker.run_in_location(gisdbase=gisdbase, location='nc_spm_08_grass7_tests', location_shortcut='nc',
+ results_dir=results_dir)
More information about the grass-commit
mailing list