Commit ccaafce0 by Calen Pennington

Merge pull request #12205 from cpennington/disable-caching-in-tests

Disable caching in LMS tests
parents a422ad60 e97af55e
...@@ -46,9 +46,6 @@ class TestCreateCourse(ModuleStoreTestCase): ...@@ -46,9 +46,6 @@ class TestCreateCourse(ModuleStoreTestCase):
Unit tests for creating a course in either old mongo or split mongo via command line Unit tests for creating a course in either old mongo or split mongo via command line
""" """
def setUp(self):
super(TestCreateCourse, self).setUp(create_user=True)
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split) @ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
def test_all_stores_user_email(self, store): def test_all_stores_user_email(self, store):
call_command( call_command(
......
...@@ -4,7 +4,7 @@ Tests for the force_publish management command ...@@ -4,7 +4,7 @@ Tests for the force_publish management command
import mock import mock
from django.core.management import call_command, CommandError from django.core.management import call_command, CommandError
from xmodule.modulestore import ModuleStoreEnum from xmodule.modulestore import ModuleStoreEnum
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase, ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
from contentstore.management.commands.force_publish import Command from contentstore.management.commands.force_publish import Command
from contentstore.management.commands.utils import get_course_versions from contentstore.management.commands.utils import get_course_versions
...@@ -62,7 +62,19 @@ class TestForcePublish(SharedModuleStoreTestCase): ...@@ -62,7 +62,19 @@ class TestForcePublish(SharedModuleStoreTestCase):
with self.assertRaisesRegexp(CommandError, errstring): with self.assertRaisesRegexp(CommandError, errstring):
call_command('force_publish', unicode(course.id)) call_command('force_publish', unicode(course.id))
@SharedModuleStoreTestCase.modifies_courseware
class TestForcePublishModifications(ModuleStoreTestCase):
"""
Tests for the force_publish management command that modify the courseware
during the test.
"""
def setUp(self):
super(TestForcePublishModifications, self).setUp()
self.course = CourseFactory.create(default_store=ModuleStoreEnum.Type.split)
self.test_user_id = ModuleStoreEnum.UserID.test
self.command = Command()
def test_force_publish(self): def test_force_publish(self):
""" """
Test 'force_publish' command Test 'force_publish' command
......
...@@ -59,7 +59,7 @@ class TestMigrateToSplit(ModuleStoreTestCase): ...@@ -59,7 +59,7 @@ class TestMigrateToSplit(ModuleStoreTestCase):
""" """
def setUp(self): def setUp(self):
super(TestMigrateToSplit, self).setUp(create_user=True) super(TestMigrateToSplit, self).setUp()
self.course = CourseFactory(default_store=ModuleStoreEnum.Type.mongo) self.course = CourseFactory(default_store=ModuleStoreEnum.Type.mongo)
def test_user_email(self): def test_user_email(self):
......
...@@ -167,6 +167,8 @@ class InternationalizationTest(ModuleStoreTestCase): ...@@ -167,6 +167,8 @@ class InternationalizationTest(ModuleStoreTestCase):
Tests to validate Internationalization. Tests to validate Internationalization.
""" """
CREATE_USER = False
def setUp(self): def setUp(self):
""" """
These tests need a user in the DB so that the django Test Client These tests need a user in the DB so that the django Test Client
...@@ -175,7 +177,7 @@ class InternationalizationTest(ModuleStoreTestCase): ...@@ -175,7 +177,7 @@ class InternationalizationTest(ModuleStoreTestCase):
will be cleared out before each test case execution and deleted will be cleared out before each test case execution and deleted
afterwards. afterwards.
""" """
super(InternationalizationTest, self).setUp(create_user=False) super(InternationalizationTest, self).setUp()
self.uname = 'testuser' self.uname = 'testuser'
self.email = 'test+courses@edx.org' self.email = 'test+courses@edx.org'
......
...@@ -34,10 +34,10 @@ class ContentStoreImportTest(SignalDisconnectTestMixin, ModuleStoreTestCase): ...@@ -34,10 +34,10 @@ class ContentStoreImportTest(SignalDisconnectTestMixin, ModuleStoreTestCase):
NOTE: refactor using CourseFactory so they do not. NOTE: refactor using CourseFactory so they do not.
""" """
def setUp(self): def setUp(self):
password = super(ContentStoreImportTest, self).setUp() super(ContentStoreImportTest, self).setUp()
self.client = Client() self.client = Client()
self.client.login(username=self.user.username, password=password) self.client.login(username=self.user.username, password=self.user_password)
def load_test_import_course(self, target_id=None, create_if_not_present=True, module_store=None): def load_test_import_course(self, target_id=None, create_if_not_present=True, module_store=None):
''' '''
......
...@@ -32,7 +32,7 @@ class LibraryTestCase(ModuleStoreTestCase): ...@@ -32,7 +32,7 @@ class LibraryTestCase(ModuleStoreTestCase):
Common functionality for content libraries tests Common functionality for content libraries tests
""" """
def setUp(self): def setUp(self):
self.user_password = super(LibraryTestCase, self).setUp() super(LibraryTestCase, self).setUp()
self.client = AjaxEnabledTestClient() self.client = AjaxEnabledTestClient()
self._login_as_staff_user(logout_first=False) self._login_as_staff_user(logout_first=False)
......
...@@ -22,10 +22,10 @@ class TestCourseAccess(ModuleStoreTestCase): ...@@ -22,10 +22,10 @@ class TestCourseAccess(ModuleStoreTestCase):
Create a pool of users w/o granting them any permissions Create a pool of users w/o granting them any permissions
""" """
user_password = super(TestCourseAccess, self).setUp() super(TestCourseAccess, self).setUp()
self.client = AjaxEnabledTestClient() self.client = AjaxEnabledTestClient()
self.client.login(username=self.user.username, password=user_password) self.client.login(username=self.user.username, password=self.user_password)
# create a course via the view handler which has a different strategy for permissions than the factory # create a course via the view handler which has a different strategy for permissions than the factory
self.course_key = self.store.make_course_key('myu', 'mydept.mycourse', 'myrun') self.course_key = self.store.make_course_key('myu', 'mydept.mycourse', 'myrun')
......
...@@ -89,8 +89,11 @@ class ContentStoreTestCase(ModuleStoreTestCase): ...@@ -89,8 +89,11 @@ class ContentStoreTestCase(ModuleStoreTestCase):
class AuthTestCase(ContentStoreTestCase): class AuthTestCase(ContentStoreTestCase):
"""Check that various permissions-related things work""" """Check that various permissions-related things work"""
CREATE_USER = False
ENABLED_CACHES = ['default', 'mongo_metadata_inheritance', 'loc_cache']
def setUp(self): def setUp(self):
super(AuthTestCase, self).setUp(create_user=False) super(AuthTestCase, self).setUp()
self.email = 'a@b.com' self.email = 'a@b.com'
self.pw = 'xyz' self.pw = 'xyz'
......
...@@ -81,7 +81,7 @@ class CourseTestCase(ProceduralCourseTestMixin, ModuleStoreTestCase): ...@@ -81,7 +81,7 @@ class CourseTestCase(ProceduralCourseTestMixin, ModuleStoreTestCase):
afterwards. afterwards.
""" """
self.user_password = super(CourseTestCase, self).setUp() super(CourseTestCase, self).setUp()
self.client = AjaxEnabledTestClient() self.client = AjaxEnabledTestClient()
self.client.login(username=self.user.username, password=self.user_password) self.client.login(username=self.user.username, password=self.user_password)
......
...@@ -30,10 +30,10 @@ class UnitTestLibraries(ModuleStoreTestCase): ...@@ -30,10 +30,10 @@ class UnitTestLibraries(ModuleStoreTestCase):
""" """
def setUp(self): def setUp(self):
user_password = super(UnitTestLibraries, self).setUp() super(UnitTestLibraries, self).setUp()
self.client = AjaxEnabledTestClient() self.client = AjaxEnabledTestClient()
self.client.login(username=self.user.username, password=user_password) self.client.login(username=self.user.username, password=self.user_password)
###################################################### ######################################################
# Tests for /library/ - list and create libraries: # Tests for /library/ - list and create libraries:
......
...@@ -32,7 +32,7 @@ class StructuredTagsAsideTestCase(ModuleStoreTestCase): ...@@ -32,7 +32,7 @@ class StructuredTagsAsideTestCase(ModuleStoreTestCase):
""" """
Preparation for the test execution Preparation for the test execution
""" """
self.user_password = super(StructuredTagsAsideTestCase, self).setUp() super(StructuredTagsAsideTestCase, self).setUp()
self.aside_name = 'tagging_aside' self.aside_name = 'tagging_aside'
self.aside_tag_dif = 'difficulty' self.aside_tag_dif = 'difficulty'
self.aside_tag_dif_value = 'Hard' self.aside_tag_dif_value = 'Hard'
......
...@@ -33,9 +33,11 @@ class CourseModeViewTest(UrlResetMixin, ModuleStoreTestCase): ...@@ -33,9 +33,11 @@ class CourseModeViewTest(UrlResetMixin, ModuleStoreTestCase):
""" """
Course Mode View tests Course Mode View tests
""" """
URLCONF_MODULES = ['course_modes.urls']
@patch.dict(settings.FEATURES, {'MODE_CREATION_FOR_TESTING': True}) @patch.dict(settings.FEATURES, {'MODE_CREATION_FOR_TESTING': True})
def setUp(self): def setUp(self):
super(CourseModeViewTest, self).setUp('course_modes.urls') super(CourseModeViewTest, self).setUp()
self.course = CourseFactory.create() self.course = CourseFactory.create()
self.user = UserFactory.create(username="Bob", email="bob@example.com", password="edx") self.user = UserFactory.create(username="Bob", email="bob@example.com", password="edx")
self.client.login(username=self.user.username, password="edx") self.client.login(username=self.user.username, password="edx")
...@@ -392,9 +394,11 @@ class CourseModeViewTest(UrlResetMixin, ModuleStoreTestCase): ...@@ -392,9 +394,11 @@ class CourseModeViewTest(UrlResetMixin, ModuleStoreTestCase):
class TrackSelectionEmbargoTest(UrlResetMixin, ModuleStoreTestCase): class TrackSelectionEmbargoTest(UrlResetMixin, ModuleStoreTestCase):
"""Test embargo restrictions on the track selection page. """ """Test embargo restrictions on the track selection page. """
URLCONF_MODULES = ['embargo']
@patch.dict(settings.FEATURES, {'EMBARGO': True}) @patch.dict(settings.FEATURES, {'EMBARGO': True})
def setUp(self): def setUp(self):
super(TrackSelectionEmbargoTest, self).setUp('embargo') super(TrackSelectionEmbargoTest, self).setUp()
# Create a course and course modes # Create a course and course modes
self.course = CourseFactory.create() self.course = CourseFactory.create()
......
...@@ -46,6 +46,8 @@ MODULESTORE_CONFIG = mixed_store_config(settings.COMMON_TEST_DATA_ROOT, {}) ...@@ -46,6 +46,8 @@ MODULESTORE_CONFIG = mixed_store_config(settings.COMMON_TEST_DATA_ROOT, {})
class EmbargoCheckAccessApiTests(ModuleStoreTestCase): class EmbargoCheckAccessApiTests(ModuleStoreTestCase):
"""Test the embargo API calls to determine whether a user has access. """ """Test the embargo API calls to determine whether a user has access. """
ENABLED_CACHES = ['default', 'mongo_metadata_inheritance', 'loc_cache']
def setUp(self): def setUp(self):
super(EmbargoCheckAccessApiTests, self).setUp() super(EmbargoCheckAccessApiTests, self).setUp()
self.course = CourseFactory.create() self.course = CourseFactory.create()
...@@ -238,15 +240,14 @@ class EmbargoCheckAccessApiTests(ModuleStoreTestCase): ...@@ -238,15 +240,14 @@ class EmbargoCheckAccessApiTests(ModuleStoreTestCase):
class EmbargoMessageUrlApiTests(UrlResetMixin, ModuleStoreTestCase): class EmbargoMessageUrlApiTests(UrlResetMixin, ModuleStoreTestCase):
"""Test the embargo API calls for retrieving the blocking message URLs. """ """Test the embargo API calls for retrieving the blocking message URLs. """
URLCONF_MODULES = ['embargo']
ENABLED_CACHES = ['default', 'mongo_metadata_inheritance', 'loc_cache']
@patch.dict(settings.FEATURES, {'EMBARGO': True}) @patch.dict(settings.FEATURES, {'EMBARGO': True})
def setUp(self): def setUp(self):
super(EmbargoMessageUrlApiTests, self).setUp('embargo') super(EmbargoMessageUrlApiTests, self).setUp()
self.course = CourseFactory.create() self.course = CourseFactory.create()
def tearDown(self):
super(EmbargoMessageUrlApiTests, self).tearDown()
cache.clear()
@ddt.data( @ddt.data(
('enrollment', '/embargo/blocked-message/enrollment/embargo/'), ('enrollment', '/embargo/blocked-message/enrollment/embargo/'),
('courseware', '/embargo/blocked-message/courseware/embargo/') ('courseware', '/embargo/blocked-message/courseware/embargo/')
......
...@@ -35,9 +35,11 @@ class EmbargoMiddlewareAccessTests(UrlResetMixin, ModuleStoreTestCase): ...@@ -35,9 +35,11 @@ class EmbargoMiddlewareAccessTests(UrlResetMixin, ModuleStoreTestCase):
USERNAME = 'fred' USERNAME = 'fred'
PASSWORD = 'secret' PASSWORD = 'secret'
URLCONF_MODULES = ['embargo']
@patch.dict(settings.FEATURES, {'EMBARGO': True}) @patch.dict(settings.FEATURES, {'EMBARGO': True})
def setUp(self): def setUp(self):
super(EmbargoMiddlewareAccessTests, self).setUp('embargo') super(EmbargoMiddlewareAccessTests, self).setUp()
self.user = UserFactory(username=self.USERNAME, password=self.PASSWORD) self.user = UserFactory(username=self.USERNAME, password=self.PASSWORD)
self.course = CourseFactory.create() self.course = CourseFactory.create()
self.client.login(username=self.USERNAME, password=self.PASSWORD) self.client.login(username=self.USERNAME, password=self.PASSWORD)
......
...@@ -8,9 +8,14 @@ from embargo.models import ( ...@@ -8,9 +8,14 @@ from embargo.models import (
Country, CountryAccessRule, CourseAccessRuleHistory Country, CountryAccessRule, CourseAccessRuleHistory
) )
from openedx.core.djangolib.testing.utils import CacheIsolationTestCase
class EmbargoModelsTest(TestCase):
class EmbargoModelsTest(CacheIsolationTestCase):
"""Test each of the 3 models in embargo.models""" """Test each of the 3 models in embargo.models"""
ENABLED_CACHES = ['default']
def test_course_embargo(self): def test_course_embargo(self):
course_id = CourseLocator('abc', '123', 'doremi') course_id = CourseLocator('abc', '123', 'doremi')
# Test that course is not authorized by default # Test that course is not authorized by default
...@@ -101,9 +106,11 @@ class EmbargoModelsTest(TestCase): ...@@ -101,9 +106,11 @@ class EmbargoModelsTest(TestCase):
self.assertFalse('1.2.0.0' in cblacklist) self.assertFalse('1.2.0.0' in cblacklist)
class RestrictedCourseTest(TestCase): class RestrictedCourseTest(CacheIsolationTestCase):
"""Test RestrictedCourse model. """ """Test RestrictedCourse model. """
ENABLED_CACHES = ['default']
def test_unicode_values(self): def test_unicode_values(self):
course_id = CourseLocator('abc', '123', 'doremi') course_id = CourseLocator('abc', '123', 'doremi')
restricted_course = RestrictedCourse.objects.create(course_key=course_id) restricted_course = RestrictedCourse.objects.create(course_key=course_id)
...@@ -162,8 +169,9 @@ class CountryTest(TestCase): ...@@ -162,8 +169,9 @@ class CountryTest(TestCase):
self.assertEquals(unicode(country), "New Zealand (NZ)") self.assertEquals(unicode(country), "New Zealand (NZ)")
class CountryAccessRuleTest(TestCase): class CountryAccessRuleTest(CacheIsolationTestCase):
"""Test CountryAccessRule model. """ """Test CountryAccessRule model. """
ENABLED_CACHES = ['default']
def test_unicode_values(self): def test_unicode_values(self):
course_id = CourseLocator('abc', '123', 'doremi') course_id = CourseLocator('abc', '123', 'doremi')
......
...@@ -10,11 +10,12 @@ import ddt ...@@ -10,11 +10,12 @@ import ddt
from util.testing import UrlResetMixin from util.testing import UrlResetMixin
from embargo import messages from embargo import messages
from openedx.core.djangolib.testing.utils import CacheIsolationTestCase
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
@ddt.ddt @ddt.ddt
class CourseAccessMessageViewTest(UrlResetMixin, TestCase): class CourseAccessMessageViewTest(CacheIsolationTestCase, UrlResetMixin):
"""Tests for the courseware access message view. """Tests for the courseware access message view.
These end-points serve static content. These end-points serve static content.
...@@ -32,9 +33,13 @@ class CourseAccessMessageViewTest(UrlResetMixin, TestCase): ...@@ -32,9 +33,13 @@ class CourseAccessMessageViewTest(UrlResetMixin, TestCase):
""" """
ENABLED_CACHES = ['default']
URLCONF_MODULES = ['embargo']
@patch.dict(settings.FEATURES, {'EMBARGO': True}) @patch.dict(settings.FEATURES, {'EMBARGO': True})
def setUp(self): def setUp(self):
super(CourseAccessMessageViewTest, self).setUp('embargo') super(CourseAccessMessageViewTest, self).setUp()
@ddt.data(*messages.ENROLL_MESSAGES.keys()) @ddt.data(*messages.ENROLL_MESSAGES.keys())
def test_enrollment_messages(self, msg_key): def test_enrollment_messages(self, msg_key):
......
...@@ -15,22 +15,24 @@ from course_modes.models import CourseMode ...@@ -15,22 +15,24 @@ from course_modes.models import CourseMode
from enrollment import api from enrollment import api
from enrollment.errors import EnrollmentApiLoadError, EnrollmentNotFoundError, CourseModeNotFoundError from enrollment.errors import EnrollmentApiLoadError, EnrollmentNotFoundError, CourseModeNotFoundError
from enrollment.tests import fake_data_api from enrollment.tests import fake_data_api
from openedx.core.djangolib.testing.utils import CacheIsolationTestCase
@ddt.ddt @ddt.ddt
@override_settings(ENROLLMENT_DATA_API="enrollment.tests.fake_data_api") @override_settings(ENROLLMENT_DATA_API="enrollment.tests.fake_data_api")
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
class EnrollmentTest(TestCase): class EnrollmentTest(CacheIsolationTestCase):
""" """
Test student enrollment, especially with different course modes. Test student enrollment, especially with different course modes.
""" """
USERNAME = "Bob" USERNAME = "Bob"
COURSE_ID = "some/great/course" COURSE_ID = "some/great/course"
ENABLED_CACHES = ['default']
def setUp(self): def setUp(self):
super(EnrollmentTest, self).setUp() super(EnrollmentTest, self).setUp()
fake_data_api.reset() fake_data_api.reset()
cache.clear()
@ddt.data( @ddt.data(
# Default (no course modes in the database) # Default (no course modes in the database)
......
...@@ -141,6 +141,8 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase): ...@@ -141,6 +141,8 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase):
OTHER_USERNAME = "Jane" OTHER_USERNAME = "Jane"
OTHER_EMAIL = "jane@example.com" OTHER_EMAIL = "jane@example.com"
ENABLED_CACHES = ['default', 'mongo_metadata_inheritance', 'loc_cache']
def setUp(self): def setUp(self):
""" Create a course and user, then log in. """ """ Create a course and user, then log in. """
super(EnrollmentTest, self).setUp() super(EnrollmentTest, self).setUp()
...@@ -890,10 +892,12 @@ class EnrollmentEmbargoTest(EnrollmentTestMixin, UrlResetMixin, ModuleStoreTestC ...@@ -890,10 +892,12 @@ class EnrollmentEmbargoTest(EnrollmentTestMixin, UrlResetMixin, ModuleStoreTestC
EMAIL = "bob@example.com" EMAIL = "bob@example.com"
PASSWORD = "edx" PASSWORD = "edx"
URLCONF_MODULES = ['embargo']
@patch.dict(settings.FEATURES, {'EMBARGO': True}) @patch.dict(settings.FEATURES, {'EMBARGO': True})
def setUp(self): def setUp(self):
""" Create a course and user, then log in. """ """ Create a course and user, then log in. """
super(EnrollmentEmbargoTest, self).setUp('embargo') super(EnrollmentEmbargoTest, self).setUp()
self.course = CourseFactory.create() self.course = CourseFactory.create()
# Load a CourseOverview. This initial load should result in a cache # Load a CourseOverview. This initial load should result in a cache
......
...@@ -23,11 +23,12 @@ from mock import patch ...@@ -23,11 +23,12 @@ from mock import patch
from nose.plugins.attrib import attr from nose.plugins.attrib import attr
from urllib import urlencode from urllib import urlencode
from openedx.core.djangolib.testing.utils import CacheIsolationTestCase
from student.views import create_account, change_enrollment from student.views import create_account, change_enrollment
from student.models import UserProfile, CourseEnrollment from student.models import UserProfile, CourseEnrollment
from student.tests.factories import UserFactory from student.tests.factories import UserFactory
from xmodule.modulestore.tests.factories import CourseFactory from xmodule.modulestore.tests.factories import CourseFactory
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore import ModuleStoreEnum from xmodule.modulestore import ModuleStoreEnum
...@@ -76,11 +77,14 @@ def gen_all_identities(): ...@@ -76,11 +77,14 @@ def gen_all_identities():
@attr('shard_3') @attr('shard_3')
@ddt @ddt
@override_settings(SESSION_ENGINE='django.contrib.sessions.backends.cache') @override_settings(SESSION_ENGINE='django.contrib.sessions.backends.cache')
class ShibSPTest(SharedModuleStoreTestCase): class ShibSPTest(CacheIsolationTestCase):
""" """
Tests for the Shibboleth SP, which communicates via request.META Tests for the Shibboleth SP, which communicates via request.META
(Apache environment variables set by mod_shib) (Apache environment variables set by mod_shib)
""" """
ENABLED_CACHES = ['default']
request_factory = RequestFactory() request_factory = RequestFactory()
def setUp(self): def setUp(self):
...@@ -377,8 +381,23 @@ class ShibSPTest(SharedModuleStoreTestCase): ...@@ -377,8 +381,23 @@ class ShibSPTest(SharedModuleStoreTestCase):
self.assertEqual(profile.name, request2.session['ExternalAuthMap'].external_name) self.assertEqual(profile.name, request2.session['ExternalAuthMap'].external_name)
self.assertEqual(profile.name, identity.get('displayName').decode('utf-8')) self.assertEqual(profile.name, identity.get('displayName').decode('utf-8'))
@ddt
@override_settings(SESSION_ENGINE='django.contrib.sessions.backends.cache')
class ShibSPTestModifiedCourseware(ModuleStoreTestCase):
"""
Tests for the Shibboleth SP which modify the courseware
"""
ENABLED_CACHES = ['default', 'mongo_metadata_inheritance', 'loc_cache']
request_factory = RequestFactory()
def setUp(self):
super(ShibSPTestModifiedCourseware, self).setUp()
self.test_user_id = ModuleStoreEnum.UserID.test
@unittest.skipUnless(settings.FEATURES.get('AUTH_USE_SHIB'), "AUTH_USE_SHIB not set") @unittest.skipUnless(settings.FEATURES.get('AUTH_USE_SHIB'), "AUTH_USE_SHIB not set")
@SharedModuleStoreTestCase.modifies_courseware
@data(None, "", "shib:https://idp.stanford.edu/") @data(None, "", "shib:https://idp.stanford.edu/")
def test_course_specific_login_and_reg(self, domain): def test_course_specific_login_and_reg(self, domain):
""" """
...@@ -457,7 +476,6 @@ class ShibSPTest(SharedModuleStoreTestCase): ...@@ -457,7 +476,6 @@ class ShibSPTest(SharedModuleStoreTestCase):
'&enrollment_action=enroll') '&enrollment_action=enroll')
@unittest.skipUnless(settings.FEATURES.get('AUTH_USE_SHIB'), "AUTH_USE_SHIB not set") @unittest.skipUnless(settings.FEATURES.get('AUTH_USE_SHIB'), "AUTH_USE_SHIB not set")
@SharedModuleStoreTestCase.modifies_courseware
def test_enrollment_limit_by_domain(self): def test_enrollment_limit_by_domain(self):
""" """
Tests that the enrollmentDomain setting is properly limiting enrollment to those who have Tests that the enrollmentDomain setting is properly limiting enrollment to those who have
...@@ -525,7 +543,6 @@ class ShibSPTest(SharedModuleStoreTestCase): ...@@ -525,7 +543,6 @@ class ShibSPTest(SharedModuleStoreTestCase):
self.assertFalse(CourseEnrollment.is_enrolled(student, course.id)) self.assertFalse(CourseEnrollment.is_enrolled(student, course.id))
@unittest.skipUnless(settings.FEATURES.get('AUTH_USE_SHIB'), "AUTH_USE_SHIB not set") @unittest.skipUnless(settings.FEATURES.get('AUTH_USE_SHIB'), "AUTH_USE_SHIB not set")
@SharedModuleStoreTestCase.modifies_courseware
def test_shib_login_enrollment(self): def test_shib_login_enrollment(self):
""" """
A functionality test that a student with an existing shib login A functionality test that a student with an existing shib login
......
...@@ -32,6 +32,7 @@ class EnrollmentTest(UrlResetMixin, SharedModuleStoreTestCase): ...@@ -32,6 +32,7 @@ class EnrollmentTest(UrlResetMixin, SharedModuleStoreTestCase):
USERNAME = "Bob" USERNAME = "Bob"
EMAIL = "bob@example.com" EMAIL = "bob@example.com"
PASSWORD = "edx" PASSWORD = "edx"
URLCONF_MODULES = ['embargo']
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
...@@ -42,7 +43,7 @@ class EnrollmentTest(UrlResetMixin, SharedModuleStoreTestCase): ...@@ -42,7 +43,7 @@ class EnrollmentTest(UrlResetMixin, SharedModuleStoreTestCase):
@patch.dict(settings.FEATURES, {'EMBARGO': True}) @patch.dict(settings.FEATURES, {'EMBARGO': True})
def setUp(self): def setUp(self):
""" Create a course and user, then log in. """ """ Create a course and user, then log in. """
super(EnrollmentTest, self).setUp('embargo') super(EnrollmentTest, self).setUp()
self.user = UserFactory.create(username=self.USERNAME, email=self.EMAIL, password=self.PASSWORD) self.user = UserFactory.create(username=self.USERNAME, email=self.EMAIL, password=self.PASSWORD)
self.client.login(username=self.USERNAME, password=self.PASSWORD) self.client.login(username=self.USERNAME, password=self.PASSWORD)
self.course_limited.max_student_enrollments_allowed = 1 self.course_limited.max_student_enrollments_allowed = 1
......
...@@ -17,6 +17,7 @@ from mock import patch ...@@ -17,6 +17,7 @@ from mock import patch
from social.apps.django_app.default.models import UserSocialAuth from social.apps.django_app.default.models import UserSocialAuth
from external_auth.models import ExternalAuthMap from external_auth.models import ExternalAuthMap
from openedx.core.djangolib.testing.utils import CacheIsolationTestCase
from student.tests.factories import UserFactory, RegistrationFactory, UserProfileFactory from student.tests.factories import UserFactory, RegistrationFactory, UserProfileFactory
from student.views import login_oauth_token from student.views import login_oauth_token
from third_party_auth.tests.utils import ( from third_party_auth.tests.utils import (
...@@ -28,11 +29,13 @@ from xmodule.modulestore.tests.factories import CourseFactory ...@@ -28,11 +29,13 @@ from xmodule.modulestore.tests.factories import CourseFactory
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
class LoginTest(TestCase): class LoginTest(CacheIsolationTestCase):
''' '''
Test student.views.login_user() view Test student.views.login_user() view
''' '''
ENABLED_CACHES = ['default']
def setUp(self): def setUp(self):
super(LoginTest, self).setUp() super(LoginTest, self).setUp()
# Create one user and save it to the database # Create one user and save it to the database
......
...@@ -40,6 +40,8 @@ def _finish_auth_url(params): ...@@ -40,6 +40,8 @@ def _finish_auth_url(params):
class LoginFormTest(ThirdPartyAuthTestMixin, UrlResetMixin, SharedModuleStoreTestCase): class LoginFormTest(ThirdPartyAuthTestMixin, UrlResetMixin, SharedModuleStoreTestCase):
"""Test rendering of the login form. """ """Test rendering of the login form. """
URLCONF_MODULES = ['lms.urls']
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
super(LoginFormTest, cls).setUpClass() super(LoginFormTest, cls).setUpClass()
...@@ -47,7 +49,7 @@ class LoginFormTest(ThirdPartyAuthTestMixin, UrlResetMixin, SharedModuleStoreTes ...@@ -47,7 +49,7 @@ class LoginFormTest(ThirdPartyAuthTestMixin, UrlResetMixin, SharedModuleStoreTes
@patch.dict(settings.FEATURES, {"ENABLE_COMBINED_LOGIN_REGISTRATION": False}) @patch.dict(settings.FEATURES, {"ENABLE_COMBINED_LOGIN_REGISTRATION": False})
def setUp(self): def setUp(self):
super(LoginFormTest, self).setUp('lms.urls') super(LoginFormTest, self).setUp()
self.url = reverse("signin_user") self.url = reverse("signin_user")
self.course_id = unicode(self.course.id) self.course_id = unicode(self.course.id)
...@@ -155,6 +157,8 @@ class LoginFormTest(ThirdPartyAuthTestMixin, UrlResetMixin, SharedModuleStoreTes ...@@ -155,6 +157,8 @@ class LoginFormTest(ThirdPartyAuthTestMixin, UrlResetMixin, SharedModuleStoreTes
class RegisterFormTest(ThirdPartyAuthTestMixin, UrlResetMixin, SharedModuleStoreTestCase): class RegisterFormTest(ThirdPartyAuthTestMixin, UrlResetMixin, SharedModuleStoreTestCase):
"""Test rendering of the registration form. """ """Test rendering of the registration form. """
URLCONF_MODULES = ['lms.urls']
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
super(RegisterFormTest, cls).setUpClass() super(RegisterFormTest, cls).setUpClass()
...@@ -162,7 +166,7 @@ class RegisterFormTest(ThirdPartyAuthTestMixin, UrlResetMixin, SharedModuleStore ...@@ -162,7 +166,7 @@ class RegisterFormTest(ThirdPartyAuthTestMixin, UrlResetMixin, SharedModuleStore
@patch.dict(settings.FEATURES, {"ENABLE_COMBINED_LOGIN_REGISTRATION": False}) @patch.dict(settings.FEATURES, {"ENABLE_COMBINED_LOGIN_REGISTRATION": False})
def setUp(self): def setUp(self):
super(RegisterFormTest, self).setUp('lms.urls') super(RegisterFormTest, self).setUp()
self.url = reverse("register_user") self.url = reverse("register_user")
self.course_id = unicode(self.course.id) self.course_id = unicode(self.course.id)
......
...@@ -19,6 +19,7 @@ from django.utils.http import urlsafe_base64_encode, base36_to_int, int_to_base3 ...@@ -19,6 +19,7 @@ from django.utils.http import urlsafe_base64_encode, base36_to_int, int_to_base3
from mock import Mock, patch from mock import Mock, patch
import ddt import ddt
from openedx.core.djangolib.testing.utils import CacheIsolationTestCase
from student.views import password_reset, password_reset_confirm_wrapper, SETTING_CHANGE_INITIATED from student.views import password_reset, password_reset_confirm_wrapper, SETTING_CHANGE_INITIATED
from student.tests.factories import UserFactory from student.tests.factories import UserFactory
from student.tests.test_email import mock_render_to_string from student.tests.test_email import mock_render_to_string
...@@ -28,11 +29,13 @@ from .test_microsite import fake_microsite_get_value ...@@ -28,11 +29,13 @@ from .test_microsite import fake_microsite_get_value
@ddt.ddt @ddt.ddt
class ResetPasswordTests(EventTestMixin, TestCase): class ResetPasswordTests(EventTestMixin, CacheIsolationTestCase):
""" Tests that clicking reset password sends email, and doesn't activate the user """ Tests that clicking reset password sends email, and doesn't activate the user
""" """
request_factory = RequestFactory() request_factory = RequestFactory()
ENABLED_CACHES = ['default']
def setUp(self): def setUp(self):
super(ResetPasswordTests, self).setUp('student.views.tracker') super(ResetPasswordTests, self).setUp('student.views.tracker')
self.user = UserFactory.create() self.user = UserFactory.create()
......
...@@ -7,14 +7,17 @@ from django.test import TestCase ...@@ -7,14 +7,17 @@ from django.test import TestCase
from student.models import UserProfile from student.models import UserProfile
from student.tests.factories import UserFactory from student.tests.factories import UserFactory
from django.core.cache import cache from django.core.cache import cache
from openedx.core.djangolib.testing.utils import CacheIsolationTestCase
@ddt.ddt @ddt.ddt
class UserProfilePropertiesTest(TestCase): class UserProfilePropertiesTest(CacheIsolationTestCase):
"""Unit tests for age, gender_display, and level_of_education_display properties .""" """Unit tests for age, gender_display, and level_of_education_display properties ."""
password = "test" password = "test"
ENABLED_CACHES = ['default']
def setUp(self): def setUp(self):
super(UserProfilePropertiesTest, self).setUp() super(UserProfilePropertiesTest, self).setUp()
self.user = UserFactory.create(password=self.password) self.user = UserFactory.create(password=self.password)
......
...@@ -35,9 +35,11 @@ class TestCourseVerificationStatus(UrlResetMixin, ModuleStoreTestCase): ...@@ -35,9 +35,11 @@ class TestCourseVerificationStatus(UrlResetMixin, ModuleStoreTestCase):
PAST = datetime.now(UTC) - timedelta(days=5) PAST = datetime.now(UTC) - timedelta(days=5)
FUTURE = datetime.now(UTC) + timedelta(days=5) FUTURE = datetime.now(UTC) + timedelta(days=5)
URLCONF_MODULES = ['verify_student.urls']
def setUp(self): def setUp(self):
# Invoke UrlResetMixin # Invoke UrlResetMixin
super(TestCourseVerificationStatus, self).setUp('verify_student.urls') super(TestCourseVerificationStatus, self).setUp()
self.user = UserFactory(password="edx") self.user = UserFactory(password="edx")
self.course = CourseFactory.create() self.course = CourseFactory.create()
......
...@@ -26,9 +26,11 @@ class ThirdPartyOAuthTestMixin(ThirdPartyAuthTestMixin): ...@@ -26,9 +26,11 @@ class ThirdPartyOAuthTestMixin(ThirdPartyAuthTestMixin):
access_token = "test_access_token" access_token = "test_access_token"
client_id = "test_client_id" client_id = "test_client_id"
def setUp(self, create_user=True): CREATE_USER = True
def setUp(self):
super(ThirdPartyOAuthTestMixin, self).setUp() super(ThirdPartyOAuthTestMixin, self).setUp()
if create_user: if self.CREATE_USER:
self.user = UserFactory() self.user = UserFactory()
UserSocialAuth.objects.create(user=self.user, provider=self.BACKEND, uid=self.social_uid) UserSocialAuth.objects.create(user=self.user, provider=self.BACKEND, uid=self.social_uid)
self.oauth_client = self._create_client() self.oauth_client = self._create_client()
......
...@@ -29,6 +29,8 @@ class UrlResetMixin(object): ...@@ -29,6 +29,8 @@ class UrlResetMixin(object):
that affect the contents of urls.py that affect the contents of urls.py
""" """
URLCONF_MODULES = None
def _reset_urls(self, urlconf_modules): def _reset_urls(self, urlconf_modules):
"""Reset `urls.py` for a set of Django apps.""" """Reset `urls.py` for a set of Django apps."""
for urlconf in urlconf_modules: for urlconf in urlconf_modules:
...@@ -39,29 +41,29 @@ class UrlResetMixin(object): ...@@ -39,29 +41,29 @@ class UrlResetMixin(object):
# Resolve a URL so that the new urlconf gets loaded # Resolve a URL so that the new urlconf gets loaded
resolve('/') resolve('/')
def setUp(self, *args, **kwargs): def setUp(self):
"""Reset Django urls before tests and after tests """Reset Django urls before tests and after tests
If you need to reset `urls.py` from a particular Django app (or apps), If you need to reset `urls.py` from a particular Django app (or apps),
specify these modules in *args. specify these modules by setting the URLCONF_MODULES class attribute.
Examples: Examples:
# Reload only the root urls.py # Reload only the root urls.py
super(MyTestCase, self).setUp() URLCONF_MODULES = None
# Reload urls from my_app # Reload urls from my_app
super(MyTestCase, self).setUp("my_app.urls") URLCONF_MODULES = ['myapp.url']
# Reload urls from my_app and another_app # Reload urls from my_app and another_app
super(MyTestCase, self).setUp("my_app.urls", "another_app.urls") URLCONF_MODULES = ['myapp.url', 'another_app.urls']
""" """
super(UrlResetMixin, self).setUp(**kwargs) super(UrlResetMixin, self).setUp()
urlconf_modules = [settings.ROOT_URLCONF] urlconf_modules = [settings.ROOT_URLCONF]
if args: if self.URLCONF_MODULES is not None:
urlconf_modules.extend(args) urlconf_modules.extend(self.URLCONF_MODULES)
self._reset_urls(urlconf_modules) self._reset_urls(urlconf_modules)
self.addCleanup(lambda: self._reset_urls(urlconf_modules)) self.addCleanup(lambda: self._reset_urls(urlconf_modules))
......
...@@ -17,8 +17,10 @@ from util import keyword_substitution as Ks ...@@ -17,8 +17,10 @@ from util import keyword_substitution as Ks
class KeywordSubTest(ModuleStoreTestCase): class KeywordSubTest(ModuleStoreTestCase):
""" Tests for the keyword substitution feature """ """ Tests for the keyword substitution feature """
CREATE_USER = False
def setUp(self): def setUp(self):
super(KeywordSubTest, self).setUp(create_user=False) super(KeywordSubTest, self).setUp()
self.user = UserFactory.create( self.user = UserFactory.create(
email="testuser@edx.org", email="testuser@edx.org",
username="testuser", username="testuser",
......
...@@ -18,11 +18,13 @@ class MilestonesHelpersTestCase(ModuleStoreTestCase): ...@@ -18,11 +18,13 @@ class MilestonesHelpersTestCase(ModuleStoreTestCase):
Main test suite for Milestones API client library Main test suite for Milestones API client library
""" """
CREATE_USER = False
def setUp(self): def setUp(self):
""" """
Test case scaffolding Test case scaffolding
""" """
super(MilestonesHelpersTestCase, self).setUp(create_user=False) super(MilestonesHelpersTestCase, self).setUp()
self.course = CourseFactory.create( self.course = CourseFactory.create(
metadata={ metadata={
'entrance_exam_enabled': True, 'entrance_exam_enabled': True,
......
...@@ -14,11 +14,13 @@ class OrganizationsHelpersTestCase(ModuleStoreTestCase): ...@@ -14,11 +14,13 @@ class OrganizationsHelpersTestCase(ModuleStoreTestCase):
Main test suite for Organizations API client library Main test suite for Organizations API client library
""" """
CREATE_USER = False
def setUp(self): def setUp(self):
""" """
Test case scaffolding Test case scaffolding
""" """
super(OrganizationsHelpersTestCase, self).setUp(create_user=False) super(OrganizationsHelpersTestCase, self).setUp()
self.course = CourseFactory.create() self.course = CourseFactory.create()
self.organization = { self.organization = {
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
""" """
Modulestore configuration for test cases. Modulestore configuration for test cases.
""" """
import copy
import functools import functools
from uuid import uuid4 from uuid import uuid4
from contextlib import contextmanager from contextlib import contextmanager
...@@ -13,7 +14,6 @@ from django.conf import settings ...@@ -13,7 +14,6 @@ from django.conf import settings
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.test import TestCase from django.test import TestCase
from django.test.utils import override_settings from django.test.utils import override_settings
from request_cache.middleware import RequestCache
from courseware.field_overrides import OverrideFieldData # pylint: disable=import-error from courseware.field_overrides import OverrideFieldData # pylint: disable=import-error
from openedx.core.lib.tempdir import mkdtemp_clean from openedx.core.lib.tempdir import mkdtemp_clean
...@@ -25,6 +25,7 @@ from xmodule.modulestore.tests.mongo_connection import MONGO_PORT_NUM, MONGO_HOS ...@@ -25,6 +25,7 @@ from xmodule.modulestore.tests.mongo_connection import MONGO_PORT_NUM, MONGO_HOS
from xmodule.modulestore.tests.factories import XMODULE_FACTORY_LOCK from xmodule.modulestore.tests.factories import XMODULE_FACTORY_LOCK
from openedx.core.djangoapps.bookmarks.signals import trigger_update_xblocks_cache_task from openedx.core.djangoapps.bookmarks.signals import trigger_update_xblocks_cache_task
from openedx.core.djangolib.testing.utils import CacheIsolationMixin, CacheIsolationTestCase
class StoreConstructors(object): class StoreConstructors(object):
...@@ -170,23 +171,71 @@ TEST_DATA_SPLIT_MODULESTORE = mixed_store_config( ...@@ -170,23 +171,71 @@ TEST_DATA_SPLIT_MODULESTORE = mixed_store_config(
) )
def clear_all_caches(): class ModuleStoreIsolationMixin(CacheIsolationMixin):
"""Clear all caches so that cache info doesn't leak across test cases.""" """
# This will no longer be necessary when Django adds (in Django 1.10?): A mixin to be used by TestCases that want to isolate their use of the
# https://code.djangoproject.com/ticket/11505 Modulestore.
for cache in django.core.cache.caches.all():
cache.clear() How to use::
class MyTestCase(ModuleStoreMixin, TestCase):
RequestCache().clear_request_cache() MODULESTORE = <settings for the modulestore to test>
def my_test(self):
self.start_modulestore_isolation()
self.addCleanup(self.end_modulestore_isolation)
modulestore.create_course(...)
...
"""
MODULESTORE = mixed_store_config(mkdtemp_clean(), {})
ENABLED_CACHES = ['mongo_metadata_inheritance', 'loc_cache']
__settings_overrides = []
__old_modulestores = []
class SharedModuleStoreTestCase(TestCase): @classmethod
def start_modulestore_isolation(cls):
"""
Isolate uses of the modulestore after this call. Once
:py:meth:`end_modulestore_isolation` is called, this modulestore will
be flushed (all content will be deleted).
"""
cls.start_cache_isolation()
override = override_settings(
MODULESTORE=cls.MODULESTORE,
)
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()
@classmethod
def end_modulestore_isolation(cls):
"""
Delete all content in the Modulestore, and reset the Modulestore
settings from before :py:meth:`start_modulestore_isolation` was
called.
"""
drop_mongo_collections() # pylint: disable=no-value-for-parameter
XMODULE_FACTORY_LOCK.disable()
cls.__settings_overrides.pop().__exit__(None, None, None)
assert settings.MODULESTORE == cls.__old_modulestores.pop()
cls.end_cache_isolation()
class SharedModuleStoreTestCase(ModuleStoreIsolationMixin, CacheIsolationTestCase):
""" """
Subclass for any test case that uses a ModuleStore that can be shared Subclass for any test case that uses a ModuleStore that can be shared
between individual tests. This class ensures that the ModuleStore is cleaned between individual tests. This class ensures that the ModuleStore is cleaned
before/after the entire test case has run. Use this class if your tests before/after the entire test case has run. Use this class if your tests
set up one or a small number of courses that individual tests do not modify set up one or a small number of courses that individual tests do not modify.
(or modify extermely rarely -- see @modifies_courseware).
If your tests modify contents in the ModuleStore, you should use If your tests modify contents in the ModuleStore, you should use
ModuleStoreTestCase instead. ModuleStoreTestCase instead.
...@@ -218,41 +267,26 @@ class SharedModuleStoreTestCase(TestCase): ...@@ -218,41 +267,26 @@ class SharedModuleStoreTestCase(TestCase):
In Django 1.8, we will be able to use setUpTestData() to do class level init In Django 1.8, we will be able to use setUpTestData() to do class level init
for Django ORM models that will get cleaned up properly. for Django ORM models that will get cleaned up properly.
""" """
MODULESTORE = mixed_store_config(mkdtemp_clean(), {})
# Tell Django to clean out all databases, not just default # Tell Django to clean out all databases, not just default
multi_db = True multi_db = True
@classmethod @classmethod
def _setUpModuleStore(cls): # pylint: disable=invalid-name
"""
Set up the modulestore for an entire test class.
"""
cls._settings_override = override_settings(MODULESTORE=cls.MODULESTORE)
cls._settings_override.__enter__()
XMODULE_FACTORY_LOCK.enable()
clear_existing_modulestores()
cls.store = modulestore()
@classmethod
@contextmanager @contextmanager
def setUpClassAndTestData(cls): # pylint: disable=invalid-name def setUpClassAndTestData(cls): # pylint: disable=invalid-name
""" """
For use when the test class has a setUpTestData() method that uses variables For use when the test class has a setUpTestData() method that uses variables
that are setup during setUpClass() of the same test class. that are setup during setUpClass() of the same test class.
Use it like so: Use it like so:
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
with super(MyTestClass, cls).setUpClassAndTestData(): with super(MyTestClass, cls).setUpClassAndTestData():
<all the cls.setUpClass() setup code that performs modulestore setup...> <all the cls.setUpClass() setup code that performs modulestore setup...>
@classmethod @classmethod
def setUpTestData(cls): def setUpTestData(cls):
<all the setup code that creates Django models per test class...> <all the setup code that creates Django models per test class...>
<these models can use variables (courses) setup in setUpClass() above> <these models can use variables (courses) setup in setUpClass() above>
""" """
cls._setUpModuleStore() cls.start_modulestore_isolation()
# Now yield to allow the test class to run its setUpClass() setup code. # Now yield to allow the test class to run its setUpClass() setup code.
yield yield
# Now call the base class, which calls back into the test class's setUpTestData(). # Now call the base class, which calls back into the test class's setUpTestData().
...@@ -261,19 +295,15 @@ class SharedModuleStoreTestCase(TestCase): ...@@ -261,19 +295,15 @@ class SharedModuleStoreTestCase(TestCase):
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
""" """
For use when the test class has no setUpTestData() method -or- Start modulestore isolation, and then load modulestore specific
when that method does not use variable set up in setUpClass(). test data.
""" """
super(SharedModuleStoreTestCase, cls).setUpClass() super(SharedModuleStoreTestCase, cls).setUpClass()
cls._setUpModuleStore() cls.start_modulestore_isolation()
@classmethod @classmethod
def tearDownClass(cls): def tearDownClass(cls):
drop_mongo_collections() # pylint: disable=no-value-for-parameter cls.end_modulestore_isolation()
clear_all_caches()
XMODULE_FACTORY_LOCK.disable()
cls._settings_override.__exit__(None, None, None)
super(SharedModuleStoreTestCase, cls).tearDownClass() super(SharedModuleStoreTestCase, cls).tearDownClass()
def setUp(self): def setUp(self):
...@@ -282,69 +312,8 @@ class SharedModuleStoreTestCase(TestCase): ...@@ -282,69 +312,8 @@ class SharedModuleStoreTestCase(TestCase):
OverrideFieldData.provider_classes = None OverrideFieldData.provider_classes = None
super(SharedModuleStoreTestCase, self).setUp() super(SharedModuleStoreTestCase, self).setUp()
def tearDown(self):
"""Reset caches."""
clear_all_caches()
super(SharedModuleStoreTestCase, self).tearDown()
def reset(self):
"""
Manually run tearDownClass/setUpClass again.
This is so that if you have a mostly read-only course that you're just
modifying in one test, you can write `self.reset()` at the
end of that test and reset the state of the world for other tests in
the class.
"""
self.tearDownClass()
self.setUpClass()
@staticmethod class ModuleStoreTestCase(ModuleStoreIsolationMixin, TestCase):
def modifies_courseware(f):
"""
Decorator to place around tests that modify course content.
For performance reasons, SharedModuleStoreTestCase intentionally does
not reset the modulestore between individual tests. However, sometimes
you might have a test case where the vast majority of tests treat a
course as read-only, but one or two want to modify it. In that case, you
can do this:
class MyTestCase(SharedModuleStoreTestCase):
# ...
@SharedModuleStoreTestCase.modifies_courseware
def test_that_edits_modulestore(self):
do_something()
This is equivalent to calling `self.reset()` at the end of
your test.
If you find yourself using this functionality a lot, it might indicate
that you should be using ModuleStoreTestCase instead, or that you should
break up your tests into different TestCases.
"""
@functools.wraps(f)
def wrapper(*args, **kwargs):
"""Call the object method, and reset the test case afterwards."""
try:
# Attempt execution of the test.
return_val = f(*args, **kwargs)
except:
# If the test raises an exception, re-raise it.
raise
else:
# Otherwise, return the test's return value.
return return_val
finally:
# In either case, call SharedModuleStoreTestCase.reset() "on the way out."
# For more, see here: https://docs.python.org/2/tutorial/errors.html#defining-clean-up-actions.
obj = args[0]
obj.reset()
return wrapper
class ModuleStoreTestCase(TestCase):
""" """
Subclass for any test case that uses a ModuleStore. Subclass for any test case that uses a ModuleStore.
Ensures that the ModuleStore is cleaned before/after each test. Ensures that the ModuleStore is cleaned before/after each test.
...@@ -382,32 +351,19 @@ class ModuleStoreTestCase(TestCase): ...@@ -382,32 +351,19 @@ class ModuleStoreTestCase(TestCase):
your `setUp()` method. your `setUp()` method.
""" """
MODULESTORE = mixed_store_config(mkdtemp_clean(), {}) CREATE_USER = True
# Tell Django to clean out all databases, not just default # Tell Django to clean out all databases, not just default
multi_db = True multi_db = True
def setUp(self, **kwargs): def setUp(self):
""" """
Creates a test User if `create_user` is True. Creates a test User if `self.CREATE_USER` is True.
Returns the password for the test User. Sets the password as self.user_password.
Args:
create_user - specifies whether or not to create a test User. Default is True.
""" """
settings_override = override_settings(MODULESTORE=self.MODULESTORE) self.start_modulestore_isolation()
settings_override.__enter__()
self.addCleanup(settings_override.__exit__, None, None, None)
# Clear out any existing modulestores,
# which will cause them to be re-created
clear_existing_modulestores()
self.addCleanup(drop_mongo_collections) self.addCleanup(self.end_modulestore_isolation)
self.addCleanup(clear_all_caches)
# Enable XModuleFactories for the space of this test (and its setUp).
self.addCleanup(XMODULE_FACTORY_LOCK.disable)
XMODULE_FACTORY_LOCK.enable()
# When testing CCX, we should make sure that # When testing CCX, we should make sure that
# OverrideFieldData.provider_classes is always reset to `None` so # OverrideFieldData.provider_classes is always reset to `None` so
...@@ -422,11 +378,11 @@ class ModuleStoreTestCase(TestCase): ...@@ -422,11 +378,11 @@ class ModuleStoreTestCase(TestCase):
uname = 'testuser' uname = 'testuser'
email = 'test+courses@edx.org' email = 'test+courses@edx.org'
password = 'foo' self.user_password = 'foo'
if kwargs.pop('create_user', True): if self.CREATE_USER:
# Create the user so we can log them in. # Create the user so we can log them in.
self.user = User.objects.create_user(uname, email, password) self.user = User.objects.create_user(uname, email, self.user_password)
# Note that we do not actually need to do anything # Note that we do not actually need to do anything
# for registration if we directly mark them active. # for registration if we directly mark them active.
...@@ -436,8 +392,6 @@ class ModuleStoreTestCase(TestCase): ...@@ -436,8 +392,6 @@ class ModuleStoreTestCase(TestCase):
self.user.is_staff = True self.user.is_staff = True
self.user.save() self.user.save()
return password
def create_non_staff_user(self): def create_non_staff_user(self):
""" """
Creates a non-staff test user. Creates a non-staff test user.
......
...@@ -44,6 +44,8 @@ class TestEmailErrors(ModuleStoreTestCase): ...@@ -44,6 +44,8 @@ class TestEmailErrors(ModuleStoreTestCase):
Test that errors from sending email are handled properly. Test that errors from sending email are handled properly.
""" """
ENABLED_CACHES = ['default', 'mongo_metadata_inheritance', 'loc_cache']
def setUp(self): def setUp(self):
super(TestEmailErrors, self).setUp() super(TestEmailErrors, self).setUp()
course_title = u"ẗëṡẗ title イ乇丂イ ᄊ乇丂丂ムg乇 キo尺 ムレレ тэѕт мэѕѕаБэ" course_title = u"ẗëṡẗ title イ乇丂イ ᄊ乇丂丂ムg乇 キo尺 ムレレ тэѕт мэѕѕаБэ"
......
...@@ -52,6 +52,8 @@ class FieldOverridePerformanceTestCase(ProceduralCourseTestMixin, ...@@ -52,6 +52,8 @@ class FieldOverridePerformanceTestCase(ProceduralCourseTestMixin,
# TEST_DATA must be overridden by subclasses # TEST_DATA must be overridden by subclasses
TEST_DATA = None TEST_DATA = None
ENABLED_CACHES = ['default', 'mongo_metadata_inheritance', 'loc_cache']
def setUp(self): def setUp(self):
""" """
Create a test client, course, and user. Create a test client, course, and user.
......
...@@ -68,6 +68,8 @@ from lms.djangoapps.ccx.tests.utils import ( ...@@ -68,6 +68,8 @@ from lms.djangoapps.ccx.tests.utils import (
from lms.djangoapps.ccx.utils import is_email from lms.djangoapps.ccx.utils import is_email
from lms.djangoapps.ccx.views import get_date from lms.djangoapps.ccx.views import get_date
from xmodule.modulestore.django import modulestore
def intercept_renderer(path, context): def intercept_renderer(path, context):
""" """
...@@ -184,10 +186,6 @@ class TestCoachDashboard(CcxTestCase, LoginEnrollmentTestCase): ...@@ -184,10 +186,6 @@ class TestCoachDashboard(CcxTestCase, LoginEnrollmentTestCase):
Tests for Custom Courses views. Tests for Custom Courses views.
""" """
@classmethod
def setUpClass(cls):
super(TestCoachDashboard, cls).setUpClass()
def setUp(self): def setUp(self):
""" """
Set up tests Set up tests
...@@ -206,31 +204,6 @@ class TestCoachDashboard(CcxTestCase, LoginEnrollmentTestCase): ...@@ -206,31 +204,6 @@ class TestCoachDashboard(CcxTestCase, LoginEnrollmentTestCase):
allow_access(self.course, instructor, 'instructor') allow_access(self.course, instructor, 'instructor')
self.assertTrue(CourseInstructorRole(self.course.id).has_user(instructor)) self.assertTrue(CourseInstructorRole(self.course.id).has_user(instructor))
def assert_elements_in_schedule(self, url, n_chapters=2, n_sequentials=4, n_verticals=8):
"""
Helper function to count visible elements in the schedule
"""
response = self.client.get(url)
# the schedule contains chapters
chapters = json.loads(response.mako_context['schedule']) # pylint: disable=no-member
sequentials = flatten([chapter.get('children', []) for chapter in chapters])
verticals = flatten([sequential.get('children', []) for sequential in sequentials])
# check that the numbers of nodes at different level are the expected ones
self.assertEqual(n_chapters, len(chapters))
self.assertEqual(n_sequentials, len(sequentials))
self.assertEqual(n_verticals, len(verticals))
# extract the locations of all the nodes
all_elements = chapters + sequentials + verticals
return [elem['location'] for elem in all_elements if 'location' in elem]
def hide_node(self, node):
"""
Helper function to set the node `visible_to_staff_only` property
to True and save the change
"""
node.visible_to_staff_only = True
self.mstore.update_item(node, self.coach.id)
def test_not_a_coach(self): def test_not_a_coach(self):
""" """
User is not a coach, should get Forbidden response. User is not a coach, should get Forbidden response.
...@@ -352,43 +325,6 @@ class TestCoachDashboard(CcxTestCase, LoginEnrollmentTestCase): ...@@ -352,43 +325,6 @@ class TestCoachDashboard(CcxTestCase, LoginEnrollmentTestCase):
self.assertEqual(get_date(ccx, unit, 'start', parent_node=subsection), self.mooc_start) self.assertEqual(get_date(ccx, unit, 'start', parent_node=subsection), self.mooc_start)
self.assertEqual(get_date(ccx, unit, 'due', parent_node=subsection), self.mooc_due) self.assertEqual(get_date(ccx, unit, 'due', parent_node=subsection), self.mooc_due)
@SharedModuleStoreTestCase.modifies_courseware
@patch('ccx.views.render_to_response', intercept_renderer)
@patch('ccx.views.TODAY')
def test_get_ccx_schedule(self, today):
"""
Gets CCX schedule and checks number of blocks in it.
Hides nodes at a different depth and checks that these nodes
are not in the schedule.
"""
today.return_value = datetime.datetime(2014, 11, 25, tzinfo=pytz.UTC)
self.make_coach()
ccx = self.make_ccx()
url = reverse(
'ccx_coach_dashboard',
kwargs={
'course_id': CCXLocator.from_course_locator(
self.course.id, ccx.id)
}
)
# all the elements are visible
self.assert_elements_in_schedule(url)
# hide a vertical
vertical = self.verticals[0]
self.hide_node(vertical)
locations = self.assert_elements_in_schedule(url, n_verticals=7)
self.assertNotIn(unicode(vertical.location), locations)
# hide a sequential
sequential = self.sequentials[0]
self.hide_node(sequential)
locations = self.assert_elements_in_schedule(url, n_sequentials=3, n_verticals=6)
self.assertNotIn(unicode(sequential.location), locations)
# hide a chapter
chapter = self.chapters[0]
self.hide_node(chapter)
locations = self.assert_elements_in_schedule(url, n_chapters=1, n_sequentials=2, n_verticals=4)
self.assertNotIn(unicode(chapter.location), locations)
@patch('ccx.views.render_to_response', intercept_renderer) @patch('ccx.views.render_to_response', intercept_renderer)
@patch('ccx.views.TODAY') @patch('ccx.views.TODAY')
def test_edit_schedule(self, today): def test_edit_schedule(self, today):
...@@ -842,6 +778,134 @@ class TestCoachDashboard(CcxTestCase, LoginEnrollmentTestCase): ...@@ -842,6 +778,134 @@ class TestCoachDashboard(CcxTestCase, LoginEnrollmentTestCase):
) )
@attr('shard_1')
class TestCoachDashboardSchedule(CcxTestCase, LoginEnrollmentTestCase, ModuleStoreTestCase):
"""
Tests of the CCX Coach Dashboard which need to modify the course content.
"""
ENABLED_CACHES = ['default', 'mongo_inheritance_cache', 'loc_cache']
def setUp(self):
super(TestCoachDashboardSchedule, self).setUp()
self.course = course = CourseFactory.create()
# Create a course outline
self.mooc_start = start = datetime.datetime(
2010, 5, 12, 2, 42, tzinfo=pytz.UTC
)
self.mooc_due = due = datetime.datetime(
2010, 7, 7, 0, 0, tzinfo=pytz.UTC
)
self.chapters = [
ItemFactory.create(start=start, parent=course) for _ in xrange(2)
]
self.sequentials = flatten([
[
ItemFactory.create(parent=chapter) for _ in xrange(2)
] for chapter in self.chapters
])
self.verticals = flatten([
[
ItemFactory.create(
start=start, due=due, parent=sequential, graded=True, format='Homework', category=u'vertical'
) for _ in xrange(2)
] for sequential in self.sequentials
])
# Trying to wrap the whole thing in a bulk operation fails because it
# doesn't find the parents. But we can at least wrap this part...
with self.store.bulk_operations(course.id, emit_signals=False):
blocks = flatten([ # pylint: disable=unused-variable
[
ItemFactory.create(parent=vertical) for _ in xrange(2)
] for vertical in self.verticals
])
# Create instructor account
self.coach = UserFactory.create()
# create an instance of modulestore
self.mstore = modulestore()
# Login with the instructor account
self.client.login(username=self.coach.username, password="test")
# adding staff to master course.
staff = UserFactory()
allow_access(self.course, staff, 'staff')
self.assertTrue(CourseStaffRole(self.course.id).has_user(staff))
# adding instructor to master course.
instructor = UserFactory()
allow_access(self.course, instructor, 'instructor')
self.assertTrue(CourseInstructorRole(self.course.id).has_user(instructor))
self.assertTrue(modulestore().has_course(self.course.id))
def assert_elements_in_schedule(self, url, n_chapters=2, n_sequentials=4, n_verticals=8):
"""
Helper function to count visible elements in the schedule
"""
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
# the schedule contains chapters
chapters = json.loads(response.mako_context['schedule']) # pylint: disable=no-member
sequentials = flatten([chapter.get('children', []) for chapter in chapters])
verticals = flatten([sequential.get('children', []) for sequential in sequentials])
# check that the numbers of nodes at different level are the expected ones
self.assertEqual(n_chapters, len(chapters))
self.assertEqual(n_sequentials, len(sequentials))
self.assertEqual(n_verticals, len(verticals))
# extract the locations of all the nodes
all_elements = chapters + sequentials + verticals
return [elem['location'] for elem in all_elements if 'location' in elem]
def hide_node(self, node):
"""
Helper function to set the node `visible_to_staff_only` property
to True and save the change
"""
node.visible_to_staff_only = True
self.mstore.update_item(node, self.coach.id)
@patch('ccx.views.render_to_response', intercept_renderer)
@patch('ccx.views.TODAY')
def test_get_ccx_schedule(self, today):
"""
Gets CCX schedule and checks number of blocks in it.
Hides nodes at a different depth and checks that these nodes
are not in the schedule.
"""
today.return_value = datetime.datetime(2014, 11, 25, tzinfo=pytz.UTC)
self.make_coach()
ccx = self.make_ccx()
url = reverse(
'ccx_coach_dashboard',
kwargs={
'course_id': CCXLocator.from_course_locator(
self.course.id, ccx.id)
}
)
# all the elements are visible
self.assert_elements_in_schedule(url)
# hide a vertical
vertical = self.verticals[0]
self.hide_node(vertical)
locations = self.assert_elements_in_schedule(url, n_verticals=7)
self.assertNotIn(unicode(vertical.location), locations)
# hide a sequential
sequential = self.sequentials[0]
self.hide_node(sequential)
locations = self.assert_elements_in_schedule(url, n_sequentials=3, n_verticals=6)
self.assertNotIn(unicode(sequential.location), locations)
# hide a chapter
chapter = self.chapters[0]
self.hide_node(chapter)
locations = self.assert_elements_in_schedule(url, n_chapters=1, n_sequentials=2, n_verticals=4)
self.assertNotIn(unicode(chapter.location), locations)
GET_CHILDREN = XModuleMixin.get_children GET_CHILDREN = XModuleMixin.get_children
......
...@@ -12,6 +12,7 @@ from django.test.client import Client ...@@ -12,6 +12,7 @@ from django.test.client import Client
from django.test.utils import override_settings from django.test.utils import override_settings
from nose.plugins.attrib import attr from nose.plugins.attrib import attr
from opaque_keys.edx.locator import CourseLocator from opaque_keys.edx.locator import CourseLocator
from openedx.core.djangolib.testing.utils import CacheIsolationTestCase
from certificates.api import get_certificate_url from certificates.api import get_certificate_url
from certificates.models import ( from certificates.models import (
...@@ -38,7 +39,7 @@ FEATURES_WITH_CUSTOM_CERTS_ENABLED.update(FEATURES_WITH_CERTS_ENABLED) ...@@ -38,7 +39,7 @@ FEATURES_WITH_CUSTOM_CERTS_ENABLED.update(FEATURES_WITH_CERTS_ENABLED)
@attr('shard_1') @attr('shard_1')
@ddt.ddt @ddt.ddt
class UpdateExampleCertificateViewTest(TestCase): class UpdateExampleCertificateViewTest(CacheIsolationTestCase):
"""Tests for the XQueue callback that updates example certificates. """ """Tests for the XQueue callback that updates example certificates. """
COURSE_KEY = CourseLocator(org='test', course='test', run='test') COURSE_KEY = CourseLocator(org='test', course='test', run='test')
...@@ -48,6 +49,8 @@ class UpdateExampleCertificateViewTest(TestCase): ...@@ -48,6 +49,8 @@ class UpdateExampleCertificateViewTest(TestCase):
DOWNLOAD_URL = 'http://www.example.com' DOWNLOAD_URL = 'http://www.example.com'
ERROR_REASON = 'Kaboom!' ERROR_REASON = 'Kaboom!'
ENABLED_CACHES = ['default']
def setUp(self): def setUp(self):
super(UpdateExampleCertificateViewTest, self).setUp() super(UpdateExampleCertificateViewTest, self).setUp()
self.cert_set = ExampleCertificateSet.objects.create(course_key=self.COURSE_KEY) self.cert_set = ExampleCertificateSet.objects.create(course_key=self.COURSE_KEY)
......
...@@ -144,13 +144,24 @@ class TestGetCourseList(CourseListTestMixin, SharedModuleStoreTestCase): ...@@ -144,13 +144,24 @@ class TestGetCourseList(CourseListTestMixin, SharedModuleStoreTestCase):
with self.assertRaises(PermissionDenied): with self.assertRaises(PermissionDenied):
self._make_api_call(anonuser, self.staff_user) self._make_api_call(anonuser, self.staff_user)
@SharedModuleStoreTestCase.modifies_courseware
class TestGetCourseListMultipleCourses(CourseListTestMixin, ModuleStoreTestCase):
"""
Test the behavior of the `list_courses` api function (with tests that
modify the courseware).
"""
def setUp(self):
super(TestGetCourseListMultipleCourses, self).setUp()
self.course = self.create_course()
self.staff_user = self.create_user("staff", is_staff=True)
self.honor_user = self.create_user("honor", is_staff=False)
def test_multiple_courses(self): def test_multiple_courses(self):
self.create_course(course='second') self.create_course(course='second')
courses = self._make_api_call(self.honor_user, self.honor_user) courses = self._make_api_call(self.honor_user, self.honor_user)
self.assertEqual(len(courses), 2) self.assertEqual(len(courses), 2)
@SharedModuleStoreTestCase.modifies_courseware
def test_filter_by_org(self): def test_filter_by_org(self):
"""Verify that courses are filtered by the provided org key.""" """Verify that courses are filtered by the provided org key."""
# Create a second course to be filtered out of queries. # Create a second course to be filtered out of queries.
...@@ -173,7 +184,6 @@ class TestGetCourseList(CourseListTestMixin, SharedModuleStoreTestCase): ...@@ -173,7 +184,6 @@ class TestGetCourseList(CourseListTestMixin, SharedModuleStoreTestCase):
all(course.org == self.course.org for course in filtered_courses) all(course.org == self.course.org for course in filtered_courses)
) )
@SharedModuleStoreTestCase.modifies_courseware
def test_filter(self): def test_filter(self):
# Create a second course to be filtered out of queries. # Create a second course to be filtered out of queries.
alternate_course = self.create_course(course='mobile', mobile_available=True) alternate_course = self.create_course(course='mobile', mobile_available=True)
......
...@@ -7,7 +7,7 @@ from django.core.urlresolvers import reverse ...@@ -7,7 +7,7 @@ from django.core.urlresolvers import reverse
from django.test import RequestFactory from django.test import RequestFactory
from nose.plugins.attrib import attr from nose.plugins.attrib import attr
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase, ModuleStoreTestCase
from .mixins import CourseApiFactoryMixin, TEST_PASSWORD from .mixins import CourseApiFactoryMixin, TEST_PASSWORD
from ..views import CourseDetailView from ..views import CourseDetailView
...@@ -91,7 +91,24 @@ class CourseListViewTestCase(CourseApiTestViewMixin, SharedModuleStoreTestCase): ...@@ -91,7 +91,24 @@ class CourseListViewTestCase(CourseApiTestViewMixin, SharedModuleStoreTestCase):
response_to_missing_username = self.verify_response(expected_status_code=200) response_to_missing_username = self.verify_response(expected_status_code=200)
self.assertIsNotNone(response_to_missing_username.data) # pylint: disable=no-member self.assertIsNotNone(response_to_missing_username.data) # pylint: disable=no-member
@SharedModuleStoreTestCase.modifies_courseware def test_not_logged_in(self):
self.client.logout()
self.verify_response()
class CourseListViewTestCaseMultipleCourses(CourseApiTestViewMixin, ModuleStoreTestCase):
"""
Test responses returned from CourseListView (with tests that modify the
courseware).
"""
def setUp(self):
super(CourseListViewTestCaseMultipleCourses, self).setUp()
self.course = self.create_course()
self.url = reverse('course-list')
self.staff_user = self.create_user(username='staff', is_staff=True)
self.honor_user = self.create_user(username='honor', is_staff=False)
def test_filter_by_org(self): def test_filter_by_org(self):
"""Verify that CourseOverviews are filtered by the provided org key.""" """Verify that CourseOverviews are filtered by the provided org key."""
self.setup_user(self.staff_user) self.setup_user(self.staff_user)
...@@ -116,7 +133,6 @@ class CourseListViewTestCase(CourseApiTestViewMixin, SharedModuleStoreTestCase): ...@@ -116,7 +133,6 @@ class CourseListViewTestCase(CourseApiTestViewMixin, SharedModuleStoreTestCase):
all(course['org'] == self.course.org for course in filtered_response.data['results']) # pylint: disable=no-member all(course['org'] == self.course.org for course in filtered_response.data['results']) # pylint: disable=no-member
) )
@SharedModuleStoreTestCase.modifies_courseware
def test_filter(self): def test_filter(self):
self.setup_user(self.staff_user) self.setup_user(self.staff_user)
...@@ -139,10 +155,6 @@ class CourseListViewTestCase(CourseApiTestViewMixin, SharedModuleStoreTestCase): ...@@ -139,10 +155,6 @@ class CourseListViewTestCase(CourseApiTestViewMixin, SharedModuleStoreTestCase):
"testing course_api.views.CourseListView with filter_={}".format(filter_), "testing course_api.views.CourseListView with filter_={}".format(filter_),
) )
def test_not_logged_in(self):
self.client.logout()
self.verify_response()
class CourseDetailViewTestCase(CourseApiTestViewMixin, SharedModuleStoreTestCase): class CourseDetailViewTestCase(CourseApiTestViewMixin, SharedModuleStoreTestCase):
""" """
......
...@@ -15,6 +15,8 @@ class TestGenerateCourseBlocks(ModuleStoreTestCase): ...@@ -15,6 +15,8 @@ class TestGenerateCourseBlocks(ModuleStoreTestCase):
""" """
Tests generate course blocks management command. Tests generate course blocks management command.
""" """
ENABLED_CACHES = ['default', 'mongo_metadata_inheritance', 'loc_cache']
def setUp(self): def setUp(self):
""" """
Create courses in modulestore. Create courses in modulestore.
......
...@@ -15,9 +15,10 @@ class CourseBlocksSignalTest(EnableTransformerRegistryMixin, ModuleStoreTestCase ...@@ -15,9 +15,10 @@ class CourseBlocksSignalTest(EnableTransformerRegistryMixin, ModuleStoreTestCase
""" """
Tests for the Course Blocks signal Tests for the Course Blocks signal
""" """
ENABLED_CACHES = ['default', 'mongo_metadata_inheritance', 'loc_cache']
def setUp(self): def setUp(self):
super(CourseBlocksSignalTest, self).setUp(create_user=True) super(CourseBlocksSignalTest, self).setUp()
self.course = CourseFactory.create() self.course = CourseFactory.create()
self.course_usage_key = self.store.make_course_usage_key(self.course.id) self.course_usage_key = self.store.make_course_usage_key(self.course.id)
......
...@@ -36,6 +36,8 @@ class CourseStructureTestCase(TransformerRegistryTestMixin, ModuleStoreTestCase) ...@@ -36,6 +36,8 @@ class CourseStructureTestCase(TransformerRegistryTestMixin, ModuleStoreTestCase)
""" """
Helper for test cases that need to build course structures. Helper for test cases that need to build course structures.
""" """
ENABLED_CACHES = ['default', 'mongo_metadata_inheritance', 'loc_cache']
def setUp(self): def setUp(self):
""" """
Create users. Create users.
......
...@@ -56,6 +56,14 @@ class AccessResponse(object): ...@@ -56,6 +56,14 @@ class AccessResponse(object):
"user_message": self.user_message "user_message": self.user_message
} }
def __repr__(self):
return "AccessResponse({!r}, {!r}, {!r}, {!r})".format(
self.has_access,
self.error_code,
self.developer_message,
self.user_message
)
class AccessError(AccessResponse): class AccessError(AccessResponse):
""" """
......
...@@ -36,6 +36,7 @@ class CourseInfoTestCase(LoginEnrollmentTestCase, SharedModuleStoreTestCase): ...@@ -36,6 +36,7 @@ class CourseInfoTestCase(LoginEnrollmentTestCase, SharedModuleStoreTestCase):
""" """
Tests for the Course Info page Tests for the Course Info page
""" """
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
super(CourseInfoTestCase, cls).setUpClass() super(CourseInfoTestCase, cls).setUpClass()
...@@ -263,6 +264,7 @@ class SelfPacedCourseInfoTestCase(LoginEnrollmentTestCase, SharedModuleStoreTest ...@@ -263,6 +264,7 @@ class SelfPacedCourseInfoTestCase(LoginEnrollmentTestCase, SharedModuleStoreTest
""" """
Tests for the info page of self-paced courses. Tests for the info page of self-paced courses.
""" """
ENABLED_CACHES = ['default', 'mongo_metadata_inheritance', 'loc_cache']
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
......
...@@ -151,6 +151,8 @@ class TestMaxScoresCache(SharedModuleStoreTestCase): ...@@ -151,6 +151,8 @@ class TestMaxScoresCache(SharedModuleStoreTestCase):
Tests for the MaxScoresCache Tests for the MaxScoresCache
""" """
ENABLED_CACHES = ['default', 'mongo_metadata_inheritance', 'loc_cache']
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
super(TestMaxScoresCache, cls).setUpClass() super(TestMaxScoresCache, cls).setUpClass()
......
...@@ -127,6 +127,8 @@ class TestSubmittingProblems(ModuleStoreTestCase, LoginEnrollmentTestCase, Probl ...@@ -127,6 +127,8 @@ class TestSubmittingProblems(ModuleStoreTestCase, LoginEnrollmentTestCase, Probl
COURSE_SLUG = "100" COURSE_SLUG = "100"
COURSE_NAME = "test_course" COURSE_NAME = "test_course"
ENABLED_CACHES = ['default', 'mongo_metadata_inheritance', 'loc_cache']
def setUp(self): def setUp(self):
super(TestSubmittingProblems, self).setUp() super(TestSubmittingProblems, self).setUp()
......
...@@ -1014,6 +1014,8 @@ class ProgressPageTests(ModuleStoreTestCase): ...@@ -1014,6 +1014,8 @@ class ProgressPageTests(ModuleStoreTestCase):
Tests that verify that the progress page works correctly. Tests that verify that the progress page works correctly.
""" """
ENABLED_CACHES = ['default', 'mongo_modulestore_inheritance', 'loc_cache']
def setUp(self): def setUp(self):
super(ProgressPageTests, self).setUp() super(ProgressPageTests, self).setUp()
self.request_factory = RequestFactory() self.request_factory = RequestFactory()
......
...@@ -51,6 +51,8 @@ class TestGitAddCourse(SharedModuleStoreTestCase): ...@@ -51,6 +51,8 @@ class TestGitAddCourse(SharedModuleStoreTestCase):
TEST_BRANCH_COURSE = SlashSeparatedCourseKey('MITx', 'edx4edx_branch', 'edx4edx') TEST_BRANCH_COURSE = SlashSeparatedCourseKey('MITx', 'edx4edx_branch', 'edx4edx')
GIT_REPO_DIR = settings.GIT_REPO_DIR GIT_REPO_DIR = settings.GIT_REPO_DIR
ENABLED_CACHES = ['default', 'mongo_metadata_inheritance', 'loc_cache']
def assertCommandFailureRegexp(self, regex, *args): def assertCommandFailureRegexp(self, regex, *args):
""" """
Convenience function for testing command failures Convenience function for testing command failures
......
...@@ -10,7 +10,6 @@ from django.test.client import RequestFactory ...@@ -10,7 +10,6 @@ from django.test.client import RequestFactory
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core.management import call_command from django.core.management import call_command
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from request_cache.middleware import RequestCache
from mock import patch, ANY, Mock from mock import patch, ANY, Mock
from nose.tools import assert_true, assert_equal from nose.tools import assert_true, assert_equal
from nose.plugins.attrib import attr from nose.plugins.attrib import attr
...@@ -24,8 +23,9 @@ from django_comment_client.tests.utils import CohortedTestCase ...@@ -24,8 +23,9 @@ from django_comment_client.tests.utils import CohortedTestCase
from django_comment_client.tests.unicode import UnicodeTestMixin from django_comment_client.tests.unicode import UnicodeTestMixin
from django_comment_common.models import Role from django_comment_common.models import Role
from django_comment_common.utils import seed_permissions_roles, ThreadContext from django_comment_common.utils import seed_permissions_roles, ThreadContext
from student.tests.factories import CourseEnrollmentFactory, UserFactory, CourseAccessRoleFactory
from lms.djangoapps.teams.tests.factories import CourseTeamFactory, CourseTeamMembershipFactory from lms.djangoapps.teams.tests.factories import CourseTeamFactory, CourseTeamMembershipFactory
from student.tests.factories import CourseEnrollmentFactory, UserFactory, CourseAccessRoleFactory
from util.testing import UrlResetMixin from util.testing import UrlResetMixin
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase, SharedModuleStoreTestCase from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase, SharedModuleStoreTestCase
...@@ -350,15 +350,12 @@ class ViewsTestCaseMixin(object): ...@@ -350,15 +350,12 @@ class ViewsTestCaseMixin(object):
@disable_signal(views, 'thread_edited') @disable_signal(views, 'thread_edited')
class ViewsQueryCountTestCase(UrlResetMixin, ModuleStoreTestCase, MockRequestSetupMixin, ViewsTestCaseMixin): class ViewsQueryCountTestCase(UrlResetMixin, ModuleStoreTestCase, MockRequestSetupMixin, ViewsTestCaseMixin):
CREATE_USER = False
ENABLED_CACHES = ['default', 'mongo_metadata_inheritance', 'loc_cache']
@patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) @patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True})
def setUp(self): def setUp(self):
super(ViewsQueryCountTestCase, self).setUp(create_user=False) super(ViewsQueryCountTestCase, self).setUp()
def clear_caches(self):
"""Clears caches so that query count numbers are accurate."""
for cache in settings.CACHES:
caches[cache].clear()
RequestCache.clear_request_cache()
def count_queries(func): # pylint: disable=no-self-argument def count_queries(func): # pylint: disable=no-self-argument
""" """
......
...@@ -220,8 +220,11 @@ class PartialDictMatcher(object): ...@@ -220,8 +220,11 @@ class PartialDictMatcher(object):
@patch('requests.request', autospec=True) @patch('requests.request', autospec=True)
class SingleThreadTestCase(ModuleStoreTestCase): class SingleThreadTestCase(ModuleStoreTestCase):
CREATE_USER = False
def setUp(self): def setUp(self):
super(SingleThreadTestCase, self).setUp(create_user=False) super(SingleThreadTestCase, self).setUp()
self.course = CourseFactory.create(discussion_topics={'dummy discussion': {'id': 'dummy_discussion_id'}}) self.course = CourseFactory.create(discussion_topics={'dummy discussion': {'id': 'dummy_discussion_id'}})
self.student = UserFactory.create() self.student = UserFactory.create()
...@@ -1223,6 +1226,9 @@ class UserProfileTestCase(ModuleStoreTestCase): ...@@ -1223,6 +1226,9 @@ class UserProfileTestCase(ModuleStoreTestCase):
@patch('requests.request', autospec=True) @patch('requests.request', autospec=True)
class CommentsServiceRequestHeadersTestCase(UrlResetMixin, ModuleStoreTestCase): class CommentsServiceRequestHeadersTestCase(UrlResetMixin, ModuleStoreTestCase):
CREATE_USER = False
@patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) @patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True})
def setUp(self): def setUp(self):
super(CommentsServiceRequestHeadersTestCase, self).setUp() super(CommentsServiceRequestHeadersTestCase, self).setUp()
...@@ -1231,7 +1237,7 @@ class CommentsServiceRequestHeadersTestCase(UrlResetMixin, ModuleStoreTestCase): ...@@ -1231,7 +1237,7 @@ class CommentsServiceRequestHeadersTestCase(UrlResetMixin, ModuleStoreTestCase):
password = "bar" password = "bar"
# Invoke UrlResetMixin # Invoke UrlResetMixin
super(CommentsServiceRequestHeadersTestCase, self).setUp(create_user=False) super(CommentsServiceRequestHeadersTestCase, self).setUp()
self.course = CourseFactory.create(discussion_topics={'dummy discussion': {'id': 'dummy_discussion_id'}}) self.course = CourseFactory.create(discussion_topics={'dummy discussion': {'id': 'dummy_discussion_id'}})
self.student = UserFactory.create(username=username, password=password) self.student = UserFactory.create(username=username, password=password)
CourseEnrollmentFactory.create(user=self.student, course_id=self.course.id) CourseEnrollmentFactory.create(user=self.student, course_id=self.course.id)
......
...@@ -63,8 +63,10 @@ class AccessUtilsTestCase(ModuleStoreTestCase): ...@@ -63,8 +63,10 @@ class AccessUtilsTestCase(ModuleStoreTestCase):
Base testcase class for access and roles for the Base testcase class for access and roles for the
comment client service integration comment client service integration
""" """
CREATE_USER = False
def setUp(self): def setUp(self):
super(AccessUtilsTestCase, self).setUp(create_user=False) super(AccessUtilsTestCase, self).setUp()
self.course = CourseFactory.create() self.course = CourseFactory.create()
self.course_id = self.course.id self.course_id = self.course.id
...@@ -118,7 +120,7 @@ class CoursewareContextTestCase(ModuleStoreTestCase): ...@@ -118,7 +120,7 @@ class CoursewareContextTestCase(ModuleStoreTestCase):
comment client service integration comment client service integration
""" """
def setUp(self): def setUp(self):
super(CoursewareContextTestCase, self).setUp(create_user=True) super(CoursewareContextTestCase, self).setUp()
self.course = CourseFactory.create(org="TestX", number="101", display_name="Test Course") self.course = CourseFactory.create(org="TestX", number="101", display_name="Test Course")
self.discussion1 = ItemFactory.create( self.discussion1 = ItemFactory.create(
...@@ -206,7 +208,7 @@ class CachedDiscussionIdMapTestCase(ModuleStoreTestCase): ...@@ -206,7 +208,7 @@ class CachedDiscussionIdMapTestCase(ModuleStoreTestCase):
Tests that using the cache of discussion id mappings has the same behavior as searching through the course. Tests that using the cache of discussion id mappings has the same behavior as searching through the course.
""" """
def setUp(self): def setUp(self):
super(CachedDiscussionIdMapTestCase, self).setUp(create_user=True) super(CachedDiscussionIdMapTestCase, self).setUp()
self.course = CourseFactory.create(org='TestX', number='101', display_name='Test Course') self.course = CourseFactory.create(org='TestX', number='101', display_name='Test Course')
self.discussion = ItemFactory.create( self.discussion = ItemFactory.create(
...@@ -340,7 +342,7 @@ class CategoryMapTestCase(CategoryMapTestMixin, ModuleStoreTestCase): ...@@ -340,7 +342,7 @@ class CategoryMapTestCase(CategoryMapTestMixin, ModuleStoreTestCase):
comment client service integration comment client service integration
""" """
def setUp(self): def setUp(self):
super(CategoryMapTestCase, self).setUp(create_user=True) super(CategoryMapTestCase, self).setUp()
self.course = CourseFactory.create( self.course = CourseFactory.create(
org="TestX", number="101", display_name="Test Course", org="TestX", number="101", display_name="Test Course",
......
...@@ -51,7 +51,7 @@ from student.models import ( ...@@ -51,7 +51,7 @@ from student.models import (
) )
from student.tests.factories import UserFactory, CourseModeFactory, AdminFactory from student.tests.factories import UserFactory, CourseModeFactory, AdminFactory
from student.roles import CourseBetaTesterRole, CourseSalesAdminRole, CourseFinanceAdminRole, CourseInstructorRole from student.roles import CourseBetaTesterRole, CourseSalesAdminRole, CourseFinanceAdminRole, CourseInstructorRole
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase, ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
from xmodule.fields import Date from xmodule.fields import Date
...@@ -3968,27 +3968,6 @@ class TestDueDateExtensions(SharedModuleStoreTestCase, LoginEnrollmentTestCase): ...@@ -3968,27 +3968,6 @@ class TestDueDateExtensions(SharedModuleStoreTestCase, LoginEnrollmentTestCase):
}) })
self.assertEqual(response.status_code, 400, response.content) self.assertEqual(response.status_code, 400, response.content)
@SharedModuleStoreTestCase.modifies_courseware
def test_reset_extension_to_deleted_date(self):
"""
Test that we can delete a due date extension after deleting the normal
due date, without causing an error.
"""
self.test_change_due_date()
self.week1.due = None
self.week1 = self.store.update_item(self.week1, self.user1.id)
# Now, week1's normal due date is deleted but the extension still exists.
url = reverse('reset_due_date', kwargs={'course_id': self.course.id.to_deprecated_string()})
response = self.client.get(url, {
'student': self.user1.username,
'url': self.week1.location.to_deprecated_string(),
})
self.assertEqual(response.status_code, 200, response.content)
self.assertEqual(
None,
get_extended_due(self.course, self.week1, self.user1)
)
def test_show_unit_extensions(self): def test_show_unit_extensions(self):
self.test_change_due_date() self.test_change_due_date()
url = reverse('show_unit_extensions', url = reverse('show_unit_extensions',
...@@ -4018,6 +3997,114 @@ class TestDueDateExtensions(SharedModuleStoreTestCase, LoginEnrollmentTestCase): ...@@ -4018,6 +3997,114 @@ class TestDueDateExtensions(SharedModuleStoreTestCase, LoginEnrollmentTestCase):
@attr('shard_1') @attr('shard_1')
class TestDueDateExtensionsDeletedDate(ModuleStoreTestCase, LoginEnrollmentTestCase):
def setUp(self):
"""
Fixtures.
"""
super(TestDueDateExtensionsDeletedDate, self).setUp()
self.course = CourseFactory.create()
self.due = datetime.datetime(2010, 5, 12, 2, 42, tzinfo=utc)
with self.store.bulk_operations(self.course.id, emit_signals=False):
self.week1 = ItemFactory.create(due=self.due)
self.week2 = ItemFactory.create(due=self.due)
self.week3 = ItemFactory.create() # No due date
self.course.children = [
self.week1.location.to_deprecated_string(),
self.week2.location.to_deprecated_string(),
self.week3.location.to_deprecated_string()
]
self.homework = ItemFactory.create(
parent_location=self.week1.location,
due=self.due
)
self.week1.children = [self.homework.location.to_deprecated_string()]
user1 = UserFactory.create()
StudentModule(
state='{}',
student_id=user1.id,
course_id=self.course.id,
module_state_key=self.week1.location).save()
StudentModule(
state='{}',
student_id=user1.id,
course_id=self.course.id,
module_state_key=self.week2.location).save()
StudentModule(
state='{}',
student_id=user1.id,
course_id=self.course.id,
module_state_key=self.week3.location).save()
StudentModule(
state='{}',
student_id=user1.id,
course_id=self.course.id,
module_state_key=self.homework.location).save()
user2 = UserFactory.create()
StudentModule(
state='{}',
student_id=user2.id,
course_id=self.course.id,
module_state_key=self.week1.location).save()
StudentModule(
state='{}',
student_id=user2.id,
course_id=self.course.id,
module_state_key=self.homework.location).save()
user3 = UserFactory.create()
StudentModule(
state='{}',
student_id=user3.id,
course_id=self.course.id,
module_state_key=self.week1.location).save()
StudentModule(
state='{}',
student_id=user3.id,
course_id=self.course.id,
module_state_key=self.homework.location).save()
self.user1 = user1
self.user2 = user2
self.instructor = InstructorFactory(course_key=self.course.id)
self.client.login(username=self.instructor.username, password='test')
def test_reset_extension_to_deleted_date(self):
"""
Test that we can delete a due date extension after deleting the normal
due date, without causing an error.
"""
url = reverse('change_due_date', kwargs={'course_id': self.course.id.to_deprecated_string()})
response = self.client.get(url, {
'student': self.user1.username,
'url': self.week1.location.to_deprecated_string(),
'due_datetime': '12/30/2013 00:00'
})
self.assertEqual(response.status_code, 200, response.content)
self.assertEqual(datetime.datetime(2013, 12, 30, 0, 0, tzinfo=utc),
get_extended_due(self.course, self.week1, self.user1))
self.week1.due = None
self.week1 = self.store.update_item(self.week1, self.user1.id)
# Now, week1's normal due date is deleted but the extension still exists.
url = reverse('reset_due_date', kwargs={'course_id': self.course.id.to_deprecated_string()})
response = self.client.get(url, {
'student': self.user1.username,
'url': self.week1.location.to_deprecated_string(),
})
self.assertEqual(response.status_code, 200, response.content)
self.assertEqual(
None,
get_extended_due(self.course, self.week1, self.user1)
)
@attr('shard_1')
class TestCourseIssuedCertificatesData(SharedModuleStoreTestCase): class TestCourseIssuedCertificatesData(SharedModuleStoreTestCase):
""" """
Test data dumps for issued certificates. Test data dumps for issued certificates.
......
...@@ -1683,6 +1683,9 @@ class TestCertificateGeneration(InstructorTaskModuleTestCase): ...@@ -1683,6 +1683,9 @@ class TestCertificateGeneration(InstructorTaskModuleTestCase):
""" """
Test certificate generation task works. Test certificate generation task works.
""" """
ENABLED_CACHES = ['default', 'mongo_metadata_inheritance', 'loc_cache']
def setUp(self): def setUp(self):
super(TestCertificateGeneration, self).setUp() super(TestCertificateGeneration, self).setUp()
self.initialize_course() self.initialize_course()
......
...@@ -10,18 +10,21 @@ import mock ...@@ -10,18 +10,21 @@ import mock
from pytz import UTC from pytz import UTC
from mobile_api.middleware import AppVersionUpgrade from mobile_api.middleware import AppVersionUpgrade
from mobile_api.models import AppVersionConfig from mobile_api.models import AppVersionConfig
from openedx.core.djangolib.testing.utils import CacheIsolationTestCase
@ddt.ddt @ddt.ddt
class TestAppVersionUpgradeMiddleware(TestCase): class TestAppVersionUpgradeMiddleware(CacheIsolationTestCase):
""" """
Tests for version based app upgrade middleware Tests for version based app upgrade middleware
""" """
ENABLED_CACHES = ['default']
def setUp(self): def setUp(self):
super(TestAppVersionUpgradeMiddleware, self).setUp() super(TestAppVersionUpgradeMiddleware, self).setUp()
self.middleware = AppVersionUpgrade() self.middleware = AppVersionUpgrade()
self.set_app_version_config() self.set_app_version_config()
cache.clear()
def set_app_version_config(self): def set_app_version_config(self):
""" Creates configuration data for platform versions """ """ Creates configuration data for platform versions """
......
...@@ -1707,6 +1707,9 @@ class RegistrationCodeRedemptionCourseEnrollment(SharedModuleStoreTestCase): ...@@ -1707,6 +1707,9 @@ class RegistrationCodeRedemptionCourseEnrollment(SharedModuleStoreTestCase):
""" """
Test suite for RegistrationCodeRedemption Course Enrollments Test suite for RegistrationCodeRedemption Course Enrollments
""" """
ENABLED_CACHES = ['default', 'mongo_metadata_inheritance', 'loc_cache']
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
super(RegistrationCodeRedemptionCourseEnrollment, cls).setUpClass() super(RegistrationCodeRedemptionCourseEnrollment, cls).setUpClass()
...@@ -1843,9 +1846,11 @@ class RedeemCodeEmbargoTests(UrlResetMixin, ModuleStoreTestCase): ...@@ -1843,9 +1846,11 @@ class RedeemCodeEmbargoTests(UrlResetMixin, ModuleStoreTestCase):
USERNAME = 'bob' USERNAME = 'bob'
PASSWORD = 'test' PASSWORD = 'test'
URLCONF_MODULES = ['embargo']
@patch.dict(settings.FEATURES, {'EMBARGO': True}) @patch.dict(settings.FEATURES, {'EMBARGO': True})
def setUp(self): def setUp(self):
super(RedeemCodeEmbargoTests, self).setUp('embargo') super(RedeemCodeEmbargoTests, self).setUp()
self.course = CourseFactory.create() self.course = CourseFactory.create()
self.user = UserFactory.create(username=self.USERNAME, password=self.PASSWORD) self.user = UserFactory.create(username=self.USERNAME, password=self.PASSWORD)
result = self.client.login(username=self.user.username, password=self.PASSWORD) result = self.client.login(username=self.user.username, password=self.PASSWORD)
......
...@@ -22,6 +22,7 @@ from course_modes.models import CourseMode ...@@ -22,6 +22,7 @@ from course_modes.models import CourseMode
from openedx.core.djangoapps.user_api.accounts.api import activate_account, create_account from openedx.core.djangoapps.user_api.accounts.api import activate_account, create_account
from openedx.core.djangoapps.user_api.accounts import EMAIL_MAX_LENGTH from openedx.core.djangoapps.user_api.accounts import EMAIL_MAX_LENGTH
from openedx.core.djangolib.js_utils import dump_js_escaped_json from openedx.core.djangolib.js_utils import dump_js_escaped_json
from openedx.core.djangolib.testing.utils import CacheIsolationTestCase
from student.tests.factories import UserFactory from student.tests.factories import UserFactory
from student_account.views import account_settings_context from student_account.views import account_settings_context
from third_party_auth.tests.testutil import simulate_running_pipeline, ThirdPartyAuthTestMixin from third_party_auth.tests.testutil import simulate_running_pipeline, ThirdPartyAuthTestMixin
...@@ -31,7 +32,7 @@ from openedx.core.djangoapps.theming.test_util import with_edx_domain_context ...@@ -31,7 +32,7 @@ from openedx.core.djangoapps.theming.test_util import with_edx_domain_context
@ddt.ddt @ddt.ddt
class StudentAccountUpdateTest(UrlResetMixin, TestCase): class StudentAccountUpdateTest(CacheIsolationTestCase, UrlResetMixin):
""" Tests for the student account views that update the user's account information. """ """ Tests for the student account views that update the user's account information. """
USERNAME = u"heisenberg" USERNAME = u"heisenberg"
...@@ -62,8 +63,12 @@ class StudentAccountUpdateTest(UrlResetMixin, TestCase): ...@@ -62,8 +63,12 @@ class StudentAccountUpdateTest(UrlResetMixin, TestCase):
INVALID_KEY = u"123abc" INVALID_KEY = u"123abc"
URLCONF_MODULES = ['student_accounts.urls']
ENABLED_CACHES = ['default']
def setUp(self): def setUp(self):
super(StudentAccountUpdateTest, self).setUp("student_account.urls") super(StudentAccountUpdateTest, self).setUp()
# Create/activate a new account # Create/activate a new account
activation_key = create_account(self.USERNAME, self.OLD_PASSWORD, self.OLD_EMAIL) activation_key = create_account(self.USERNAME, self.OLD_PASSWORD, self.OLD_EMAIL)
...@@ -213,9 +218,11 @@ class StudentAccountLoginAndRegistrationTest(ThirdPartyAuthTestMixin, UrlResetMi ...@@ -213,9 +218,11 @@ class StudentAccountLoginAndRegistrationTest(ThirdPartyAuthTestMixin, UrlResetMi
EMAIL = "bob@example.com" EMAIL = "bob@example.com"
PASSWORD = "password" PASSWORD = "password"
URLCONF_MODULES = ['embargo']
@mock.patch.dict(settings.FEATURES, {'EMBARGO': True}) @mock.patch.dict(settings.FEATURES, {'EMBARGO': True})
def setUp(self): def setUp(self):
super(StudentAccountLoginAndRegistrationTest, self).setUp('embargo') super(StudentAccountLoginAndRegistrationTest, self).setUp()
# For these tests, three third party auth providers are enabled by default: # For these tests, three third party auth providers are enabled by default:
self.configure_google_provider(enabled=True) self.configure_google_provider(enabled=True)
......
...@@ -14,10 +14,13 @@ class SoftwareSecureFakeViewTest(UrlResetMixin, TestCase): ...@@ -14,10 +14,13 @@ class SoftwareSecureFakeViewTest(UrlResetMixin, TestCase):
""" """
Base class to test the fake software secure view. Base class to test the fake software secure view.
""" """
URLCONF_MODULES = ['verify_student.urls']
def setUp(self, **kwargs): def setUp(self, **kwargs):
enable_software_secure_fake = kwargs.get('enable_software_secure_fake', False) enable_software_secure_fake = kwargs.get('enable_software_secure_fake', False)
with patch.dict('django.conf.settings.FEATURES', {'ENABLE_SOFTWARE_SECURE_FAKE': enable_software_secure_fake}): with patch.dict('django.conf.settings.FEATURES', {'ENABLE_SOFTWARE_SECURE_FAKE': enable_software_secure_fake}):
super(SoftwareSecureFakeViewTest, self).setUp('verify_student.urls') super(SoftwareSecureFakeViewTest, self).setUp()
self.user = UserFactory.create(username="test", password="test") self.user = UserFactory.create(username="test", password="test")
self.attempt = SoftwareSecurePhotoVerification.objects.create(user=self.user) self.attempt = SoftwareSecurePhotoVerification.objects.create(user=self.user)
......
...@@ -18,6 +18,7 @@ from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase ...@@ -18,6 +18,7 @@ from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory from xmodule.modulestore.tests.factories import CourseFactory
from opaque_keys.edx.keys import CourseKey from opaque_keys.edx.keys import CourseKey
from openedx.core.djangolib.testing.utils import CacheIsolationTestCase
from lms.djangoapps.verify_student.models import ( from lms.djangoapps.verify_student.models import (
SoftwareSecurePhotoVerification, SoftwareSecurePhotoVerification,
...@@ -844,11 +845,13 @@ class SkippedReverificationTest(ModuleStoreTestCase): ...@@ -844,11 +845,13 @@ class SkippedReverificationTest(ModuleStoreTestCase):
) )
class VerificationDeadlineTest(TestCase): class VerificationDeadlineTest(CacheIsolationTestCase):
""" """
Tests for the VerificationDeadline model. Tests for the VerificationDeadline model.
""" """
ENABLED_CACHES = ['default']
def test_caching(self): def test_caching(self):
deadlines = { deadlines = {
CourseKey.from_string("edX/DemoX/Fall"): datetime.now(pytz.UTC), CourseKey.from_string("edX/DemoX/Fall"): datetime.now(pytz.UTC),
......
...@@ -104,9 +104,11 @@ class TestPayAndVerifyView(UrlResetMixin, ModuleStoreTestCase, XssTestMixin): ...@@ -104,9 +104,11 @@ class TestPayAndVerifyView(UrlResetMixin, ModuleStoreTestCase, XssTestMixin):
YESTERDAY = NOW - timedelta(days=1) YESTERDAY = NOW - timedelta(days=1)
TOMORROW = NOW + timedelta(days=1) TOMORROW = NOW + timedelta(days=1)
URLCONF_MODULES = ['embargo']
@mock.patch.dict(settings.FEATURES, {'EMBARGO': True}) @mock.patch.dict(settings.FEATURES, {'EMBARGO': True})
def setUp(self): def setUp(self):
super(TestPayAndVerifyView, self).setUp('embargo') super(TestPayAndVerifyView, self).setUp()
self.user = UserFactory.create(username=self.USERNAME, password=self.PASSWORD) self.user = UserFactory.create(username=self.USERNAME, password=self.PASSWORD)
result = self.client.login(username=self.USERNAME, password=self.PASSWORD) result = self.client.login(username=self.USERNAME, password=self.PASSWORD)
self.assertTrue(result, msg="Could not log in") self.assertTrue(result, msg="Could not log in")
......
...@@ -203,9 +203,7 @@ CACHES = { ...@@ -203,9 +203,7 @@ CACHES = {
# This is the cache used for most things. # This is the cache used for most things.
# In staging/prod envs, the sessions also live here. # In staging/prod envs, the sessions also live here.
'default': { 'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', 'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
'LOCATION': 'edx_loc_mem_cache',
'KEY_FUNCTION': 'util.memcache.safe_key',
}, },
# The general cache is what you get if you use our util.cache. It's used for # The general cache is what you get if you use our util.cache. It's used for
...@@ -215,20 +213,13 @@ CACHES = { ...@@ -215,20 +213,13 @@ CACHES = {
# push process. # push process.
'general': { 'general': {
'BACKEND': 'django.core.cache.backends.dummy.DummyCache', 'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
'KEY_PREFIX': 'general',
'VERSION': 4,
'KEY_FUNCTION': 'util.memcache.safe_key',
}, },
'mongo_metadata_inheritance': { 'mongo_metadata_inheritance': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', 'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
'LOCATION': os.path.join(tempfile.gettempdir(), 'mongo_metadata_inheritance'),
'TIMEOUT': 300,
'KEY_FUNCTION': 'util.memcache.safe_key',
}, },
'loc_cache': { 'loc_cache': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', 'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
'LOCATION': 'edx_location_mem_cache',
}, },
'course_structure_cache': { 'course_structure_cache': {
'BACKEND': 'django.core.cache.backends.dummy.DummyCache', 'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
......
...@@ -40,6 +40,8 @@ class BookmarksTestsBase(ModuleStoreTestCase): ...@@ -40,6 +40,8 @@ class BookmarksTestsBase(ModuleStoreTestCase):
STORE_TYPE = ModuleStoreEnum.Type.mongo STORE_TYPE = ModuleStoreEnum.Type.mongo
TEST_PASSWORD = 'test' TEST_PASSWORD = 'test'
ENABLED_CACHES = ['default', 'mongo_metadata_inheritance', 'loc_cache']
def setUp(self): def setUp(self):
super(BookmarksTestsBase, self).setUp() super(BookmarksTestsBase, self).setUp()
......
...@@ -16,6 +16,8 @@ class CourseStructureApiTests(ModuleStoreTestCase): ...@@ -16,6 +16,8 @@ class CourseStructureApiTests(ModuleStoreTestCase):
""" """
MOCK_CACHE = "openedx.core.djangoapps.content.course_structures.api.v0.api.cache" MOCK_CACHE = "openedx.core.djangoapps.content.course_structures.api.v0.api.cache"
ENABLED_CACHES = ['default', 'mongo_metadata_inheritance', 'loc_cache']
def setUp(self): def setUp(self):
""" """
Test setup Test setup
......
...@@ -16,16 +16,20 @@ from openedx.core.djangoapps.credentials.utils import ( ...@@ -16,16 +16,20 @@ from openedx.core.djangoapps.credentials.utils import (
) )
from openedx.core.djangoapps.programs.tests.mixins import ProgramsApiConfigMixin, ProgramsDataMixin from openedx.core.djangoapps.programs.tests.mixins import ProgramsApiConfigMixin, ProgramsDataMixin
from openedx.core.djangoapps.programs.models import ProgramsApiConfig from openedx.core.djangoapps.programs.models import ProgramsApiConfig
from openedx.core.djangolib.testing.utils import CacheIsolationTestCase
from student.tests.factories import UserFactory from student.tests.factories import UserFactory
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
@attr('shard_2') @attr('shard_2')
class TestCredentialsRetrieval(ProgramsApiConfigMixin, CredentialsApiConfigMixin, CredentialsDataMixin, class TestCredentialsRetrieval(ProgramsApiConfigMixin, CredentialsApiConfigMixin, CredentialsDataMixin,
ProgramsDataMixin, TestCase): ProgramsDataMixin, CacheIsolationTestCase):
""" Tests covering the retrieval of user credentials from the Credentials """ Tests covering the retrieval of user credentials from the Credentials
service. service.
""" """
ENABLED_CACHES = ['default']
def setUp(self): def setUp(self):
super(TestCredentialsRetrieval, self).setUp() super(TestCredentialsRetrieval, self).setUp()
......
...@@ -56,6 +56,8 @@ class CreditApiTestBase(ModuleStoreTestCase): ...@@ -56,6 +56,8 @@ class CreditApiTestBase(ModuleStoreTestCase):
Base class for test cases of the credit API. Base class for test cases of the credit API.
""" """
ENABLED_CACHES = ['default', 'mongo_metadata_inheritance', 'loc_cache']
PROVIDER_ID = "hogwarts" PROVIDER_ID = "hogwarts"
PROVIDER_NAME = "Hogwarts School of Witchcraft and Wizardry" PROVIDER_NAME = "Hogwarts School of Witchcraft and Wizardry"
PROVIDER_URL = "https://credit.example.com/request" PROVIDER_URL = "https://credit.example.com/request"
......
...@@ -31,6 +31,7 @@ class ReverificationPartitionTest(ModuleStoreTestCase): ...@@ -31,6 +31,7 @@ class ReverificationPartitionTest(ModuleStoreTestCase):
SUBMITTED = "submitted" SUBMITTED = "submitted"
APPROVED = "approved" APPROVED = "approved"
DENIED = "denied" DENIED = "denied"
ENABLED_CACHES = ['default', 'mongo_metadata_inheritance', 'loc_cache']
def setUp(self): def setUp(self):
super(ReverificationPartitionTest, self).setUp() super(ReverificationPartitionTest, self).setUp()
......
...@@ -17,6 +17,7 @@ from openedx.core.djangoapps.programs import utils ...@@ -17,6 +17,7 @@ from openedx.core.djangoapps.programs import utils
from openedx.core.djangoapps.programs.models import ProgramsApiConfig from openedx.core.djangoapps.programs.models import ProgramsApiConfig
from openedx.core.djangoapps.programs.tests import factories from openedx.core.djangoapps.programs.tests import factories
from openedx.core.djangoapps.programs.tests.mixins import ProgramsApiConfigMixin, ProgramsDataMixin from openedx.core.djangoapps.programs.tests.mixins import ProgramsApiConfigMixin, ProgramsDataMixin
from openedx.core.djangolib.testing.utils import CacheIsolationTestCase
from student.tests.factories import UserFactory, CourseEnrollmentFactory from student.tests.factories import UserFactory, CourseEnrollmentFactory
...@@ -26,8 +27,11 @@ UTILS_MODULE = 'openedx.core.djangoapps.programs.utils' ...@@ -26,8 +27,11 @@ UTILS_MODULE = 'openedx.core.djangoapps.programs.utils'
@skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') @skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
@attr('shard_2') @attr('shard_2')
class TestProgramRetrieval(ProgramsApiConfigMixin, ProgramsDataMixin, class TestProgramRetrieval(ProgramsApiConfigMixin, ProgramsDataMixin,
CredentialsApiConfigMixin, TestCase): CredentialsApiConfigMixin, CacheIsolationTestCase):
"""Tests covering the retrieval of programs from the Programs service.""" """Tests covering the retrieval of programs from the Programs service."""
ENABLED_CACHES = ['default']
def setUp(self): def setUp(self):
super(TestProgramRetrieval, self).setUp() super(TestProgramRetrieval, self).setUp()
......
...@@ -25,6 +25,7 @@ from student.tests.factories import UserFactory ...@@ -25,6 +25,7 @@ from student.tests.factories import UserFactory
from student.models import UserProfile, LanguageProficiency, PendingEmailChange from student.models import UserProfile, LanguageProficiency, PendingEmailChange
from openedx.core.djangoapps.user_api.accounts import ACCOUNT_VISIBILITY_PREF_KEY from openedx.core.djangoapps.user_api.accounts import ACCOUNT_VISIBILITY_PREF_KEY
from openedx.core.djangoapps.user_api.preferences.api import set_user_preference from openedx.core.djangoapps.user_api.preferences.api import set_user_preference
from openedx.core.djangolib.testing.utils import CacheIsolationTestCase
from .. import PRIVATE_VISIBILITY, ALL_USERS_VISIBILITY from .. import PRIVATE_VISIBILITY, ALL_USERS_VISIBILITY
TEST_PROFILE_IMAGE_UPLOADED_AT = datetime.datetime(2002, 1, 9, 15, 43, 01, tzinfo=UTC) TEST_PROFILE_IMAGE_UPLOADED_AT = datetime.datetime(2002, 1, 9, 15, 43, 01, tzinfo=UTC)
...@@ -121,10 +122,13 @@ class UserAPITestCase(APITestCase): ...@@ -121,10 +122,13 @@ class UserAPITestCase(APITestCase):
clear=True clear=True
) )
@attr('shard_2') @attr('shard_2')
class TestAccountAPI(UserAPITestCase): class TestAccountAPI(CacheIsolationTestCase, UserAPITestCase):
""" """
Unit tests for the Account API. Unit tests for the Account API.
""" """
ENABLED_CACHES = ['default']
def setUp(self): def setUp(self):
super(TestAccountAPI, self).setUp() super(TestAccountAPI, self).setUp()
...@@ -244,7 +248,7 @@ class TestAccountAPI(UserAPITestCase): ...@@ -244,7 +248,7 @@ class TestAccountAPI(UserAPITestCase):
""" """
self.different_client.login(username=self.different_user.username, password=self.test_password) self.different_client.login(username=self.different_user.username, password=self.test_password)
self.create_mock_profile(self.user) self.create_mock_profile(self.user)
with self.assertNumQueries(11): with self.assertNumQueries(14):
response = self.send_get(self.different_client) response = self.send_get(self.different_client)
self._verify_full_shareable_account_response(response, account_privacy=ALL_USERS_VISIBILITY) self._verify_full_shareable_account_response(response, account_privacy=ALL_USERS_VISIBILITY)
...@@ -259,7 +263,7 @@ class TestAccountAPI(UserAPITestCase): ...@@ -259,7 +263,7 @@ class TestAccountAPI(UserAPITestCase):
""" """
self.different_client.login(username=self.different_user.username, password=self.test_password) self.different_client.login(username=self.different_user.username, password=self.test_password)
self.create_mock_profile(self.user) self.create_mock_profile(self.user)
with self.assertNumQueries(11): with self.assertNumQueries(14):
response = self.send_get(self.different_client) response = self.send_get(self.different_client)
self._verify_private_account_response(response, account_privacy=PRIVATE_VISIBILITY) self._verify_private_account_response(response, account_privacy=PRIVATE_VISIBILITY)
...@@ -307,11 +311,11 @@ class TestAccountAPI(UserAPITestCase): ...@@ -307,11 +311,11 @@ class TestAccountAPI(UserAPITestCase):
Test that a client (logged in) can get her own account information (using default legacy profile information, Test that a client (logged in) can get her own account information (using default legacy profile information,
as created by the test UserFactory). as created by the test UserFactory).
""" """
def verify_get_own_information(): def verify_get_own_information(queries):
""" """
Internal helper to perform the actual assertions Internal helper to perform the actual assertions
""" """
with self.assertNumQueries(9): with self.assertNumQueries(queries):
response = self.send_get(self.client) response = self.send_get(self.client)
data = response.data data = response.data
self.assertEqual(17, len(data)) self.assertEqual(17, len(data))
...@@ -333,12 +337,12 @@ class TestAccountAPI(UserAPITestCase): ...@@ -333,12 +337,12 @@ class TestAccountAPI(UserAPITestCase):
self.assertEqual(False, data["accomplishments_shared"]) self.assertEqual(False, data["accomplishments_shared"])
self.client.login(username=self.user.username, password=self.test_password) self.client.login(username=self.user.username, password=self.test_password)
verify_get_own_information() verify_get_own_information(12)
# Now make sure that the user can get the same information, even if not active # Now make sure that the user can get the same information, even if not active
self.user.is_active = False self.user.is_active = False
self.user.save() self.user.save()
verify_get_own_information() verify_get_own_information(9)
def test_get_account_empty_string(self): def test_get_account_empty_string(self):
""" """
...@@ -352,7 +356,7 @@ class TestAccountAPI(UserAPITestCase): ...@@ -352,7 +356,7 @@ class TestAccountAPI(UserAPITestCase):
legacy_profile.save() legacy_profile.save()
self.client.login(username=self.user.username, password=self.test_password) self.client.login(username=self.user.username, password=self.test_password)
with self.assertNumQueries(9): with self.assertNumQueries(12):
response = self.send_get(self.client) response = self.send_get(self.client)
for empty_field in ("level_of_education", "gender", "country", "bio"): for empty_field in ("level_of_education", "gender", "country", "bio"):
self.assertIsNone(response.data[empty_field]) self.assertIsNone(response.data[empty_field])
......
...@@ -20,6 +20,7 @@ from social.apps.django_app.default.models import UserSocialAuth ...@@ -20,6 +20,7 @@ from social.apps.django_app.default.models import UserSocialAuth
from django_comment_common import models from django_comment_common import models
from openedx.core.lib.api.test_utils import ApiTestCase, TEST_API_KEY from openedx.core.lib.api.test_utils import ApiTestCase, TEST_API_KEY
from openedx.core.djangolib.testing.utils import CacheIsolationTestCase
from student.tests.factories import UserFactory from student.tests.factories import UserFactory
from third_party_auth.tests.testutil import simulate_running_pipeline, ThirdPartyAuthTestMixin from third_party_auth.tests.testutil import simulate_running_pipeline, ThirdPartyAuthTestMixin
from third_party_auth.tests.utils import ( from third_party_auth.tests.utils import (
...@@ -334,12 +335,14 @@ class UserViewSetTest(UserApiTestCase): ...@@ -334,12 +335,14 @@ class UserViewSetTest(UserApiTestCase):
) )
class UserPreferenceViewSetTest(UserApiTestCase): class UserPreferenceViewSetTest(CacheIsolationTestCase, UserApiTestCase):
""" """
Test cases covering the User Preference DRF view class and its various behaviors Test cases covering the User Preference DRF view class and its various behaviors
""" """
LIST_URI = USER_PREFERENCE_LIST_URI LIST_URI = USER_PREFERENCE_LIST_URI
ENABLED_CACHES = ['default']
def setUp(self): def setUp(self):
super(UserPreferenceViewSetTest, self).setUp() super(UserPreferenceViewSetTest, self).setUp()
self.detail_uri = self.get_uri_for_pref(self.prefs[0]) self.detail_uri = self.get_uri_for_pref(self.prefs[0])
...@@ -1725,12 +1728,18 @@ class RegistrationViewTest(ThirdPartyAuthTestMixin, UserAPITestCase): ...@@ -1725,12 +1728,18 @@ class RegistrationViewTest(ThirdPartyAuthTestMixin, UserAPITestCase):
@httpretty.activate @httpretty.activate
@ddt.ddt @ddt.ddt
class ThirdPartyRegistrationTestMixin(ThirdPartyOAuthTestMixin): class ThirdPartyRegistrationTestMixin(ThirdPartyOAuthTestMixin, CacheIsolationTestCase):
""" """
Tests for the User API registration endpoint with 3rd party authentication. Tests for the User API registration endpoint with 3rd party authentication.
""" """
CREATE_USER = False
ENABLED_CACHES = ['default']
__test__ = False
def setUp(self): def setUp(self):
super(ThirdPartyRegistrationTestMixin, self).setUp(create_user=False) super(ThirdPartyRegistrationTestMixin, self).setUp()
self.url = reverse('user_api_registration') self.url = reverse('user_api_registration')
def data(self, user=None): def data(self, user=None):
...@@ -1845,6 +1854,8 @@ class TestFacebookRegistrationView( ...@@ -1845,6 +1854,8 @@ class TestFacebookRegistrationView(
ThirdPartyRegistrationTestMixin, ThirdPartyOAuthTestMixinFacebook, TransactionTestCase ThirdPartyRegistrationTestMixin, ThirdPartyOAuthTestMixinFacebook, TransactionTestCase
): ):
"""Tests the User API registration endpoint with Facebook authentication.""" """Tests the User API registration endpoint with Facebook authentication."""
__test__ = True
def test_social_auth_exception(self): def test_social_auth_exception(self):
""" """
According to the do_auth method in social.backends.facebook.py, According to the do_auth method in social.backends.facebook.py,
...@@ -1861,6 +1872,8 @@ class TestGoogleRegistrationView( ...@@ -1861,6 +1872,8 @@ class TestGoogleRegistrationView(
ThirdPartyRegistrationTestMixin, ThirdPartyOAuthTestMixinGoogle, TransactionTestCase ThirdPartyRegistrationTestMixin, ThirdPartyOAuthTestMixinGoogle, TransactionTestCase
): ):
"""Tests the User API registration endpoint with Google authentication.""" """Tests the User API registration endpoint with Google authentication."""
__test__ = True
pass pass
......
"""
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
from django.contrib import sites
from request_cache.middleware import RequestCache
class CacheIsolationMixin(object):
"""
This class can be used to enable specific django caches for
specific the TestCase that it's mixed into.
Usage:
Use the ENABLED_CACHES to list the names of caches that should
be enabled in the context of this TestCase. These caches will
use a loc_mem_cache with the default settings.
Set the class variable CACHES to explicitly specify the cache settings
that should be overridden. This class will insert those values into
django.conf.settings, and will reset all named caches before each
test.
If both CACHES and ENABLED_CACHES are not None, raises an error.
"""
CACHES = None
ENABLED_CACHES = None
__settings_overrides = []
__old_settings = []
@classmethod
def start_cache_isolation(cls):
"""
Start cache isolation by overriding the settings.CACHES and
flushing the cache.
"""
cache_settings = None
if cls.CACHES is not None and cls.ENABLED_CACHES is not None:
raise Exception(
"Use either CACHES or ENABLED_CACHES, but not both"
)
if cls.CACHES is not None:
cache_settings = cls.CACHES
elif cls.ENABLED_CACHES is not None:
cache_settings = {
'default': {
'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
}
}
cache_settings.update({
cache_name: {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
'LOCATION': cache_name,
'KEY_FUNCTION': 'util.memcache.safe_key',
} for cache_name in cls.ENABLED_CACHES
})
if cache_settings is None:
return
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()
@classmethod
def end_cache_isolation(cls):
"""
End cache isolation by flushing the cache and then returning
settings.CACHES to its original state.
"""
# Make sure that cache contents don't leak out after the isolation is ended
cls.clear_caches()
if cls.__settings_overrides:
cls.__settings_overrides.pop().__exit__(None, None, None)
assert settings.CACHES == cls.__old_settings.pop()
@classmethod
def clear_caches(cls):
"""
Clear all of the caches defined in settings.CACHES.
"""
# N.B. As of 2016-04-20, Django won't return any caches
# from django.core.cache.caches.all() that haven't been
# accessed using caches[name] previously, so we loop
# over our list of overridden caches, instead.
for cache in settings.CACHES:
caches[cache].clear()
# The sites framework caches in a module-level dictionary.
# Clear that.
sites.models.SITE_CACHE.clear()
RequestCache.clear_request_cache()
class CacheIsolationTestCase(CacheIsolationMixin, TestCase):
"""
A TestCase that isolates caches (as described in
:py:class:`CacheIsolationMixin`) at class setup, and flushes the cache
between every test.
"""
@classmethod
def setUpClass(cls):
super(CacheIsolationTestCase, cls).setUpClass()
cls.start_cache_isolation()
@classmethod
def tearDownClass(cls):
cls.end_cache_isolation()
super(CacheIsolationTestCase, cls).tearDownClass()
def setUp(self):
super(CacheIsolationTestCase, self).setUp()
self.clear_caches()
self.addCleanup(self.clear_caches)
...@@ -15,6 +15,7 @@ from openedx.core.djangoapps.credentials.models import CredentialsApiConfig ...@@ -15,6 +15,7 @@ from openedx.core.djangoapps.credentials.models import CredentialsApiConfig
from openedx.core.djangoapps.credentials.tests.mixins import CredentialsApiConfigMixin, CredentialsDataMixin from openedx.core.djangoapps.credentials.tests.mixins import CredentialsApiConfigMixin, CredentialsDataMixin
from openedx.core.djangoapps.programs.models import ProgramsApiConfig from openedx.core.djangoapps.programs.models import ProgramsApiConfig
from openedx.core.djangoapps.programs.tests.mixins import ProgramsApiConfigMixin, ProgramsDataMixin from openedx.core.djangoapps.programs.tests.mixins import ProgramsApiConfigMixin, ProgramsDataMixin
from openedx.core.djangolib.testing.utils import CacheIsolationTestCase
from openedx.core.lib.edx_api_utils import get_edx_api_data from openedx.core.lib.edx_api_utils import get_edx_api_data
from student.tests.factories import UserFactory from student.tests.factories import UserFactory
...@@ -24,8 +25,11 @@ LOGGER_NAME = 'openedx.core.lib.edx_api_utils' ...@@ -24,8 +25,11 @@ LOGGER_NAME = 'openedx.core.lib.edx_api_utils'
@attr('shard_2') @attr('shard_2')
class TestApiDataRetrieval(CredentialsApiConfigMixin, CredentialsDataMixin, ProgramsApiConfigMixin, ProgramsDataMixin, class TestApiDataRetrieval(CredentialsApiConfigMixin, CredentialsDataMixin, ProgramsApiConfigMixin, ProgramsDataMixin,
TestCase): CacheIsolationTestCase):
"""Test utility for API data retrieval.""" """Test utility for API data retrieval."""
ENABLED_CACHES = ['default']
def setUp(self): def setUp(self):
super(TestApiDataRetrieval, self).setUp() super(TestApiDataRetrieval, self).setUp()
ClientFactory(name=CredentialsApiConfig.OAUTH2_CLIENT_NAME, client_type=CONFIDENTIAL) ClientFactory(name=CredentialsApiConfig.OAUTH2_CLIENT_NAME, client_type=CONFIDENTIAL)
......
...@@ -169,6 +169,7 @@ selenium==2.53.1 ...@@ -169,6 +169,7 @@ selenium==2.53.1
splinter==0.5.4 splinter==0.5.4
testtools==0.9.34 testtools==0.9.34
testfixtures==4.5.0 testfixtures==4.5.0
nose-faulthandler==0.1
# Used for Segment analytics # Used for Segment analytics
analytics-python==1.1.0 analytics-python==1.1.0
......
...@@ -102,16 +102,16 @@ case "$TEST_SUITE" in ...@@ -102,16 +102,16 @@ case "$TEST_SUITE" in
paver test_system -s lms --extra_args="--with-flaky" --cov_args="-p" paver test_system -s lms --extra_args="--with-flaky" --cov_args="-p"
;; ;;
"1") "1")
paver test_system -s lms --extra_args="--attr='shard_1' --with-flaky" --cov_args="-p" paver test_system -s lms --extra_args="--attr='shard_1' --with-flaky" --cov_args="-p" -v
;; ;;
"2") "2")
paver test_system -s lms --extra_args="--attr='shard_2' --with-flaky" --cov_args="-p" paver test_system -s lms --extra_args="--attr='shard_2' --with-flaky" --cov_args="-p" -v
;; ;;
"3") "3")
paver test_system -s lms --extra_args="--attr='shard_3' --with-flaky" --cov_args="-p" paver test_system -s lms --extra_args="--attr='shard_3' --with-flaky" --cov_args="-p" -v
;; ;;
"4") "4")
paver test_system -s lms --extra_args="--attr='shard_1=False,shard_2=False,shard_3=False' --with-flaky" --cov_args="-p" paver test_system -s lms --extra_args="--attr='shard_1=False,shard_2=False,shard_3=False' --with-flaky" --cov_args="-p" -v
;; ;;
*) *)
# If no shard is specified, rather than running all tests, create an empty xunit file. This is a # If no shard is specified, rather than running all tests, create an empty xunit file. This is a
...@@ -125,11 +125,11 @@ case "$TEST_SUITE" in ...@@ -125,11 +125,11 @@ case "$TEST_SUITE" in
;; ;;
"cms-unit") "cms-unit")
paver test_system -s cms --extra_args="--with-flaky" --cov_args="-p" paver test_system -s cms --extra_args="--with-flaky" --cov_args="-p" -v
;; ;;
"commonlib-unit") "commonlib-unit")
paver test_lib --extra_args="--with-flaky" --cov_args="-p" paver test_lib --extra_args="--with-flaky" --cov_args="-p" -v
;; ;;
"js-unit") "js-unit")
......
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