diff --git a/lms/djangoapps/ccx/tests/test_field_override_performance.py b/lms/djangoapps/ccx/tests/test_field_override_performance.py index ffc43ae17c..7c832ff38c 100644 --- a/lms/djangoapps/ccx/tests/test_field_override_performance.py +++ b/lms/djangoapps/ccx/tests/test_field_override_performance.py @@ -3,18 +3,21 @@ Performance tests for field overrides. """ import ddt +import itertools import mock from courseware.views import progress # pylint: disable=import-error from datetime import datetime -from django.core.cache import cache +from django.core.cache import get_cache from django.test.client import RequestFactory from django.test.utils import override_settings from edxmako.middleware import MakoMiddleware # pylint: disable=import-error from nose.plugins.attrib import attr from pytz import UTC +from request_cache.middleware import RequestCache from student.models import CourseEnrollment from student.tests.factories import UserFactory # pylint: disable=import-error +from xmodule.modulestore.django import modulestore from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase, \ TEST_DATA_SPLIT_MODULESTORE, TEST_DATA_MONGO_MODULESTORE from xmodule.modulestore.tests.factories import check_mongo_calls, CourseFactory @@ -32,6 +35,11 @@ class FieldOverridePerformanceTestCase(ProceduralCourseTestMixin, Base class for instrumenting SQL queries and Mongo reads for field override providers. """ + __test__ = False + + # TEST_DATA must be overridden by subclasses + TEST_DATA = None + def setUp(self): """ Create a test client, course, and user. @@ -42,14 +50,14 @@ class FieldOverridePerformanceTestCase(ProceduralCourseTestMixin, self.student = UserFactory.create() self.request = self.request_factory.get("foo") self.request.user = self.student + self.course = None MakoMiddleware().process_request(self.request) - # TEST_DATA must be overridden by subclasses, otherwise the test is - # skipped. - self.TEST_DATA = None - def setup_course(self, size): + """ + Build a gradable course where each node has `size` children. + """ grading_policy = { "GRADER": [ { @@ -113,50 +121,39 @@ class FieldOverridePerformanceTestCase(ProceduralCourseTestMixin, """ self.setup_course(dataset_index + 1) - # Clear the cache before measuring - # TODO: remove once django cache is disabled in tests - cache.clear() - with self.assertNumQueries(queries): - with check_mongo_calls(reads): - self.grade_course(self.course) + # Switch to published-only mode to simulate the LMS + with self.settings(MODULESTORE_BRANCH='published-only'): + # Clear the cache before measuring + # We clear the mongo_metadata_inheritance cache so that we can refill it + # with published-only contents. + get_cache('mongo_metadata_inheritance').clear() - def run_if_subclassed(self, test_type, dataset_index): - """ - Run the query/read instrumentation only if TEST_DATA has been - overridden. - """ - if not self.TEST_DATA: - self.skipTest( - "Test not properly configured. TEST_DATA must be overridden " - "by a subclass." - ) + # Refill the metadata inheritance cache + modulestore().get_course(self.course.id, depth=None) - queries, reads = self.TEST_DATA[test_type][dataset_index] - self.instrument_course_progress_render(dataset_index, queries, reads) + # We clear the request cache to simulate a new request in the LMS. + RequestCache.clear_request_cache() - @ddt.data((0,), (1,), (2,)) + with self.assertNumQueries(queries): + with check_mongo_calls(reads): + self.grade_course(self.course) + + @ddt.data(*itertools.product(('no_overrides', 'ccx'), range(3))) @ddt.unpack @override_settings( FIELD_OVERRIDE_PROVIDERS=(), ) - def test_instrument_without_field_override(self, dataset): + def test_field_overrides(self, overrides, dataset_index): """ Test without any field overrides. """ - self.run_if_subclassed('no_overrides', dataset) - - @ddt.data((0,), (1,), (2,)) - @ddt.unpack - @override_settings( - FIELD_OVERRIDE_PROVIDERS=( - 'ccx.overrides.CustomCoursesForEdxOverrideProvider', - ), - ) - def test_instrument_with_field_override(self, dataset): - """ - Test with the CCX field override enabled. - """ - self.run_if_subclassed('ccx', dataset) + providers = { + 'no_overrides': (), + 'ccx': ('ccx.overrides.CustomCoursesForEdxOverrideProvider',) + } + with self.settings(FIELD_OVERRIDE_PROVIDERS=providers[overrides]): + queries, reads = self.TEST_DATA[overrides][dataset_index] + self.instrument_course_progress_render(dataset_index, queries, reads) class TestFieldOverrideMongoPerformance(FieldOverridePerformanceTestCase): @@ -164,21 +161,16 @@ class TestFieldOverrideMongoPerformance(FieldOverridePerformanceTestCase): Test cases for instrumenting field overrides against the Mongo modulestore. """ MODULESTORE = TEST_DATA_MONGO_MODULESTORE + __test__ = True - def setUp(self): - """ - Set the modulestore and scaffold the test data. - """ - super(TestFieldOverrideMongoPerformance, self).setUp() - - self.TEST_DATA = { - 'no_overrides': [ - (22, 6), (130, 6), (590, 6) - ], - 'ccx': [ - (22, 6), (130, 6), (590, 6) - ], - } + TEST_DATA = { + 'no_overrides': [ + (26, 7), (132, 7), (592, 7) + ], + 'ccx': [ + (24, 35), (132, 331), (592, 1507) + ], + } class TestFieldOverrideSplitPerformance(FieldOverridePerformanceTestCase): @@ -186,18 +178,13 @@ class TestFieldOverrideSplitPerformance(FieldOverridePerformanceTestCase): Test cases for instrumenting field overrides against the Split modulestore. """ MODULESTORE = TEST_DATA_SPLIT_MODULESTORE + __test__ = True - def setUp(self): - """ - Set the modulestore and scaffold the test data. - """ - super(TestFieldOverrideSplitPerformance, self).setUp() - - self.TEST_DATA = { - 'no_overrides': [ - (22, 4), (130, 19), (590, 84) - ], - 'ccx': [ - (22, 4), (130, 19), (590, 84) - ] - } + TEST_DATA = { + 'no_overrides': [ + (24, 4), (132, 19), (592, 84) + ], + 'ccx': [ + (24, 4), (132, 19), (592, 84) + ] + }