Commit 7e9a139d by John Eskew

Merge pull request #11766 from CredoReference/too-many-mongo-queries-in-instructor-api-gradebook

Reduce the number of queries to mongodb in /courses/<course-id>/instructor/api/gradebook API
parents a8f274d5 d7502384
......@@ -2,7 +2,9 @@
Unit tests for instructor_dashboard.py.
"""
import ddt
import datetime
from mock import patch
from pytz import UTC
from django.conf import settings
from django.core.urlresolvers import reverse
......@@ -10,16 +12,16 @@ from django.test.client import RequestFactory
from django.test.utils import override_settings
from edxmako.shortcuts import render_to_response
from lms.djangoapps.ccx.tests.test_views import setup_students_and_grades
from courseware.tabs import get_course_tab_list
from courseware.tests.factories import UserFactory
from courseware.tests.factories import UserFactory, StudentModuleFactory
from courseware.tests.helpers import LoginEnrollmentTestCase
from instructor.views.gradebook_api import calculate_page_info
from common.test.utils import XssTestMixin
from student.tests.factories import AdminFactory
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory
from student.tests.factories import AdminFactory, CourseEnrollmentFactory
from xmodule.modulestore import ModuleStoreEnum
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase, TEST_DATA_SPLIT_MODULESTORE
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory, check_mongo_calls
from shoppingcart.models import PaidCourseRegistration, Order, CourseRegCodeItem
from course_modes.models import CourseMode
from student.roles import CourseFinanceAdminRole
......@@ -284,7 +286,10 @@ class TestInstructorDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase, XssT
@patch('instructor.views.gradebook_api.render_to_response', intercept_renderer)
@patch('instructor.views.gradebook_api.MAX_STUDENTS_PER_PAGE_GRADE_BOOK', 1)
def test_spoc_gradebook_pages(self):
setup_students_and_grades(self)
for i in xrange(2):
username = "user_%d" % i
student = UserFactory.create(username=username)
CourseEnrollmentFactory.create(user=student, course_id=self.course.id)
url = reverse(
'spoc_gradebook',
kwargs={'course_id': self.course.id}
......@@ -293,3 +298,98 @@ class TestInstructorDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase, XssT
self.assertEqual(response.status_code, 200)
# Max number of student per page is one. Patched setting MAX_STUDENTS_PER_PAGE_GRADE_BOOK = 1
self.assertEqual(len(response.mako_context['students']), 1) # pylint: disable=no-member
@ddt.ddt
class TestInstructorDashboardPerformance(ModuleStoreTestCase, LoginEnrollmentTestCase, XssTestMixin):
"""
Tests for the instructor dashboard from the performance point of view.
"""
MODULESTORE = TEST_DATA_SPLIT_MODULESTORE
def setUp(self):
"""
Set up tests
"""
super(TestInstructorDashboardPerformance, self).setUp()
self.course = CourseFactory.create(
grading_policy={"GRADE_CUTOFFS": {"A": 0.75, "B": 0.63, "C": 0.57, "D": 0.5}},
display_name='<script>alert("XSS")</script>',
default_store=ModuleStoreEnum.Type.split
)
self.course_mode = CourseMode(
course_id=self.course.id,
mode_slug=CourseMode.DEFAULT_MODE_SLUG,
mode_display_name=CourseMode.DEFAULT_MODE.name,
min_price=40
)
self.course_mode.save()
# Create instructor account
self.instructor = AdminFactory.create()
self.client.login(username=self.instructor.username, password="test")
def test_spoc_gradebook_mongo_calls(self):
"""
Test that the MongoDB cache is used in API to return grades
"""
# prepare course structure
course = ItemFactory.create(
parent_location=self.course.location,
category="course",
display_name="Test course",
)
students = []
for i in xrange(20):
username = "user_%d" % i
student = UserFactory.create(username=username)
CourseEnrollmentFactory.create(user=student, course_id=self.course.id)
students.append(student)
chapter = ItemFactory.create(
parent=course,
category='chapter',
display_name="Chapter",
publish_item=True,
start=datetime.datetime(2015, 3, 1, tzinfo=UTC),
)
sequential = ItemFactory.create(
parent=chapter,
category='sequential',
display_name="Lesson",
publish_item=True,
start=datetime.datetime(2015, 3, 1, tzinfo=UTC),
metadata={'graded': True, 'format': 'Homework'},
)
vertical = ItemFactory.create(
parent=sequential,
category='vertical',
display_name='Subsection',
publish_item=True,
start=datetime.datetime(2015, 4, 1, tzinfo=UTC),
)
for i in xrange(10):
problem = ItemFactory.create(
category="problem",
parent=vertical,
display_name="A Problem Block %d" % i,
weight=1,
publish_item=False,
metadata={'rerandomize': 'always'},
)
for j in students:
grade = i % 2
StudentModuleFactory.create(
grade=grade,
max_grade=1,
student=j,
course_id=self.course.id,
module_state_key=problem.location
)
# check MongoDB calls count
url = reverse('spoc_gradebook', kwargs={'course_id': self.course.id})
with check_mongo_calls(8):
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
......@@ -15,6 +15,7 @@ from edxmako.shortcuts import render_to_response
from courseware.courses import get_course_with_access
from instructor.offline_gradecalc import student_grades
from instructor.views.api import require_level
from xmodule.modulestore.django import modulestore
# Grade book: max students per page
......@@ -84,15 +85,16 @@ def get_grade_book_page(request, course, course_key):
# Apply limit on queryset only if total number of students are greater then MAX_STUDENTS_PER_PAGE_GRADE_BOOK.
enrolled_students = enrolled_students[offset: offset + MAX_STUDENTS_PER_PAGE_GRADE_BOOK]
student_info = [
{
'username': student.username,
'id': student.id,
'email': student.email,
'grade_summary': student_grades(student, request, course),
}
for student in enrolled_students
]
with modulestore().bulk_operations(course.location.course_key):
student_info = [
{
'username': student.username,
'id': student.id,
'email': student.email,
'grade_summary': student_grades(student, request, course),
}
for student in enrolled_students
]
return student_info, page
......
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