diff --git a/common/djangoapps/util/tests/test_django_utils.py b/common/djangoapps/util/tests/test_django_utils.py new file mode 100644 index 0000000000..bd0dc846ef --- /dev/null +++ b/common/djangoapps/util/tests/test_django_utils.py @@ -0,0 +1,53 @@ +""" +THE TESTS IN THIS MODULE SHOULD BE RUN ON THE SAME PROCESS TO BE MEANINGFUL!!! + +The tests in this module look kind of goofy, but the idea is to make sure that +cache values can't leak between different TestCase classes and methods. The need +for this will go away whenever Django merges the fix to reset the caches between +tests (https://code.djangoproject.com/ticket/11505). +""" +from django.core.cache import caches + +from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase, SharedModuleStoreTestCase + + +class CacheCheckMixin(object): + """Base mixin that does our cache check.""" + + def check_caches(self, key): + """Check that caches are empty, and add values.""" + for cache in caches.all(): + self.assertIsNone(cache.get(key)) + cache.set(key, "Not None") + + +class CacheModuleStoreTestCaseParent(ModuleStoreTestCase, CacheCheckMixin): + """Make sure that we're clearing cache values between tests.""" + + def test_cache_reset_1(self): + """Check to make sure cache is empty, and add values to it.""" + self.check_caches("mstc_cache_test_key") + + def test_cache_reset_2(self): + """Check to make sure cache is empty, and add values to it.""" + self.check_caches("mstc_cache_test_key") + + +class CacheModuleStoreTestCaseChild(CacheModuleStoreTestCaseParent): # pylint: disable=test-inherits-tests + """Make sure that we're clearing cache values between classes.""" + + +class CacheSharedModuleStoreTestCaseParent(SharedModuleStoreTestCase, CacheCheckMixin): + """Make sure that we're clearing cache values between tests.""" + + def test_cache_reset_1(self): + """Check to make sure cache is empty, and add values to it.""" + self.check_caches("smstc_cache_test_key") + + def test_cache_reset_2(self): + """Check to make sure cache is empty, and add values to it.""" + self.check_caches("smstc_cache_test_key") + + +class CacheSharedModuleStoreTestCaseChild(CacheSharedModuleStoreTestCaseParent): # pylint: disable=test-inherits-tests + """Make sure that we're clearing cache values between classes.""" diff --git a/common/lib/xmodule/xmodule/modulestore/tests/django_utils.py b/common/lib/xmodule/xmodule/modulestore/tests/django_utils.py index 8d3224db2a..5ed4ce201e 100644 --- a/common/lib/xmodule/xmodule/modulestore/tests/django_utils.py +++ b/common/lib/xmodule/xmodule/modulestore/tests/django_utils.py @@ -7,6 +7,7 @@ from uuid import uuid4 from mock import patch +import django.core.cache from django.conf import settings from django.contrib.auth.models import User from django.test import TestCase @@ -215,6 +216,16 @@ TEST_DATA_SPLIT_MODULESTORE = mixed_store_config( ) +def clear_all_caches(): + """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?): + # https://code.djangoproject.com/ticket/11505 + for cache in django.core.cache.caches.all(): + cache.clear() + + RequestCache().clear_request_cache() + + class SharedModuleStoreTestCase(TestCase): """ Subclass for any test case that uses a ModuleStore that can be shared @@ -268,7 +279,7 @@ class SharedModuleStoreTestCase(TestCase): @classmethod def tearDownClass(cls): drop_mongo_collections() # pylint: disable=no-value-for-parameter - RequestCache().clear_request_cache() + clear_all_caches() XMODULE_FACTORY_LOCK.disable() cls._settings_override.__exit__(None, None, None) @@ -280,6 +291,11 @@ class SharedModuleStoreTestCase(TestCase): OverrideFieldData.provider_classes = None super(SharedModuleStoreTestCase, self).setUp() + def tearDown(self): + """Reset caches.""" + clear_all_caches() + super(SharedModuleStoreTestCase, self).tearDown() + def reset(self): """ Manually run tearDownClass/setUpClass again. @@ -394,7 +410,7 @@ class ModuleStoreTestCase(TestCase): clear_existing_modulestores() self.addCleanup(drop_mongo_collections) - self.addCleanup(RequestCache().clear_request_cache) + self.addCleanup(clear_all_caches) # Enable XModuleFactories for the space of this test (and its setUp). self.addCleanup(XMODULE_FACTORY_LOCK.disable) diff --git a/lms/djangoapps/course_structure_api/v0/tests.py b/lms/djangoapps/course_structure_api/v0/tests.py index 08224e521a..726db58583 100644 --- a/lms/djangoapps/course_structure_api/v0/tests.py +++ b/lms/djangoapps/course_structure_api/v0/tests.py @@ -520,7 +520,7 @@ class CourseBlocksOrNavigationTestMixin(CourseDetailTestMixin, CourseViewTestsMi return 'course_structure_api:v0:' + self.block_navigation_view_type def test_get(self): - with check_mongo_calls(3): + with check_mongo_calls(4): response = super(CourseBlocksOrNavigationTestMixin, self).test_get() # verify root element diff --git a/lms/djangoapps/courseware/tests/test_views.py b/lms/djangoapps/courseware/tests/test_views.py index 001af735a2..5914b83671 100644 --- a/lms/djangoapps/courseware/tests/test_views.py +++ b/lms/djangoapps/courseware/tests/test_views.py @@ -950,7 +950,7 @@ class ProgressPageTests(ModuleStoreTestCase): self.assertContains(resp, u"Download Your Certificate") @ddt.data( - *itertools.product(((38, 4, True), (38, 4, False)), (True, False)) + *itertools.product(((40, 4, True), (40, 4, False)), (True, False)) ) @ddt.unpack def test_query_counts(self, (sql_calls, mongo_calls, self_paced), self_paced_enabled): diff --git a/lms/djangoapps/instructor_task/tests/test_tasks_helper.py b/lms/djangoapps/instructor_task/tests/test_tasks_helper.py index 1d7fbe2ca4..e50e756a05 100644 --- a/lms/djangoapps/instructor_task/tests/test_tasks_helper.py +++ b/lms/djangoapps/instructor_task/tests/test_tasks_helper.py @@ -1628,7 +1628,7 @@ class TestCertificateGeneration(InstructorTaskModuleTestCase): current_task.update_state = Mock() instructor_task = Mock() instructor_task.task_input = json.dumps({'students': None}) - with self.assertNumQueries(213): + with self.assertNumQueries(214): with patch('instructor_task.tasks_helper._get_current_task') as mock_current_task: mock_current_task.return_value = current_task with patch('capa.xqueue_interface.XQueueInterface.send_to_queue') as mock_queue: diff --git a/openedx/core/djangoapps/bookmarks/tests/test_views.py b/openedx/core/djangoapps/bookmarks/tests/test_views.py index 2468422914..f86ac56174 100644 --- a/openedx/core/djangoapps/bookmarks/tests/test_views.py +++ b/openedx/core/djangoapps/bookmarks/tests/test_views.py @@ -95,7 +95,7 @@ class BookmarksListViewTests(BookmarksViewsTestsBase): if check_all_fields: query_parameters += '&fields=path,display_name' - with self.assertNumQueries(9): # 2 queries for bookmark table. + with self.assertNumQueries(12): # 2 queries for bookmark table. response = self.send_get( client=self.client, url=reverse('bookmarks'), @@ -138,7 +138,7 @@ class BookmarksListViewTests(BookmarksViewsTestsBase): page_size = 5 query_parameters = 'course_id={}&page_size={}'.format(urllib.quote(unicode(course.id)), page_size) - with self.assertNumQueries(9): # 2 queries for bookmark table. + with self.assertNumQueries(12): # 2 queries for bookmark table. response = self.send_get( client=self.client, url=reverse('bookmarks'), @@ -171,15 +171,15 @@ class BookmarksListViewTests(BookmarksViewsTestsBase): Test that requesting bookmarks with invalid data returns 0 records. """ # Invalid course id. - with self.assertNumQueries(7): # No queries for bookmark table. + with self.assertNumQueries(10): # No queries for bookmark table. response = self.send_get( client=self.client, url=reverse('bookmarks'), query_parameters='course_id=invalid' ) bookmarks_data = response.data['results'] - self.assertEqual(len(bookmarks_data), 0) + self.assertEqual(len(bookmarks_data), 0) self.assertFalse(mock_tracker.emit.called) # pylint: disable=maybe-no-member @patch('eventtracking.tracker.emit') @@ -189,7 +189,7 @@ class BookmarksListViewTests(BookmarksViewsTestsBase): """ # Without course id we would return all the bookmarks for that user. - with self.assertNumQueries(9): # 2 queries for bookmark table. + with self.assertNumQueries(12): # 2 queries for bookmark table. response = self.send_get( client=self.client, url=reverse('bookmarks') @@ -214,7 +214,7 @@ class BookmarksListViewTests(BookmarksViewsTestsBase): Test that an anonymous client (not logged in) cannot call GET or POST. """ query_parameters = 'course_id={}'.format(self.course_id) - with self.assertNumQueries(4): # No queries for bookmark table. + with self.assertNumQueries(7): # No queries for bookmark table. self.send_get( client=self.anonymous_client, url=reverse('bookmarks'), @@ -234,7 +234,7 @@ class BookmarksListViewTests(BookmarksViewsTestsBase): """ Test that posting a bookmark successfully returns newly created data with 201 code. """ - with self.assertNumQueries(16): + with self.assertNumQueries(19): response = self.send_post( client=self.client, url=reverse('bookmarks'), @@ -258,7 +258,7 @@ class BookmarksListViewTests(BookmarksViewsTestsBase): 3) With empty request.data """ # Send usage_id with invalid format. - with self.assertNumQueries(7): # No queries for bookmark table. + with self.assertNumQueries(10): # No queries for bookmark table. response = self.send_post( client=self.client, url=reverse('bookmarks'), @@ -293,7 +293,7 @@ class BookmarksListViewTests(BookmarksViewsTestsBase): """ Test that posting a bookmark for a block that does not exist returns a 400. """ - with self.assertNumQueries(7): # No queries for bookmark table. + with self.assertNumQueries(10): # No queries for bookmark table. response = self.send_post( client=self.client, url=reverse('bookmarks'), @@ -317,7 +317,7 @@ class BookmarksListViewTests(BookmarksViewsTestsBase): max_bookmarks = settings.MAX_BOOKMARKS_PER_COURSE __, blocks, __ = self.create_course_with_bookmarks_count(max_bookmarks) - with self.assertNumQueries(8): # No queries for bookmark table. + with self.assertNumQueries(11): # No queries for bookmark table. response = self.send_post( client=self.client, url=reverse('bookmarks'), @@ -397,7 +397,7 @@ class BookmarksDetailViewTests(BookmarksViewsTestsBase): """ Test that requesting bookmark returns data with 200 code. """ - with self.assertNumQueries(8): # 1 query for bookmark table. + with self.assertNumQueries(11): # 1 query for bookmark table. response = self.send_get( client=self.client, url=reverse( @@ -414,7 +414,7 @@ class BookmarksDetailViewTests(BookmarksViewsTestsBase): """ Test that requesting bookmark that belongs to other user returns 404 status code. """ - with self.assertNumQueries(8): # No queries for bookmark table. + with self.assertNumQueries(11): # No queries for bookmark table. self.send_get( client=self.client, url=reverse( @@ -428,7 +428,7 @@ class BookmarksDetailViewTests(BookmarksViewsTestsBase): """ Test that requesting bookmark that does not exist returns 404 status code. """ - with self.assertNumQueries(8): # 1 query for bookmark table. + with self.assertNumQueries(11): # 1 query for bookmark table. response = self.send_get( client=self.client, url=reverse( @@ -450,7 +450,7 @@ class BookmarksDetailViewTests(BookmarksViewsTestsBase): """ Test that requesting bookmark with invalid usage id returns 400. """ - with self.assertNumQueries(7): # No queries for bookmark table. + with self.assertNumQueries(10): # No queries for bookmark table. response = self.send_get( client=self.client, url=reverse( @@ -506,7 +506,7 @@ class BookmarksDetailViewTests(BookmarksViewsTestsBase): """ Test that delete bookmark that belongs to other user returns 404. """ - with self.assertNumQueries(8): # No queries for bookmark table. + with self.assertNumQueries(11): # No queries for bookmark table. self.send_delete( client=self.client, url=reverse( @@ -520,7 +520,7 @@ class BookmarksDetailViewTests(BookmarksViewsTestsBase): """ Test that delete bookmark that does not exist returns 404. """ - with self.assertNumQueries(8): # 1 query for bookmark table. + with self.assertNumQueries(11): # 1 query for bookmark table. response = self.send_delete( client=self.client, url=reverse( @@ -542,7 +542,7 @@ class BookmarksDetailViewTests(BookmarksViewsTestsBase): """ Test that delete bookmark with invalid usage id returns 400. """ - with self.assertNumQueries(7): # No queries for bookmark table. + with self.assertNumQueries(10): # No queries for bookmark table. response = self.send_delete( client=self.client, url=reverse( @@ -559,7 +559,7 @@ class BookmarksDetailViewTests(BookmarksViewsTestsBase): """ url = reverse('bookmarks_detail', kwargs={'username': self.user.username, 'usage_id': 'i4x'}) self.client.login(username=self.user.username, password=self.TEST_PASSWORD) - with self.assertNumQueries(8): # No queries for bookmark table. + with self.assertNumQueries(11): # No queries for bookmark table. self.assertEqual(405, self.client.put(url).status_code) with self.assertNumQueries(7): diff --git a/openedx/core/djangoapps/content/course_overviews/tests.py b/openedx/core/djangoapps/content/course_overviews/tests.py index a87518ff2f..582b8fc8c1 100644 --- a/openedx/core/djangoapps/content/course_overviews/tests.py +++ b/openedx/core/djangoapps/content/course_overviews/tests.py @@ -348,7 +348,7 @@ class CourseOverviewTestCase(ModuleStoreTestCase): course_overview = CourseOverview._create_from_course(course) # pylint: disable=protected-access self.assertEqual(course_overview.lowest_passing_grade, None) - @ddt.data((ModuleStoreEnum.Type.mongo, 5, 5), (ModuleStoreEnum.Type.split, 3, 4)) + @ddt.data((ModuleStoreEnum.Type.mongo, 4, 4), (ModuleStoreEnum.Type.split, 3, 4)) @ddt.unpack def test_versioning(self, modulestore_type, min_mongo_calls, max_mongo_calls): """