Commit 5962c4eb by Calen Pennington

Better simulate a request happening in the LMS in FieldOverride performance tests

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