From 199a8b783f3526c695b64e4ccc30d9ab3711b178 Mon Sep 17 00:00:00 2001 From: Calen Pennington Date: Fri, 23 Jan 2015 16:04:01 -0500 Subject: [PATCH] Enforce the use of XModuleFactory only in contexts where something will clean up after it --- common/djangoapps/terrain/factories.py | 3 ++ .../xmodule/modulestore/tests/django_utils.py | 5 +++ .../xmodule/modulestore/tests/factories.py | 41 +++++++++++++++++++ 3 files changed, 49 insertions(+) diff --git a/common/djangoapps/terrain/factories.py b/common/djangoapps/terrain/factories.py index 4173efa1d9..29df3c0f43 100644 --- a/common/djangoapps/terrain/factories.py +++ b/common/djangoapps/terrain/factories.py @@ -8,6 +8,9 @@ import xmodule.modulestore.tests.factories as xf import course_modes.tests.factories as cmf from lettuce import world +# Unlock XBlock factories, because we're randomizing the collection +# name above to prevent collisions +xf.XMODULE_FACTORY_LOCK.enable() world.absorb(sf.UserFactory) world.absorb(sf.UserProfileFactory) diff --git a/common/lib/xmodule/xmodule/modulestore/tests/django_utils.py b/common/lib/xmodule/xmodule/modulestore/tests/django_utils.py index 93090ae555..7418c86b07 100644 --- a/common/lib/xmodule/xmodule/modulestore/tests/django_utils.py +++ b/common/lib/xmodule/xmodule/modulestore/tests/django_utils.py @@ -20,6 +20,7 @@ from xmodule.modulestore import ModuleStoreEnum from xmodule.modulestore.django import modulestore, clear_existing_modulestores from xmodule.modulestore.tests.mongo_connection import MONGO_PORT_NUM, MONGO_HOST from xmodule.modulestore.tests.sample_courses import default_block_info_tree, TOY_BLOCK_INFO_TREE +from xmodule.modulestore.tests.factories import XMODULE_FACTORY_LOCK from xmodule.tabs import CoursewareTab, CourseInfoTab, StaticTab, DiscussionTab, ProgressTab, WikiTab @@ -242,6 +243,10 @@ class ModuleStoreTestCase(TestCase): self.addCleanup(RequestCache().clear_request_cache) + # Enable XModuleFactories for the space of this test (and its setUp). + self.addCleanup(XMODULE_FACTORY_LOCK.disable) + XMODULE_FACTORY_LOCK.enable() + super(ModuleStoreTestCase, self).setUp() self.store = modulestore() diff --git a/common/lib/xmodule/xmodule/modulestore/tests/factories.py b/common/lib/xmodule/xmodule/modulestore/tests/factories.py index fb704299c9..2e0965fd91 100644 --- a/common/lib/xmodule/xmodule/modulestore/tests/factories.py +++ b/common/lib/xmodule/xmodule/modulestore/tests/factories.py @@ -22,6 +22,44 @@ class Dummy(object): pass +class XModuleFactoryLock(threading.local): + """ + This class exists to store whether XModuleFactory can be accessed in a safe + way (meaning, in a context where the data it creates will be cleaned up). + + Users of XModuleFactory (or its subclasses) should only call XModuleFactoryLock.enable + after ensuring that a) the modulestore will be cleaned up, and b) that XModuleFactoryLock.disable + will be called. + """ + def __init__(self): + super(XModuleFactoryLock, self).__init__() + self._enabled = False + + def enable(self): + """ + Enable XModuleFactories. This should only be turned in a context + where the modulestore will be reset at the end of the test (such + as inside ModuleStoreTestCase). + """ + self._enabled = True + + def disable(self): + """ + Disable XModuleFactories. This should be called once the data + from the factory has been cleaned up. + """ + self._enabled = False + + def is_enabled(self): + """ + Return whether XModuleFactories are enabled. + """ + return self._enabled + + +XMODULE_FACTORY_LOCK = XModuleFactoryLock() + + class XModuleFactory(Factory): """ Factory for XModules @@ -34,6 +72,9 @@ class XModuleFactory(Factory): @lazy_attribute def modulestore(self): + msg = "XMODULE_FACTORY_LOCK not enabled. Please use ModuleStoreTestCase as your test baseclass." + assert XMODULE_FACTORY_LOCK.is_enabled(), msg + from xmodule.modulestore.django import modulestore return modulestore()