app/django/contrib/gis/tests/__init__.py
changeset 323 ff1a9aa48cfd
equal deleted inserted replaced
322:6641e941ef1e 323:ff1a9aa48cfd
       
     1 import sys, unittest
       
     2 
       
     3 def geo_suite():
       
     4     """
       
     5     Builds a test suite for the GIS package.  This is not named
       
     6     `suite` so it will not interfere with the Django test suite (since
       
     7     spatial database tables are required to execute these tests on
       
     8     some backends).
       
     9     """
       
    10     from django.conf import settings
       
    11     from django.contrib.gis.tests.utils import mysql, oracle, postgis
       
    12     from django.contrib.gis.gdal import HAS_GDAL
       
    13     from django.contrib.gis.utils import HAS_GEOIP
       
    14 
       
    15     # Tests that require use of a spatial database (e.g., creation of models)
       
    16     test_models = ['geoapp',]
       
    17 
       
    18     # Tests that do not require setting up and tearing down a spatial database.
       
    19     test_suite_names = [
       
    20         'test_geos',
       
    21         'test_measure',
       
    22         ]
       
    23     if HAS_GDAL:
       
    24         if oracle:
       
    25             # TODO: There's a problem with `select_related` and GeoQuerySet on
       
    26             # Oracle -- e.g., GeoModel.objects.distance(geom, field_name='fk__point')
       
    27             # doesn't work so we don't test `relatedapp`.
       
    28             test_models += ['distapp', 'layermap']
       
    29         elif postgis:
       
    30             test_models += ['distapp', 'layermap', 'relatedapp']
       
    31         elif mysql:
       
    32             test_models += ['relatedapp']
       
    33 
       
    34         test_suite_names += [
       
    35             'test_gdal_driver',
       
    36             'test_gdal_ds',
       
    37             'test_gdal_envelope',
       
    38             'test_gdal_geom',
       
    39             'test_gdal_srs',
       
    40             'test_spatialrefsys',
       
    41             ]
       
    42     else:
       
    43         print >>sys.stderr, "GDAL not available - no GDAL tests will be run."
       
    44 
       
    45     if HAS_GEOIP and hasattr(settings, 'GEOIP_PATH'):
       
    46         test_suite_names.append('test_geoip')
       
    47 
       
    48     s = unittest.TestSuite()
       
    49     for test_suite in test_suite_names:
       
    50         tsuite = getattr(__import__('django.contrib.gis.tests', globals(), locals(), [test_suite]),test_suite)
       
    51         s.addTest(tsuite.suite())
       
    52     return s, test_models
       
    53 
       
    54 def run_gis_tests(test_labels, **kwargs):
       
    55     """
       
    56     Use this routine as the TEST_RUNNER in your settings in order to run the
       
    57     GeoDjango test suite.  This must be done as a database superuser for
       
    58     PostGIS, so read the docstring in `run_test()` below for more details.
       
    59     """
       
    60     from django.conf import settings
       
    61     from django.db.models import loading
       
    62     from django.contrib.gis.tests.utils import mysql
       
    63 
       
    64     # Getting initial values.
       
    65     old_installed = settings.INSTALLED_APPS
       
    66     old_root_urlconf = settings.ROOT_URLCONF
       
    67 
       
    68     # Based on ALWAYS_INSTALLED_APPS from django test suite --
       
    69     # this prevents us from creating tables in our test database
       
    70     # from locally installed apps.
       
    71     new_installed =  ['django.contrib.contenttypes',
       
    72                       'django.contrib.auth',
       
    73                       'django.contrib.sites',
       
    74                       'django.contrib.sitemaps',
       
    75                       'django.contrib.flatpages',
       
    76                       'django.contrib.gis',
       
    77                       'django.contrib.redirects',
       
    78                       'django.contrib.sessions',
       
    79                       'django.contrib.comments',
       
    80                       'django.contrib.admin',
       
    81                       ]
       
    82 
       
    83     # Setting the URLs.
       
    84     settings.ROOT_URLCONF = 'django.contrib.gis.tests.urls'
       
    85 
       
    86     # Creating the test suite, adding the test models to INSTALLED_APPS, and
       
    87     # adding the model test suites to our suite package.
       
    88     gis_suite, test_models = geo_suite()
       
    89     for test_model in test_models:
       
    90         module_name = 'django.contrib.gis.tests.%s' % test_model
       
    91         if mysql:
       
    92             test_module_name = 'tests_mysql'
       
    93         else:
       
    94             test_module_name = 'tests'
       
    95         new_installed.append(module_name)
       
    96 
       
    97         # Getting the model test suite
       
    98         tsuite = getattr(__import__('django.contrib.gis.tests.%s' % test_model, globals(), locals(), [test_module_name]), 
       
    99                          test_module_name)
       
   100         gis_suite.addTest(tsuite.suite())
       
   101 
       
   102     # Resetting the loaded flag to take into account what we appended to 
       
   103     # the INSTALLED_APPS (since this routine is invoked through 
       
   104     # django/core/management, it caches the apps; this ensures that syncdb 
       
   105     # will see our appended models)
       
   106     settings.INSTALLED_APPS = new_installed
       
   107     loading.cache.loaded = False
       
   108 
       
   109     # Running the tests using the GIS test runner.
       
   110     result = run_tests(test_labels, suite=gis_suite, **kwargs)
       
   111 
       
   112     # Restoring modified settings.
       
   113     settings.INSTALLED_APPS = old_installed
       
   114     settings.ROOT_URLCONF = old_root_urlconf
       
   115 
       
   116     return result
       
   117 
       
   118 def run_tests(test_labels, verbosity=1, interactive=True, extra_tests=[], suite=None):
       
   119     """
       
   120     This module allows users to run tests for GIS apps that require the creation 
       
   121     of a spatial database.  Currently, this is only required for PostgreSQL as
       
   122     PostGIS needs extra overhead in test database creation.
       
   123 
       
   124     In order to create a PostGIS database, the DATABASE_USER (or 
       
   125     TEST_DATABASE_USER, if defined) will require superuser priviliges.  
       
   126 
       
   127     To accomplish this outside the `postgres` user, you have a few options:
       
   128       (A) Make your user a super user:
       
   129         This may be done at the time the user is created, for example:
       
   130         $ createuser --superuser <user_name>
       
   131 
       
   132         Or you may alter the user's role from the SQL shell (assuming this
       
   133         is done from an existing superuser role):
       
   134         postgres# ALTER ROLE <user_name> SUPERUSER;
       
   135 
       
   136       (B) Create your own PostgreSQL database as a local user:
       
   137         1. Initialize database: `initdb -D /path/to/user/db`
       
   138         2. If there's already a Postgres instance on the machine, it will need
       
   139            to use a different TCP port than 5432. Edit postgresql.conf (in 
       
   140            /path/to/user/db) to change the database port (e.g. `port = 5433`).  
       
   141         3. Start this database `pg_ctl -D /path/to/user/db start`
       
   142 
       
   143       (C) On Windows platforms the pgAdmin III utility may also be used as 
       
   144         a simple way to add superuser privileges to your database user.
       
   145 
       
   146     The TEST_RUNNER needs to be set in your settings like so:
       
   147 
       
   148       TEST_RUNNER='django.contrib.gis.tests.run_tests'
       
   149 
       
   150     Note: This test runner assumes that the PostGIS SQL files ('lwpostgis.sql'
       
   151     and 'spatial_ref_sys.sql') are installed in the directory specified by 
       
   152     `pg_config --sharedir` (and defaults to /usr/local/share if that fails).
       
   153     This behavior is overridden if POSTGIS_SQL_PATH is set in your settings.
       
   154     
       
   155     Windows users should set POSTGIS_SQL_PATH manually because the output
       
   156     of `pg_config` uses paths like 'C:/PROGRA~1/POSTGR~1/..'.
       
   157 
       
   158     Finally, the tests may be run by invoking `./manage.py test`.
       
   159     """
       
   160     from django.conf import settings
       
   161     from django.db import connection
       
   162     from django.db.models import get_app, get_apps
       
   163     from django.test.simple import build_suite, build_test
       
   164     from django.test.utils import setup_test_environment, teardown_test_environment
       
   165 
       
   166     # The `create_spatial_db` routine abstracts away all the steps needed
       
   167     # to properly construct a spatial database for the backend.
       
   168     from django.contrib.gis.db.backend import create_spatial_db
       
   169 
       
   170     # Setting up for testing.
       
   171     setup_test_environment()
       
   172     settings.DEBUG = False
       
   173     old_name = settings.DATABASE_NAME
       
   174 
       
   175     # The suite may be passed in manually, e.g., when we run the GeoDjango test,
       
   176     # we want to build it and pass it in due to some customizations.  Otherwise, 
       
   177     # the normal test suite creation process from `django.test.simple.run_tests` 
       
   178     # is used to create the test suite.
       
   179     if suite is None:
       
   180         suite = unittest.TestSuite()
       
   181         if test_labels:
       
   182             for label in test_labels:
       
   183                 if '.' in label:
       
   184                     suite.addTest(build_test(label))
       
   185                 else:
       
   186                     app = get_app(label)
       
   187                     suite.addTest(build_suite(app))
       
   188         else:
       
   189             for app in get_apps():
       
   190                 suite.addTest(build_suite(app))
       
   191     
       
   192         for test in extra_tests:
       
   193             suite.addTest(test)
       
   194 
       
   195     # Creating the test spatial database.
       
   196     create_spatial_db(test=True, verbosity=verbosity)
       
   197 
       
   198     # Executing the tests (including the model tests), and destorying the
       
   199     # test database after the tests have completed.
       
   200     result = unittest.TextTestRunner(verbosity=verbosity).run(suite)
       
   201     connection.creation.destroy_test_db(old_name, verbosity)
       
   202     teardown_test_environment()
       
   203 
       
   204     # Returning the total failures and errors
       
   205     return len(result.failures) + len(result.errors)