Commit be25bb8a by David Ormsbee

Clear caches between tests for ModuleStoreTestCase/SharedModuleStoreTestCase

Cached values were leaking across tests, causing difficult to debug errors,
particularly when using Config Models. As part of this work, certain tests
that had query counts that relied on those values being cached needed to
be adjusted up.
parent 68cf4af2
"""
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."""
...@@ -7,6 +7,7 @@ from uuid import uuid4 ...@@ -7,6 +7,7 @@ from uuid import uuid4
from mock import patch from mock import patch
import django.core.cache
from django.conf import settings 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
...@@ -215,6 +216,16 @@ TEST_DATA_SPLIT_MODULESTORE = mixed_store_config( ...@@ -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): class SharedModuleStoreTestCase(TestCase):
""" """
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
...@@ -268,7 +279,7 @@ class SharedModuleStoreTestCase(TestCase): ...@@ -268,7 +279,7 @@ class SharedModuleStoreTestCase(TestCase):
@classmethod @classmethod
def tearDownClass(cls): def tearDownClass(cls):
drop_mongo_collections() # pylint: disable=no-value-for-parameter drop_mongo_collections() # pylint: disable=no-value-for-parameter
RequestCache().clear_request_cache() clear_all_caches()
XMODULE_FACTORY_LOCK.disable() XMODULE_FACTORY_LOCK.disable()
cls._settings_override.__exit__(None, None, None) cls._settings_override.__exit__(None, None, None)
...@@ -280,6 +291,11 @@ class SharedModuleStoreTestCase(TestCase): ...@@ -280,6 +291,11 @@ 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): def reset(self):
""" """
Manually run tearDownClass/setUpClass again. Manually run tearDownClass/setUpClass again.
...@@ -394,7 +410,7 @@ class ModuleStoreTestCase(TestCase): ...@@ -394,7 +410,7 @@ class ModuleStoreTestCase(TestCase):
clear_existing_modulestores() clear_existing_modulestores()
self.addCleanup(drop_mongo_collections) 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). # Enable XModuleFactories for the space of this test (and its setUp).
self.addCleanup(XMODULE_FACTORY_LOCK.disable) self.addCleanup(XMODULE_FACTORY_LOCK.disable)
......
...@@ -520,7 +520,7 @@ class CourseBlocksOrNavigationTestMixin(CourseDetailTestMixin, CourseViewTestsMi ...@@ -520,7 +520,7 @@ class CourseBlocksOrNavigationTestMixin(CourseDetailTestMixin, CourseViewTestsMi
return 'course_structure_api:v0:' + self.block_navigation_view_type return 'course_structure_api:v0:' + self.block_navigation_view_type
def test_get(self): def test_get(self):
with check_mongo_calls(3): with check_mongo_calls(4):
response = super(CourseBlocksOrNavigationTestMixin, self).test_get() response = super(CourseBlocksOrNavigationTestMixin, self).test_get()
# verify root element # verify root element
......
...@@ -950,7 +950,7 @@ class ProgressPageTests(ModuleStoreTestCase): ...@@ -950,7 +950,7 @@ class ProgressPageTests(ModuleStoreTestCase):
self.assertContains(resp, u"Download Your Certificate") self.assertContains(resp, u"Download Your Certificate")
@ddt.data( @ddt.data(
*itertools.product(((38, 4, True), (38, 4, False)), (True, False)) *itertools.product(((40, 4, True), (40, 4, False)), (True, False))
) )
@ddt.unpack @ddt.unpack
def test_query_counts(self, (sql_calls, mongo_calls, self_paced), self_paced_enabled): def test_query_counts(self, (sql_calls, mongo_calls, self_paced), self_paced_enabled):
......
...@@ -1628,7 +1628,7 @@ class TestCertificateGeneration(InstructorTaskModuleTestCase): ...@@ -1628,7 +1628,7 @@ class TestCertificateGeneration(InstructorTaskModuleTestCase):
current_task.update_state = Mock() current_task.update_state = Mock()
instructor_task = Mock() instructor_task = Mock()
instructor_task.task_input = json.dumps({'students': None}) 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: with patch('instructor_task.tasks_helper._get_current_task') as mock_current_task:
mock_current_task.return_value = current_task mock_current_task.return_value = current_task
with patch('capa.xqueue_interface.XQueueInterface.send_to_queue') as mock_queue: with patch('capa.xqueue_interface.XQueueInterface.send_to_queue') as mock_queue:
......
...@@ -95,7 +95,7 @@ class BookmarksListViewTests(BookmarksViewsTestsBase): ...@@ -95,7 +95,7 @@ class BookmarksListViewTests(BookmarksViewsTestsBase):
if check_all_fields: if check_all_fields:
query_parameters += '&fields=path,display_name' 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( response = self.send_get(
client=self.client, client=self.client,
url=reverse('bookmarks'), url=reverse('bookmarks'),
...@@ -138,7 +138,7 @@ class BookmarksListViewTests(BookmarksViewsTestsBase): ...@@ -138,7 +138,7 @@ class BookmarksListViewTests(BookmarksViewsTestsBase):
page_size = 5 page_size = 5
query_parameters = 'course_id={}&page_size={}'.format(urllib.quote(unicode(course.id)), page_size) 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( response = self.send_get(
client=self.client, client=self.client,
url=reverse('bookmarks'), url=reverse('bookmarks'),
...@@ -171,15 +171,15 @@ class BookmarksListViewTests(BookmarksViewsTestsBase): ...@@ -171,15 +171,15 @@ class BookmarksListViewTests(BookmarksViewsTestsBase):
Test that requesting bookmarks with invalid data returns 0 records. Test that requesting bookmarks with invalid data returns 0 records.
""" """
# Invalid course id. # 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( response = self.send_get(
client=self.client, client=self.client,
url=reverse('bookmarks'), url=reverse('bookmarks'),
query_parameters='course_id=invalid' query_parameters='course_id=invalid'
) )
bookmarks_data = response.data['results'] 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 self.assertFalse(mock_tracker.emit.called) # pylint: disable=maybe-no-member
@patch('eventtracking.tracker.emit') @patch('eventtracking.tracker.emit')
...@@ -189,7 +189,7 @@ class BookmarksListViewTests(BookmarksViewsTestsBase): ...@@ -189,7 +189,7 @@ class BookmarksListViewTests(BookmarksViewsTestsBase):
""" """
# Without course id we would return all the bookmarks for that user. # 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( response = self.send_get(
client=self.client, client=self.client,
url=reverse('bookmarks') url=reverse('bookmarks')
...@@ -214,7 +214,7 @@ class BookmarksListViewTests(BookmarksViewsTestsBase): ...@@ -214,7 +214,7 @@ class BookmarksListViewTests(BookmarksViewsTestsBase):
Test that an anonymous client (not logged in) cannot call GET or POST. Test that an anonymous client (not logged in) cannot call GET or POST.
""" """
query_parameters = 'course_id={}'.format(self.course_id) 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( self.send_get(
client=self.anonymous_client, client=self.anonymous_client,
url=reverse('bookmarks'), url=reverse('bookmarks'),
...@@ -234,7 +234,7 @@ class BookmarksListViewTests(BookmarksViewsTestsBase): ...@@ -234,7 +234,7 @@ class BookmarksListViewTests(BookmarksViewsTestsBase):
""" """
Test that posting a bookmark successfully returns newly created data with 201 code. 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( response = self.send_post(
client=self.client, client=self.client,
url=reverse('bookmarks'), url=reverse('bookmarks'),
...@@ -258,7 +258,7 @@ class BookmarksListViewTests(BookmarksViewsTestsBase): ...@@ -258,7 +258,7 @@ class BookmarksListViewTests(BookmarksViewsTestsBase):
3) With empty request.data 3) With empty request.data
""" """
# Send usage_id with invalid format. # 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( response = self.send_post(
client=self.client, client=self.client,
url=reverse('bookmarks'), url=reverse('bookmarks'),
...@@ -293,7 +293,7 @@ class BookmarksListViewTests(BookmarksViewsTestsBase): ...@@ -293,7 +293,7 @@ class BookmarksListViewTests(BookmarksViewsTestsBase):
""" """
Test that posting a bookmark for a block that does not exist returns a 400. 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( response = self.send_post(
client=self.client, client=self.client,
url=reverse('bookmarks'), url=reverse('bookmarks'),
...@@ -317,7 +317,7 @@ class BookmarksListViewTests(BookmarksViewsTestsBase): ...@@ -317,7 +317,7 @@ class BookmarksListViewTests(BookmarksViewsTestsBase):
max_bookmarks = settings.MAX_BOOKMARKS_PER_COURSE max_bookmarks = settings.MAX_BOOKMARKS_PER_COURSE
__, blocks, __ = self.create_course_with_bookmarks_count(max_bookmarks) __, 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( response = self.send_post(
client=self.client, client=self.client,
url=reverse('bookmarks'), url=reverse('bookmarks'),
...@@ -397,7 +397,7 @@ class BookmarksDetailViewTests(BookmarksViewsTestsBase): ...@@ -397,7 +397,7 @@ class BookmarksDetailViewTests(BookmarksViewsTestsBase):
""" """
Test that requesting bookmark returns data with 200 code. 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( response = self.send_get(
client=self.client, client=self.client,
url=reverse( url=reverse(
...@@ -414,7 +414,7 @@ class BookmarksDetailViewTests(BookmarksViewsTestsBase): ...@@ -414,7 +414,7 @@ class BookmarksDetailViewTests(BookmarksViewsTestsBase):
""" """
Test that requesting bookmark that belongs to other user returns 404 status code. 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( self.send_get(
client=self.client, client=self.client,
url=reverse( url=reverse(
...@@ -428,7 +428,7 @@ class BookmarksDetailViewTests(BookmarksViewsTestsBase): ...@@ -428,7 +428,7 @@ class BookmarksDetailViewTests(BookmarksViewsTestsBase):
""" """
Test that requesting bookmark that does not exist returns 404 status code. 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( response = self.send_get(
client=self.client, client=self.client,
url=reverse( url=reverse(
...@@ -450,7 +450,7 @@ class BookmarksDetailViewTests(BookmarksViewsTestsBase): ...@@ -450,7 +450,7 @@ class BookmarksDetailViewTests(BookmarksViewsTestsBase):
""" """
Test that requesting bookmark with invalid usage id returns 400. 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( response = self.send_get(
client=self.client, client=self.client,
url=reverse( url=reverse(
...@@ -506,7 +506,7 @@ class BookmarksDetailViewTests(BookmarksViewsTestsBase): ...@@ -506,7 +506,7 @@ class BookmarksDetailViewTests(BookmarksViewsTestsBase):
""" """
Test that delete bookmark that belongs to other user returns 404. 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( self.send_delete(
client=self.client, client=self.client,
url=reverse( url=reverse(
...@@ -520,7 +520,7 @@ class BookmarksDetailViewTests(BookmarksViewsTestsBase): ...@@ -520,7 +520,7 @@ class BookmarksDetailViewTests(BookmarksViewsTestsBase):
""" """
Test that delete bookmark that does not exist returns 404. 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( response = self.send_delete(
client=self.client, client=self.client,
url=reverse( url=reverse(
...@@ -542,7 +542,7 @@ class BookmarksDetailViewTests(BookmarksViewsTestsBase): ...@@ -542,7 +542,7 @@ class BookmarksDetailViewTests(BookmarksViewsTestsBase):
""" """
Test that delete bookmark with invalid usage id returns 400. 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( response = self.send_delete(
client=self.client, client=self.client,
url=reverse( url=reverse(
...@@ -559,7 +559,7 @@ class BookmarksDetailViewTests(BookmarksViewsTestsBase): ...@@ -559,7 +559,7 @@ class BookmarksDetailViewTests(BookmarksViewsTestsBase):
""" """
url = reverse('bookmarks_detail', kwargs={'username': self.user.username, 'usage_id': 'i4x'}) url = reverse('bookmarks_detail', kwargs={'username': self.user.username, 'usage_id': 'i4x'})
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(8): # No queries for bookmark table. with self.assertNumQueries(11): # No queries for bookmark table.
self.assertEqual(405, self.client.put(url).status_code) self.assertEqual(405, self.client.put(url).status_code)
with self.assertNumQueries(7): with self.assertNumQueries(7):
......
...@@ -348,7 +348,7 @@ class CourseOverviewTestCase(ModuleStoreTestCase): ...@@ -348,7 +348,7 @@ class CourseOverviewTestCase(ModuleStoreTestCase):
course_overview = CourseOverview._create_from_course(course) # pylint: disable=protected-access course_overview = CourseOverview._create_from_course(course) # pylint: disable=protected-access
self.assertEqual(course_overview.lowest_passing_grade, None) 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 @ddt.unpack
def test_versioning(self, modulestore_type, min_mongo_calls, max_mongo_calls): def test_versioning(self, modulestore_type, min_mongo_calls, max_mongo_calls):
""" """
......
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