Commit e0407893 by Renzo Lucioni

Merge pull request #11603 from edx/usman/migrations-setup

Update migrations setup during Python unit tests
parents 0b430fc9 2586f09d
...@@ -23,6 +23,7 @@ import os ...@@ -23,6 +23,7 @@ import os
from path import Path as path from path import Path as path
from warnings import filterwarnings, simplefilter from warnings import filterwarnings, simplefilter
from uuid import uuid4 from uuid import uuid4
from util.db import NoOpMigrationModules
# import settings from LMS for consistent behavior with CMS # import settings from LMS for consistent behavior with CMS
# pylint: disable=unused-import # pylint: disable=unused-import
...@@ -42,7 +43,7 @@ MONGO_HOST = os.environ.get('EDXAPP_TEST_MONGO_HOST', 'localhost') ...@@ -42,7 +43,7 @@ MONGO_HOST = os.environ.get('EDXAPP_TEST_MONGO_HOST', 'localhost')
THIS_UUID = uuid4().hex[:5] THIS_UUID = uuid4().hex[:5]
# Nose Test Runner # Nose Test Runner
TEST_RUNNER = 'django_nose.NoseTestSuiteRunner' TEST_RUNNER = 'openedx.core.djangolib.nose.NoseTestSuiteRunner'
_SYSTEM = 'cms' _SYSTEM = 'cms'
...@@ -129,9 +130,10 @@ DATABASES = { ...@@ -129,9 +130,10 @@ DATABASES = {
}, },
} }
# This hack disables migrations during tests. We want to create tables directly from the models for speed. if os.environ.get('DISABLE_MIGRATIONS'):
# See https://groups.google.com/d/msg/django-developers/PWPj3etj3-U/kCl6pMsQYYoJ. # Create tables directly from apps' models. This can be removed once we upgrade
MIGRATION_MODULES = {app: "app.migrations_not_used_in_tests" for app in INSTALLED_APPS} # to Django 1.9, which allows setting MIGRATION_MODULES to None in order to skip migrations.
MIGRATION_MODULES = NoOpMigrationModules()
LMS_BASE = "localhost:8000" LMS_BASE = "localhost:8000"
FEATURES['PREVIEW_LMS_BASE'] = "preview" FEATURES['PREVIEW_LMS_BASE'] = "preview"
......
...@@ -231,3 +231,16 @@ def generate_int_id(minimum=0, maximum=MYSQL_MAX_INT, used_ids=None): ...@@ -231,3 +231,16 @@ def generate_int_id(minimum=0, maximum=MYSQL_MAX_INT, used_ids=None):
cid = random.randint(minimum, maximum) cid = random.randint(minimum, maximum)
return cid return cid
class NoOpMigrationModules(object):
"""
Return invalid migrations modules for apps. Used for disabling migrations during tests.
See https://groups.google.com/d/msg/django-developers/PWPj3etj3-U/kCl6pMsQYYoJ.
"""
def __contains__(self, item):
return True
def __getitem__(self, item):
return "notmigrations"
...@@ -24,6 +24,7 @@ from path import Path as path ...@@ -24,6 +24,7 @@ from path import Path as path
from uuid import uuid4 from uuid import uuid4
from warnings import filterwarnings, simplefilter from warnings import filterwarnings, simplefilter
from util.db import NoOpMigrationModules
from openedx.core.lib.tempdir import mkdtemp_clean from openedx.core.lib.tempdir import mkdtemp_clean
# This patch disables the commit_on_success decorator during tests # This patch disables the commit_on_success decorator during tests
...@@ -86,7 +87,7 @@ PARENTAL_CONSENT_AGE_LIMIT = 13 ...@@ -86,7 +87,7 @@ PARENTAL_CONSENT_AGE_LIMIT = 13
SOUTH_TESTS_MIGRATE = False # To disable migrations and use syncdb instead SOUTH_TESTS_MIGRATE = False # To disable migrations and use syncdb instead
# Nose Test Runner # Nose Test Runner
TEST_RUNNER = 'django_nose.NoseTestSuiteRunner' TEST_RUNNER = 'openedx.core.djangolib.nose.NoseTestSuiteRunner'
_SYSTEM = 'lms' _SYSTEM = 'lms'
...@@ -188,9 +189,10 @@ DATABASES = { ...@@ -188,9 +189,10 @@ DATABASES = {
} }
# This hack disables migrations during tests. We want to create tables directly from the models for speed. if os.environ.get('DISABLE_MIGRATIONS'):
# See https://groups.google.com/d/msg/django-developers/PWPj3etj3-U/kCl6pMsQYYoJ. # Create tables directly from apps' models. This can be removed once we upgrade
MIGRATION_MODULES = {app: "app.migrations_not_used_in_tests" for app in INSTALLED_APPS} # to Django 1.9, which allows setting MIGRATION_MODULES to None in order to skip migrations.
MIGRATION_MODULES = NoOpMigrationModules()
CACHES = { CACHES = {
# This is the cache used for most things. # This is the cache used for most things.
......
"""
Utilities related to nose.
"""
from django.core.management import call_command
from django.db import DEFAULT_DB_ALIAS, connections, transaction
import django_nose
class NoseTestSuiteRunner(django_nose.NoseTestSuiteRunner):
"""Custom NoseTestSuiteRunner."""
def setup_databases(self):
""" Setup databases and then flush to remove data added by migrations. """
return_value = super(NoseTestSuiteRunner, self).setup_databases()
# Delete all data added by data migrations. Unit tests should setup their own data using factories.
call_command('flush', verbosity=0, interactive=False, load_initial_data=False)
# Through Django 1.8, auto increment sequences are not reset when calling flush on a SQLite db.
# So we do it ourselves.
# http://sqlite.org/autoinc.html
connection = connections[DEFAULT_DB_ALIAS]
if connection.vendor == 'sqlite' and not connection.features.supports_sequence_reset:
with transaction.atomic(using=DEFAULT_DB_ALIAS):
cursor = connection.cursor()
cursor.execute(
"delete from sqlite_sequence;"
)
return return_value
...@@ -34,6 +34,12 @@ __test__ = False # do not collect ...@@ -34,6 +34,12 @@ __test__ = False # do not collect
make_option("-q", "--quiet", action="store_const", const=0, dest="verbosity"), make_option("-q", "--quiet", action="store_const", const=0, dest="verbosity"),
make_option("-v", "--verbosity", action="count", dest="verbosity", default=1), make_option("-v", "--verbosity", action="count", dest="verbosity", default=1),
make_option("--pdb", action="store_true", help="Drop into debugger on failures or errors"), make_option("--pdb", action="store_true", help="Drop into debugger on failures or errors"),
make_option(
'--disable-migrations',
action='store_true',
dest='disable_migrations',
help="Create tables directly from apps' models. Can also be used by exporting DISABLE_MIGRATIONS=1."
),
], share_with=['pavelib.utils.test.utils.clean_reports_dir']) ], share_with=['pavelib.utils.test.utils.clean_reports_dir'])
def test_system(options): def test_system(options):
""" """
...@@ -51,6 +57,7 @@ def test_system(options): ...@@ -51,6 +57,7 @@ def test_system(options):
'cov_args': getattr(options, 'cov_args', ''), 'cov_args': getattr(options, 'cov_args', ''),
'skip_clean': getattr(options, 'skip_clean', False), 'skip_clean': getattr(options, 'skip_clean', False),
'pdb': getattr(options, 'pdb', False), 'pdb': getattr(options, 'pdb', False),
'disable_migrations': getattr(options, 'disable_migrations', False),
} }
if test_id: if test_id:
...@@ -134,6 +141,12 @@ def test_lib(options): ...@@ -134,6 +141,12 @@ def test_lib(options):
make_option("-q", "--quiet", action="store_const", const=0, dest="verbosity"), make_option("-q", "--quiet", action="store_const", const=0, dest="verbosity"),
make_option("-v", "--verbosity", action="count", dest="verbosity", default=1), make_option("-v", "--verbosity", action="count", dest="verbosity", default=1),
make_option("--pdb", action="store_true", help="Drop into debugger on failures or errors"), make_option("--pdb", action="store_true", help="Drop into debugger on failures or errors"),
make_option(
'--disable-migrations',
action='store_true',
dest='disable_migrations',
help="Create tables directly from apps' models. Can also be used by exporting DISABLE_MIGRATIONS=1."
),
]) ])
def test_python(options): def test_python(options):
""" """
...@@ -146,6 +159,7 @@ def test_python(options): ...@@ -146,6 +159,7 @@ def test_python(options):
'extra_args': getattr(options, 'extra_args', ''), 'extra_args': getattr(options, 'extra_args', ''),
'cov_args': getattr(options, 'cov_args', ''), 'cov_args': getattr(options, 'cov_args', ''),
'pdb': getattr(options, 'pdb', False), 'pdb': getattr(options, 'pdb', False),
'disable_migrations': getattr(options, 'disable_migrations', False),
} }
python_suite = suites.PythonTestSuite('Python Tests', **opts) python_suite = suites.PythonTestSuite('Python Tests', **opts)
......
""" """
Classes used for defining and running python test suites Classes used for defining and running python test suites
""" """
import os
from pavelib.utils.test import utils as test_utils from pavelib.utils.test import utils as test_utils
from pavelib.utils.test.suites.suite import TestSuite from pavelib.utils.test.suites.suite import TestSuite
from pavelib.utils.test.suites.nose_suite import LibTestSuite, SystemTestSuite from pavelib.utils.test.suites.nose_suite import LibTestSuite, SystemTestSuite
...@@ -16,11 +18,16 @@ class PythonTestSuite(TestSuite): ...@@ -16,11 +18,16 @@ class PythonTestSuite(TestSuite):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(PythonTestSuite, self).__init__(*args, **kwargs) super(PythonTestSuite, self).__init__(*args, **kwargs)
self.opts = kwargs self.opts = kwargs
self.disable_migrations = kwargs.get('disable_migrations', False)
self.fasttest = kwargs.get('fasttest', False) self.fasttest = kwargs.get('fasttest', False)
self.subsuites = kwargs.get('subsuites', self._default_subsuites) self.subsuites = kwargs.get('subsuites', self._default_subsuites)
def __enter__(self): def __enter__(self):
super(PythonTestSuite, self).__enter__() super(PythonTestSuite, self).__enter__()
if self.disable_migrations:
os.environ['DISABLE_MIGRATIONS'] = '1'
if not (self.fasttest or self.skip_clean): if not (self.fasttest or self.skip_clean):
test_utils.clean_test_files() test_utils.clean_test_files()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment