diff --git a/common/lib/xmodule/xmodule/modulestore/tests/django_utils.py b/common/lib/xmodule/xmodule/modulestore/tests/django_utils.py index 6bebed9acc..d66e604117 100644 --- a/common/lib/xmodule/xmodule/modulestore/tests/django_utils.py +++ b/common/lib/xmodule/xmodule/modulestore/tests/django_utils.py @@ -2,6 +2,7 @@ """ Modulestore configuration for test cases. """ +import copy import functools from uuid import uuid4 from contextlib import contextmanager @@ -192,6 +193,8 @@ class ModuleStoreIsolationMixin(CacheIsolationMixin): MODULESTORE = mixed_store_config(mkdtemp_clean(), {}) ENABLED_CACHES = ['mongo_metadata_inheritance', 'loc_cache'] + __settings_overrides = [] + __old_modulestores = [] @classmethod def start_modulestore_isolation(cls): @@ -201,10 +204,13 @@ class ModuleStoreIsolationMixin(CacheIsolationMixin): be flushed (all content will be deleted). """ cls.start_cache_isolation() - cls.__settings_override = override_settings( + override = override_settings( MODULESTORE=cls.MODULESTORE, ) - cls.__settings_override.__enter__() + + cls.__old_modulestores.append(copy.deepcopy(settings.MODULESTORE)) + override.__enter__() + cls.__settings_overrides.append(override) XMODULE_FACTORY_LOCK.enable() clear_existing_modulestores() cls.store = modulestore() @@ -218,7 +224,9 @@ class ModuleStoreIsolationMixin(CacheIsolationMixin): """ drop_mongo_collections() # pylint: disable=no-value-for-parameter XMODULE_FACTORY_LOCK.disable() - cls.__settings_override.__exit__(None, None, None) + cls.__settings_overrides.pop().__exit__(None, None, None) + + assert settings.MODULESTORE == cls.__old_modulestores.pop() cls.end_cache_isolation() diff --git a/openedx/core/djangolib/testing/utils.py b/openedx/core/djangolib/testing/utils.py index 4feb1749c3..5a6efbfaa0 100644 --- a/openedx/core/djangolib/testing/utils.py +++ b/openedx/core/djangolib/testing/utils.py @@ -1,3 +1,15 @@ +""" +Utility classes for testing django applications. + +:py:class:`CacheIsolationMixin` + A mixin helping to write tests which are isolated from cached data. + +:py:class:`CacheIsolationTestCase` + A TestCase baseclass that has per-test isolated caches. +""" + +import copy + from django.core.cache import caches from django.test import TestCase, override_settings from django.conf import settings @@ -27,7 +39,9 @@ class CacheIsolationMixin(object): CACHES = None ENABLED_CACHES = None - __settings_override = None + + __settings_overrides = [] + __old_settings = [] @classmethod def start_cache_isolation(cls): @@ -61,8 +75,12 @@ class CacheIsolationMixin(object): if cache_settings is None: return - cls.__settings_override = override_settings(CACHES=cache_settings) - cls.__settings_override.__enter__() + cls.__old_settings.append(copy.deepcopy(settings.CACHES)) + override = override_settings(CACHES=cache_settings) + override.__enter__() + cls.__settings_overrides.append(override) + + assert settings.CACHES == cache_settings # Start with empty caches cls.clear_caches() @@ -76,9 +94,9 @@ class CacheIsolationMixin(object): # Make sure that cache contents don't leak out after the isolation is ended cls.clear_caches() - if cls.__settings_override is not None: - cls.__settings_override.__exit__(None, None, None) - cls.__settings_override = None + if cls.__settings_overrides: + cls.__settings_overrides.pop().__exit__(None, None, None) + assert settings.CACHES == cls.__old_settings.pop() @classmethod def clear_caches(cls):