From bcaa873be0af447c520a56cc85e29ea2770fdb6d Mon Sep 17 00:00:00 2001 From: Sanford Student Date: Fri, 30 Sep 2016 10:45:30 -0400 Subject: [PATCH] bug fix for TNL-5601 fixes signal handling for delete student state --- .../test/acceptance/pages/lms/staff_view.py | 4 ++-- .../tests/lms/test_progress_page.py | 24 +++++++++++++++++++ lms/djangoapps/instructor/enrollment.py | 8 +++---- lms/djangoapps/instructor/tests/test_api.py | 3 ++- .../instructor/tests/test_enrollment.py | 7 +++--- .../instructor/tests/test_services.py | 3 ++- 6 files changed, 38 insertions(+), 11 deletions(-) diff --git a/common/test/acceptance/pages/lms/staff_view.py b/common/test/acceptance/pages/lms/staff_view.py index db23f89fd1..c87fef1d7d 100644 --- a/common/test/acceptance/pages/lms/staff_view.py +++ b/common/test/acceptance/pages/lms/staff_view.py @@ -95,8 +95,8 @@ class StaffDebugPage(PageObject): This delete's a student's state for the problem """ if user: - self.q(css='input[id^=sd_fu_]').fill(user) - self.q(css='.staff-modal .staff-debug-sdelete').click() + self.q(css='input[id^=sd_fu_]').first.fill(user) + self.q(css='.staff-modal .staff-debug-sdelete').first.click() def rescore(self, user=None): """ diff --git a/common/test/acceptance/tests/lms/test_progress_page.py b/common/test/acceptance/tests/lms/test_progress_page.py index cad30b789c..3553cc9e44 100644 --- a/common/test/acceptance/tests/lms/test_progress_page.py +++ b/common/test/acceptance/tests/lms/test_progress_page.py @@ -15,6 +15,7 @@ from ...pages.lms.courseware import CoursewarePage from ...pages.lms.instructor_dashboard import InstructorDashboardPage from ...pages.lms.problem import ProblemPage from ...pages.lms.progress import ProgressPage +from ...pages.lms.staff_view import StaffPage, StaffDebugPage from ...pages.studio.component_editor import ComponentEditorView from ...pages.studio.utils import type_in_codemirror from ...pages.studio.overview import CourseOutlinePage @@ -192,6 +193,22 @@ class PersistentGradesTest(ProgressPageBaseTest): type_in_codemirror(self, 0, modified_content) modal.q(css='.action-save').click() + def _delete_student_state_for_problem(self): + """ + As staff, clicks the "delete student state" button, + deleting the student user's state for the problem. + """ + with self._logged_in_session(staff=True): + self.courseware_page.visit() + staff_page = StaffPage(self.browser, self.course_id) + self.assertEqual(staff_page.staff_view_mode, "Staff") + staff_page.q(css='a.instructor-info-action').nth(1).click() + staff_debug_page = StaffDebugPage(self.browser) + staff_debug_page.wait_for_page() + staff_debug_page.delete_state(self.USERNAME) + msg = staff_debug_page.idash_msg[0] + self.assertEqual(u'Successfully deleted student state for user {0}'.format(self.USERNAME), msg) + @ddt.data( _edit_problem_content, _change_subsection_structure, @@ -223,6 +240,13 @@ class PersistentGradesTest(ProgressPageBaseTest): self.assertEqual(self._get_problem_scores(), [(1, 1), (0, 1)]) self.assertEqual(self._get_section_score(), (1, 2)) + def test_progress_page_updates_when_student_state_deleted(self): + self._check_progress_page_with_scored_problem() + self._delete_student_state_for_problem() + with self._logged_in_session(): + self.assertEqual(self._get_problem_scores(), [(0, 1), (0, 1)]) + self.assertEqual(self._get_section_score(), (0, 2)) + class SubsectionGradingPolicyTest(ProgressPageBaseTest): """ diff --git a/lms/djangoapps/instructor/enrollment.py b/lms/djangoapps/instructor/enrollment.py index becae8f2ba..fd3921431b 100644 --- a/lms/djangoapps/instructor/enrollment.py +++ b/lms/djangoapps/instructor/enrollment.py @@ -18,8 +18,8 @@ from courseware.model_data import FieldDataCache from courseware.module_render import get_module_for_descriptor from courseware.models import StudentModule from edxmako.shortcuts import render_to_string -from grades.scores import weighted_score -from grades.signals.signals import SCORE_CHANGED +from lms.djangoapps.grades.scores import weighted_score +from lms.djangoapps.grades.signals.signals import SCORE_CHANGED from lang_pref import LANGUAGE_KEY from student.models import CourseEnrollment, CourseEnrollmentAllowed from submissions import api as sub_api # installed from the edx-submissions repository @@ -325,8 +325,8 @@ def _fire_score_changed_for_block(course_id, student, block, module_state_key): points_possible=points_possible, points_earned=points_earned, user=student, - course_id=course_id, - usage_id=module_state_key + course_id=unicode(course_id), + usage_id=unicode(module_state_key) ) diff --git a/lms/djangoapps/instructor/tests/test_api.py b/lms/djangoapps/instructor/tests/test_api.py index 312a40adab..4a1c292eca 100644 --- a/lms/djangoapps/instructor/tests/test_api.py +++ b/lms/djangoapps/instructor/tests/test_api.py @@ -3190,7 +3190,8 @@ class TestInstructorAPIRegradeTask(SharedModuleStoreTestCase, LoginEnrollmentTes }) self.assertEqual(response.status_code, 400) - def test_reset_student_attempts_delete(self): + @patch('courseware.module_render.SCORE_CHANGED.send') + def test_reset_student_attempts_delete(self, _mock_signal): """ Test delete single student state. """ url = reverse('reset_student_attempts', kwargs={'course_id': self.course.id.to_deprecated_string()}) response = self.client.post(url, { diff --git a/lms/djangoapps/instructor/tests/test_enrollment.py b/lms/djangoapps/instructor/tests/test_enrollment.py index 0b65f1c8a4..ca7b0f3aea 100644 --- a/lms/djangoapps/instructor/tests/test_enrollment.py +++ b/lms/djangoapps/instructor/tests/test_enrollment.py @@ -378,7 +378,8 @@ class TestInstructorEnrollmentStudentModule(SharedModuleStoreTestCase): reset_student_attempts(self.course_key, self.user, msk, requesting_user=self.user) self.assertEqual(json.loads(module().state)['attempts'], 0) - def test_delete_student_attempts(self): + @mock.patch('courseware.module_render.SCORE_CHANGED.send') + def test_delete_student_attempts(self, _mock_signal): msk = self.course_key.make_usage_key('dummy', 'module') original_state = json.dumps({'attempts': 32, 'otherstuff': 'alsorobots'}) StudentModule.objects.create( @@ -404,7 +405,7 @@ class TestInstructorEnrollmentStudentModule(SharedModuleStoreTestCase): # Disable the score change signal to prevent other components from being # pulled into tests. @mock.patch('courseware.module_render.SCORE_CHANGED.send') - def test_delete_submission_scores(self, _lti_mock): + def test_delete_submission_scores(self, _mock_signal): user = UserFactory() problem_location = self.course_key.make_usage_key('dummy', 'module') @@ -548,7 +549,7 @@ class TestStudentModuleGrading(SharedModuleStoreTestCase): self.course, get_course_blocks(self.user, self.course.location) ) - grade = subsection_grade_factory.update(self.sequence) + grade = subsection_grade_factory.create(self.sequence) self.assertEqual(grade.all_total.earned, all_earned) self.assertEqual(grade.graded_total.earned, graded_earned) self.assertEqual(grade.all_total.possible, all_possible) diff --git a/lms/djangoapps/instructor/tests/test_services.py b/lms/djangoapps/instructor/tests/test_services.py index 2cf59a663e..648f6350ee 100644 --- a/lms/djangoapps/instructor/tests/test_services.py +++ b/lms/djangoapps/instructor/tests/test_services.py @@ -49,7 +49,8 @@ class InstructorServiceTests(SharedModuleStoreTestCase): state=json.dumps({'attempts': 2}), ) - def test_reset_student_attempts_delete(self): + @mock.patch('courseware.module_render.SCORE_CHANGED.send') + def test_reset_student_attempts_delete(self, _mock_signal): """ Test delete student state. """