From 8a7f5b7fd17d542bd1f428c87f059e24ab570501 Mon Sep 17 00:00:00 2001 From: Jeff Balogh Date: Mon, 1 Feb 2010 11:21:13 -0800 Subject: [PATCH 1/2] files.platform needs created & modified fields --- apps/admin/fixtures/admin/tests/flagged.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/admin/fixtures/admin/tests/flagged.json b/apps/admin/fixtures/admin/tests/flagged.json index 13c566843b..ff7224fc60 100644 --- a/apps/admin/fixtures/admin/tests/flagged.json +++ b/apps/admin/fixtures/admin/tests/flagged.json @@ -133,7 +133,9 @@ "fields": { "name": null, "shortname": null, - "icontype": "image/png" + "icontype": "image/png", + "modified": "2009-08-03 23:59:20", + "created": "2009-08-03 23:58:46" } }, { From 0e866440554ebe0bdc3f02f0dc71e5a9f875f4f1 Mon Sep 17 00:00:00 2001 From: Jeff Balogh Date: Mon, 1 Feb 2010 11:24:26 -0800 Subject: [PATCH 2/2] a new test runner for blazing-fast tests --- docs/topics/testing.rst | 12 +++++-- lib/test_utils/runner.py | 67 ++++++++++++++++++++++++++++++++++++++++ scripts/build.sh | 1 + settings.py | 2 +- 4 files changed, 79 insertions(+), 3 deletions(-) create mode 100644 lib/test_utils/runner.py diff --git a/docs/topics/testing.rst b/docs/topics/testing.rst index 3a09df2621..9474db3338 100644 --- a/docs/topics/testing.rst +++ b/docs/topics/testing.rst @@ -45,9 +45,17 @@ for the full set, but some common ones are: Our continuous integration server adds some additional flags for other features (for example, coverage statistics). To see what those commands are check out -the build script at ``/scripts/build.sh``. +the build script at :src:`scripts/build.sh`. -.. Would be nice to link to the actual script at some point. + +Database Setup +~~~~~~~~~~~~~~ + +Our test runner will try as hard as it can to skip creating a fresh database +every time. If you really want to make a new database (e.g. when models have +changed), set the environment variable ``FORCE_DB``. :: + + FORCE_DB=true python manage.py test Writing Tests diff --git a/lib/test_utils/runner.py b/lib/test_utils/runner.py new file mode 100644 index 0000000000..61aca3284e --- /dev/null +++ b/lib/test_utils/runner.py @@ -0,0 +1,67 @@ +""" +This is a test runner that monkeypatches connection.creation to skip database +creation if it appears that the db already exists. Your tests will run much +faster. + +To force the normal database creation, define the environment variable +"FORCE_DB". It doesn't really matter what the value is, we just check to see +if it's there. +""" +import os + +from django.db import connections +from django.db.backends.creation import TEST_DATABASE_PREFIX +from django.db.backends.mysql import creation as mysql + +import django_nose + + +# XXX: hard-coded to mysql. +class SkipDatabaseCreation(mysql.DatabaseCreation): + + def _create_test_db(self, verbosity, autoclobber): + ### Oh yes, let's copy from django/db/backends/creation.py + suffix = self.sql_table_creation_suffix() + + if self.connection.settings_dict['TEST_NAME']: + test_database_name = self.connection.settings_dict['TEST_NAME'] + else: + test_database_name = TEST_DATABASE_PREFIX + self.connection.settings_dict['NAME'] + qn = self.connection.ops.quote_name + + # Create the test database and connect to it. We need to autocommit + # if the database supports it because PostgreSQL doesn't allow + # CREATE/DROP DATABASE statements within transactions. + cursor = self.connection.cursor() + self.set_autocommit() + + ### That's enough copying. + + # If we couldn't create the test db, assume it already exists. + try: + cursor.execute("CREATE DATABASE %s %s" % + (qn(test_database_name), suffix)) + except Exception, e: + print '...Skipping setup of %s!' % test_database_name + print '...Try FORCE_DB=true if you need fresh databases.' + return test_database_name + + # Drop the db we just created, then do the normal setup. + cursor.execute("DROP DATABASE %s %s" % + (qn(test_database_name), suffix)) + return super(SkipDatabaseCreation, self)._create_test_db( + verbosity, autoclobber) + + +class RadicalTestSuiteRunner(django_nose.NoseTestSuiteRunner): + + def setup_databases(self): + if not os.getenv('FORCE_DB'): + for alias in connections: + connection = connections[alias] + connection.creation.__class__ = SkipDatabaseCreation + return super(RadicalTestSuiteRunner, self).setup_databases() + + def teardown_databases(self, old_config): + if os.getenv('FORCE_DB'): + super(RadicalTestSuiteRunner, self).teardown_databases(old_config) diff --git a/scripts/build.sh b/scripts/build.sh index 0ed6b9b0d9..83774055ad 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -23,6 +23,7 @@ ROOT_URLCONF = 'workspace.urls' SETTINGS echo "Starting tests..." +export FORCE_DB='yes sir' coverage run manage.py test --noinput --logging-clear-handlers --with-xunit coverage xml $(find apps lib -name '*.py') diff --git a/settings.py b/settings.py index 8d4690fef3..d362f37fef 100644 --- a/settings.py +++ b/settings.py @@ -184,7 +184,7 @@ DEV_APPS = ( 'django_nose', ) -TEST_RUNNER = 'django_nose.NoseTestSuiteRunner' +TEST_RUNNER = 'test_utils.runner.RadicalTestSuiteRunner' LOG_LEVEL = logging.DEBUG