Commit 853bfe7a by Calen Pennington

Add a TestCase mixin for enabling caches in tests

By default, disable all caching in tests, to preserve test independence.
In order to enable caching, inherit from CacheSetupMixin, and specify
which cache configuration is needed.

[EV-32]
parent 18e16100
...@@ -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
......
...@@ -88,8 +88,9 @@ class ContentStoreTestCase(ModuleStoreTestCase): ...@@ -88,8 +88,9 @@ 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 CREATE_USER = False
ENABLED_CACHES = ['default', 'mongo_metadata_inheritance', 'loc_cache']
def setUp(self): def setUp(self):
super(AuthTestCase, self).setUp() super(AuthTestCase, self).setUp()
......
...@@ -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()
...@@ -239,16 +241,13 @@ class EmbargoMessageUrlApiTests(UrlResetMixin, ModuleStoreTestCase): ...@@ -239,16 +241,13 @@ 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'] 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() 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/')
......
...@@ -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,6 +33,8 @@ class CourseAccessMessageViewTest(UrlResetMixin, TestCase): ...@@ -32,6 +33,8 @@ class CourseAccessMessageViewTest(UrlResetMixin, TestCase):
""" """
ENABLED_CACHES = ['default']
URLCONF_MODULES = ['embargo'] URLCONF_MODULES = ['embargo']
@patch.dict(settings.FEATURES, {'EMBARGO': True}) @patch.dict(settings.FEATURES, {'EMBARGO': True})
......
...@@ -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()
......
...@@ -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
......
...@@ -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
......
...@@ -158,7 +158,7 @@ class RegisterFormTest(ThirdPartyAuthTestMixin, UrlResetMixin, SharedModuleStore ...@@ -158,7 +158,7 @@ class RegisterFormTest(ThirdPartyAuthTestMixin, UrlResetMixin, SharedModuleStore
"""Test rendering of the registration form. """ """Test rendering of the registration form. """
URLCONF_MODULES = ['lms.urls'] URLCONF_MODULES = ['lms.urls']
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
super(RegisterFormTest, cls).setUpClass() super(RegisterFormTest, cls).setUpClass()
......
...@@ -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)
......
...@@ -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,6 +15,7 @@ class CourseBlocksSignalTest(EnableTransformerRegistryMixin, ModuleStoreTestCase ...@@ -15,6 +15,7 @@ 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() super(CourseBlocksSignalTest, self).setUp()
......
...@@ -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.
......
...@@ -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()
......
...@@ -970,6 +970,8 @@ class ProgressPageTests(ModuleStoreTestCase): ...@@ -970,6 +970,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
...@@ -351,17 +351,12 @@ class ViewsTestCaseMixin(object): ...@@ -351,17 +351,12 @@ class ViewsTestCaseMixin(object):
class ViewsQueryCountTestCase(UrlResetMixin, ModuleStoreTestCase, MockRequestSetupMixin, ViewsTestCaseMixin): class ViewsQueryCountTestCase(UrlResetMixin, ModuleStoreTestCase, MockRequestSetupMixin, ViewsTestCaseMixin):
CREATE_USER = False 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() 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
""" """
Decorates test methods to count mongo and SQL calls for a Decorates test methods to count mongo and SQL calls for a
......
...@@ -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()
......
...@@ -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"
...@@ -64,6 +65,8 @@ class StudentAccountUpdateTest(UrlResetMixin, TestCase): ...@@ -64,6 +65,8 @@ class StudentAccountUpdateTest(UrlResetMixin, TestCase):
URLCONF_MODULES = ['student_accounts.urls'] URLCONF_MODULES = ['student_accounts.urls']
ENABLED_CACHES = ['default']
def setUp(self): def setUp(self):
super(StudentAccountUpdateTest, self).setUp() super(StudentAccountUpdateTest, self).setUp()
......
...@@ -14,7 +14,7 @@ class SoftwareSecureFakeViewTest(UrlResetMixin, TestCase): ...@@ -14,7 +14,7 @@ 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'] URLCONF_MODULES = ['verify_student.urls']
def setUp(self, **kwargs): def setUp(self, **kwargs):
......
...@@ -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),
......
...@@ -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()
......
...@@ -55,6 +55,8 @@ class CreditApiTestBase(ModuleStoreTestCase): ...@@ -55,6 +55,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,16 @@ class RegistrationViewTest(ThirdPartyAuthTestMixin, UserAPITestCase): ...@@ -1725,12 +1728,16 @@ 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 CREATE_USER = False
ENABLED_CACHES = ['default']
__test__ = False
def setUp(self): def setUp(self):
super(ThirdPartyRegistrationTestMixin, self).setUp() super(ThirdPartyRegistrationTestMixin, self).setUp()
self.url = reverse('user_api_registration') self.url = reverse('user_api_registration')
...@@ -1847,6 +1854,8 @@ class TestFacebookRegistrationView( ...@@ -1847,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,
...@@ -1863,6 +1872,8 @@ class TestGoogleRegistrationView( ...@@ -1863,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
......
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_override = None
@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.__settings_override = override_settings(CACHES=cache_settings)
cls.__settings_override.__enter__()
# 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_override is not None:
cls.__settings_override.__exit__(None, None, None)
cls.__settings_override = None
@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)
......
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