From 9ff9c33f5951b487d3a6b4968d330c16e60dadd2 Mon Sep 17 00:00:00 2001 From: Calen Pennington Date: Tue, 22 Jan 2019 14:50:11 -0500 Subject: [PATCH] Add a test that shows how bad course api query counts are --- lms/djangoapps/course_api/tests/test_views.py | 58 +++++++++++++++++++ openedx/core/djangolib/testing/utils.py | 3 + 2 files changed, 61 insertions(+) diff --git a/lms/djangoapps/course_api/tests/test_views.py b/lms/djangoapps/course_api/tests/test_views.py index 974752be37..92a4fd9da9 100644 --- a/lms/djangoapps/course_api/tests/test_views.py +++ b/lms/djangoapps/course_api/tests/test_views.py @@ -1,6 +1,7 @@ """ Tests for Course API views. """ +from datetime import datetime import ddt from hashlib import md5 @@ -12,8 +13,14 @@ from search.tests.test_course_discovery import DemoCourse from search.tests.tests import TEST_INDEX_NAME from search.tests.utils import SearcherMixin +from course_modes.models import CourseMode +from course_modes.tests.factories import CourseModeFactory +from edx_django_utils.cache import RequestCache from openedx.core.lib.tests import attr +from openedx.features.content_type_gating.models import ContentTypeGatingConfig +from openedx.features.course_duration_limits.models import CourseDurationLimitConfig from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase, SharedModuleStoreTestCase +from xmodule.modulestore.tests.factories import CourseFactory from waffle.testutils import override_switch from ..views import CourseDetailView, CourseListUserThrottle @@ -283,6 +290,7 @@ class CourseListSearchViewTest(CourseApiTestViewMixin, ModuleStoreTestCase, Sear """ ENABLED_SIGNALS = ['course_published'] + ENABLED_CACHES = ModuleStoreTestCase.ENABLED_CACHES + ['configuration'] def setUp(self): super(CourseListSearchViewTest, self).setUp() @@ -298,6 +306,7 @@ class CourseListSearchViewTest(CourseApiTestViewMixin, ModuleStoreTestCase, Sear 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) + self.audit_user = self.create_user(username='audit', is_staff=False) def create_and_index_course(self, org_code, short_description): """ @@ -348,3 +357,52 @@ class CourseListSearchViewTest(CourseApiTestViewMixin, ModuleStoreTestCase, Sear self.assertIn('results', res.data) self.assertNotEqual(res.data['results'], []) self.assertEqual(res.data['pagination']['count'], 1) # Should list a single course + + def test_too_many_courses(self): + """ + Test that search results are limited to 100 courses, and that they don't + blow up the database. + """ + + ContentTypeGatingConfig.objects.create( + enabled=True, + enabled_as_of=datetime(2018, 1, 1), + ) + + CourseDurationLimitConfig.objects.create( + enabled=True, + enabled_as_of=datetime(2018, 1, 1), + ) + + course_ids = [] + + # Create 300 courses across 30 organizations + for org_num in range(10): + org_id = 'org{}'.format(org_num) + for course_num in range(30): + course_name = 'course{}.{}'.format(org_num, course_num) + course_run_name = 'run{}.{}'.format(org_num, course_num) + course = CourseFactory.create(org=org_id, number=course_name, run=course_run_name, emit_signals=True) + CourseModeFactory.create(course_id=course.id, mode_slug=CourseMode.AUDIT) + CourseModeFactory.create(course_id=course.id, mode_slug=CourseMode.VERIFIED) + course_ids.append(course.id) + + self.setup_user(self.audit_user) + + # These query counts were found empirically + query_counts = [1266, 349, 349, 349, 349, 349, 349, 349, 349, 349, 322] + ordered_course_ids = sorted([str(cid) for cid in (course_ids + [c.id for c in self.courses])]) + + self.clear_caches() + + for page in range(1, 12): + with self.assertNumQueries(query_counts[page - 1]): + response = self.verify_response(params={'page': page, 'page_size': 30}) + + self.assertIn('results', response.data) + self.assertEqual(response.data['pagination']['count'], 303) + self.assertEqual(len(response.data['results']), 30 if page < 11 else 3) + self.assertEqual( + [c['id'] for c in response.data['results']], + ordered_course_ids[(page - 1) * 30:page * 30] + ) diff --git a/openedx/core/djangolib/testing/utils.py b/openedx/core/djangolib/testing/utils.py index 710f5a35ba..3d620385e8 100644 --- a/openedx/core/djangolib/testing/utils.py +++ b/openedx/core/djangolib/testing/utils.py @@ -73,6 +73,9 @@ class CacheIsolationMixin(object): 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', 'LOCATION': cache_name, 'KEY_FUNCTION': 'util.memcache.safe_key', + 'OPTIONS': { + 'MAX_ENTRIES': 1000, + }, } for cache_name in cls.ENABLED_CACHES })