def test_set_credit_requirement_status(self): self.add_credit_course() requirements = [ {"namespace": "grade", "name": "grade", "display_name": "Grade", "criteria": {"min_grade": 0.8}}, { "namespace": "reverification", "name": "i4x://edX/DemoX/edx-reverification-block/assessment_uuid", "display_name": "Assessment 1", "criteria": {}, }, ] api.set_credit_requirements(self.course_key, requirements) course_requirements = api.get_credit_requirements(self.course_key) self.assertEqual(len(course_requirements), 2) # Initially, the status should be None req_status = api.get_credit_requirement_status(self.course_key, "staff", namespace="grade", name="grade") self.assertEqual(req_status[0]["status"], None) # Set the requirement to "satisfied" and check that it's actually set api.set_credit_requirement_status("staff", self.course_key, "grade", "grade") req_status = api.get_credit_requirement_status(self.course_key, "staff", namespace="grade", name="grade") self.assertEqual(req_status[0]["status"], "satisfied") # Set the requirement to "failed" and check that it's actually set api.set_credit_requirement_status("staff", self.course_key, "grade", "grade", status="failed") req_status = api.get_credit_requirement_status(self.course_key, "staff", namespace="grade", name="grade") self.assertEqual(req_status[0]["status"], "failed")
def test_remove_credit_requirement_status(self): self.add_credit_course() requirements = [ {"namespace": "grade", "name": "grade", "display_name": "Grade", "criteria": {"min_grade": 0.8}}, { "namespace": "reverification", "name": "i4x://edX/DemoX/edx-reverification-block/assessment_uuid", "display_name": "Assessment 1", "criteria": {}, }, ] api.set_credit_requirements(self.course_key, requirements) course_requirements = api.get_credit_requirements(self.course_key) self.assertEqual(len(course_requirements), 2) # before setting credit_requirement_status api.remove_credit_requirement_status("staff", self.course_key, "grade", "grade") req_status = api.get_credit_requirement_status(self.course_key, "staff", namespace="grade", name="grade") self.assertIsNone(req_status[0]["status"]) self.assertIsNone(req_status[0]["status_date"]) self.assertIsNone(req_status[0]["reason"]) # Set the requirement to "satisfied" and check that it's actually set api.set_credit_requirement_status("staff", self.course_key, "grade", "grade") req_status = api.get_credit_requirement_status(self.course_key, "staff", namespace="grade", name="grade") self.assertEqual(len(req_status), 1) self.assertEqual(req_status[0]["status"], "satisfied") # remove the credit requirement status and check that it's actually removed api.remove_credit_requirement_status("staff", self.course_key, "grade", "grade") req_status = api.get_credit_requirement_status(self.course_key, "staff", namespace="grade", name="grade") self.assertIsNone(req_status[0]["status"]) self.assertIsNone(req_status[0]["status_date"]) self.assertIsNone(req_status[0]["reason"])
def test_remove_credit_requirement_status(self): self.add_credit_course() requirements = [{ "namespace": "grade", "name": "grade", "display_name": "Grade", "criteria": { "min_grade": 0.8 }, }, { "namespace": "reverification", "name": "i4x://edX/DemoX/edx-reverification-block/assessment_uuid", "display_name": "Assessment 1", "criteria": {}, }] api.set_credit_requirements(self.course_key, requirements) course_requirements = api.get_credit_requirements(self.course_key) self.assertEqual(len(course_requirements), 2) # before setting credit_requirement_status api.remove_credit_requirement_status("staff", self.course_key, "grade", "grade") req_status = api.get_credit_requirement_status(self.course_key, "staff", namespace="grade", name="grade") self.assertIsNone(req_status[0]["status"]) self.assertIsNone(req_status[0]["status_date"]) self.assertIsNone(req_status[0]["reason"]) # Set the requirement to "satisfied" and check that it's actually set api.set_credit_requirement_status("staff", self.course_key, "grade", "grade") req_status = api.get_credit_requirement_status(self.course_key, "staff", namespace="grade", name="grade") self.assertEqual(len(req_status), 1) self.assertEqual(req_status[0]["status"], "satisfied") # remove the credit requirement status and check that it's actually removed api.remove_credit_requirement_status("staff", self.course_key, "grade", "grade") req_status = api.get_credit_requirement_status(self.course_key, "staff", namespace="grade", name="grade") self.assertIsNone(req_status[0]["status"]) self.assertIsNone(req_status[0]["status_date"]) self.assertIsNone(req_status[0]["reason"])
def test_set_credit_requirement_status_req_not_configured(self): # Configure a credit course with no requirements self.add_credit_course() # A user satisfies a requirement. This could potentially # happen if there's a lag when the requirements are updated # after the course is published. api.set_credit_requirement_status("bob", self.course_key, "grade", "grade") # Since the requirement hasn't been published yet, it won't show # up in the list of requirements. req_status = api.get_credit_requirement_status(self.course_key, "bob", namespace="grade", name="grade") self.assertEqual(req_status, []) # Now add the requirements, simulating what happens when a course is published. requirements = [{ "namespace": "grade", "name": "grade", "display_name": "Grade", "criteria": { "min_grade": 0.8 }, }, { "namespace": "reverification", "name": "i4x://edX/DemoX/edx-reverification-block/assessment_uuid", "display_name": "Assessment 1", "criteria": {}, }] api.set_credit_requirements(self.course_key, requirements) # The user should not have satisfied the requirements, since they weren't # in effect when the user completed the requirement req_status = api.get_credit_requirement_status(self.course_key, "bob") self.assertEqual(len(req_status), 2) self.assertEqual(req_status[0]["status"], None) self.assertEqual(req_status[0]["status"], None) # The user should *not* have satisfied the reverification requirement req_status = api.get_credit_requirement_status( self.course_key, "bob", namespace=requirements[1]["namespace"], name=requirements[1]["name"]) self.assertEqual(len(req_status), 1) self.assertEqual(req_status[0]["status"], None)
def test_set_credit_requirement_status_req_not_configured(self): # Configure a credit course with no requirements self.add_credit_course() # A user satisfies a requirement. This could potentially # happen if there's a lag when the requirements are updated # after the course is published. api.set_credit_requirement_status("bob", self.course_key, "grade", "grade") # Since the requirement hasn't been published yet, it won't show # up in the list of requirements. req_status = api.get_credit_requirement_status(self.course_key, "bob", namespace="grade", name="grade") self.assertEqual(req_status, []) # Now add the requirements, simulating what happens when a course is published. requirements = [ { "namespace": "grade", "name": "grade", "display_name": "Grade", "criteria": { "min_grade": 0.8 }, }, { "namespace": "reverification", "name": "i4x://edX/DemoX/edx-reverification-block/assessment_uuid", "display_name": "Assessment 1", "criteria": {}, } ] api.set_credit_requirements(self.course_key, requirements) # The user should not have satisfied the requirements, since they weren't # in effect when the user completed the requirement req_status = api.get_credit_requirement_status(self.course_key, "bob") self.assertEqual(len(req_status), 2) self.assertEqual(req_status[0]["status"], None) self.assertEqual(req_status[0]["status"], None) # The user should *not* have satisfied the reverification requirement req_status = api.get_credit_requirement_status( self.course_key, "bob", namespace=requirements[1]["namespace"], name=requirements[1]["name"] ) self.assertEqual(len(req_status), 1) self.assertEqual(req_status[0]["status"], None)
def test_min_grade_credit_requirements_status(self, mode): """ Test for credit course. If user passes minimum grade requirement then status will be updated as satisfied in requirement status table. """ self.basic_setup() # Enroll student in credit eligible mode. # Note that we can't call self.enroll here since that goes through # the Django student views, and does not update enrollment if it already exists. CourseEnrollment.enroll(self.student_user, self.course.id, mode) # Enable the course for credit CreditCourse.objects.create(course_key=self.course.id, enabled=True) # Configure a credit provider for the course CreditProvider.objects.create( provider_id="ASU", enable_integration=True, provider_url="https://credit.example.com/request", ) requirements = [{ "namespace": "grade", "name": "grade", "display_name": "Grade", "criteria": { "min_grade": 0.52 }, }] # Add a single credit requirement (final grade) set_credit_requirements(self.course.id, requirements) # Credit requirement is not satisfied before passing grade req_status = get_credit_requirement_status(self.course.id, self.student_user.username, 'grade', 'grade') self.assertEqual(req_status[0]["status"], None) self._stop_signal_patch() self.submit_question_answer('p1', {'2_1': 'Correct'}) self.submit_question_answer('p2', {'2_1': 'Correct'}) # Credit requirement is now satisfied after passing grade req_status = get_credit_requirement_status(self.course.id, self.student_user.username, 'grade', 'grade') self.assertEqual(req_status[0]["status"], 'satisfied')
def test_credit_requirements_eligible(self): """ Mark the user as eligible for all requirements. Requirements are only displayed for credit and verified enrollments. """ credit_api.set_credit_requirement_status( self.user, self.course.id, "grade", "grade", status="satisfied", reason={"final_grade": 0.95} ) credit_api.set_credit_requirement_status( self.user, self.course.id, "reverification", "midterm", status="satisfied", reason={} ) # Check the progress page display response = self._get_progress_page() self.assertContains(response, self.MIN_GRADE_REQ_DISPLAY) self.assertContains(response, self.VERIFICATION_REQ_DISPLAY) self.assertContains( response, "{}, you have met the requirements for credit in this course.".format(self.USER_FULL_NAME) ) self.assertContains(response, "Completed by {date}") credit_requirements = credit_api.get_credit_requirement_status(self.course.id, self.user.username) for requirement in credit_requirements: self.assertContains(response, requirement['status_date'].strftime('%Y-%m-%d %H:%M')) self.assertNotContains(response, "95%")
def test_declined_verification_on_skip(self): """Test that status with value 'declined' is added in credit requirement status model when a user skip's an ICRV. """ reverification_service = ReverificationService() checkpoint = VerificationCheckpoint.objects.create( course_id=unicode(self.course_id), checkpoint_location=self.final_checkpoint_location) # Create credit course and set credit requirements. CreditCourse.objects.create(course_key=self.course_key, enabled=True) set_credit_requirements(self.course_key, [{ "namespace": "reverification", "name": checkpoint.checkpoint_location, "display_name": "Assessment 1", "criteria": {}, }]) reverification_service.skip_verification( self.user.id, unicode(self.course_id), self.final_checkpoint_location) requirement_status = get_credit_requirement_status( self.course_key, self.user.username, 'reverification', checkpoint.checkpoint_location) self.assertEqual( SkippedReverification.objects.filter( user=self.user, course_id=self.course_id).count(), 1) self.assertEqual(len(requirement_status), 1) self.assertEqual(requirement_status[0].get('name'), checkpoint.checkpoint_location) self.assertEqual(requirement_status[0].get('status'), 'declined')
def test_declined_verification_on_skip(self): """Test that status with value 'declined' is added in credit requirement status model when a user skip's an ICRV. """ reverification_service = ReverificationService() checkpoint = VerificationCheckpoint.objects.create( course_id=unicode(self.course_id), checkpoint_location=self.final_checkpoint_location ) # Create credit course and set credit requirements. CreditCourse.objects.create(course_key=self.course_key, enabled=True) set_credit_requirements( self.course_key, [ { "namespace": "reverification", "name": checkpoint.checkpoint_location, "display_name": "Assessment 1", "criteria": {}, } ] ) reverification_service.skip_verification(self.user.id, unicode(self.course_id), self.final_checkpoint_location) requirement_status = get_credit_requirement_status( self.course_key, self.user.username, 'reverification', checkpoint.checkpoint_location ) self.assertEqual(SkippedReverification.objects.filter(user=self.user, course_id=self.course_id).count(), 1) self.assertEqual(len(requirement_status), 1) self.assertEqual(requirement_status[0].get('name'), checkpoint.checkpoint_location) self.assertEqual(requirement_status[0].get('status'), 'declined')
def test_min_grade_credit_requirements_status(self): """ Test for credit course. If user passes minimum grade requirement then status will be updated as satisfied in requirement status table. """ self.basic_setup() self.submit_question_answer('p1', {'2_1': 'Correct'}) self.submit_question_answer('p2', {'2_1': 'Correct'}) # Enable the course for credit credit_course = CreditCourse.objects.create( course_key=self.course.id, enabled=True, ) # Configure a credit provider for the course CreditProvider.objects.create( provider_id="ASU", enable_integration=True, provider_url="https://credit.example.com/request", ) requirements = [{ "namespace": "grade", "name": "grade", "display_name": "Grade", "criteria": {"min_grade": 0.52}, }] # Add a single credit requirement (final grade) set_credit_requirements(self.course.id, requirements) self.get_grade_summary() req_status = get_credit_requirement_status(self.course.id, self.student_user.username, 'grade', 'grade') self.assertEqual(req_status[0]["status"], 'satisfied')
def test_credit_requirements_eligible(self): """ Mark the user as eligible for all requirements. Requirements are only displayed for credit and verified enrollments. """ credit_api.set_credit_requirement_status( self.user, self.course.id, "grade", "grade", status="satisfied", reason={"final_grade": 0.95} ) credit_api.set_credit_requirement_status( self.user, self.course.id, "reverification", "midterm", status="satisfied", reason={} ) # Check the progress page display response = self._get_progress_page() self.assertContains(response, self.MIN_GRADE_REQ_DISPLAY) self.assertContains(response, self.VERIFICATION_REQ_DISPLAY) self.assertContains( response, f"{self.USER_FULL_NAME}, you have met the requirements for credit in this course." ) self.assertContains(response, "Completed by {date}") credit_requirements = credit_api.get_credit_requirement_status(self.course.id, self.user.username) for requirement in credit_requirements: self.assertContains(response, requirement['status_date'].strftime('%Y-%m-%d %H:%M')) self.assertNotContains(response, "95%")
def test_set_credit_requirement_status(self): self.add_credit_course() requirements = [{ "namespace": "grade", "name": "grade", "display_name": "Grade", "criteria": { "min_grade": 0.8 }, }, { "namespace": "reverification", "name": "i4x://edX/DemoX/edx-reverification-block/assessment_uuid", "display_name": "Assessment 1", "criteria": {}, }] api.set_credit_requirements(self.course_key, requirements) course_requirements = api.get_credit_requirements(self.course_key) self.assertEqual(len(course_requirements), 2) # Initially, the status should be None req_status = api.get_credit_requirement_status(self.course_key, "staff", namespace="grade", name="grade") self.assertEqual(req_status[0]["status"], None) # Set the requirement to "satisfied" and check that it's actually set api.set_credit_requirement_status("staff", self.course_key, "grade", "grade") req_status = api.get_credit_requirement_status(self.course_key, "staff", namespace="grade", name="grade") self.assertEqual(req_status[0]["status"], "satisfied") # Set the requirement to "failed" and check that it's actually set api.set_credit_requirement_status("staff", self.course_key, "grade", "grade", status="failed") req_status = api.get_credit_requirement_status(self.course_key, "staff", namespace="grade", name="grade") self.assertEqual(req_status[0]["status"], "failed")
def test_min_grade_requirement_with_valid_grade(self, grade_achieved, due_date): """Test with valid grades. Deadline date does not effect in case of valid grade. """ listen_for_grade_calculation(None, self.user.username, {'percent': grade_achieved}, self.course.id, due_date) req_status = get_credit_requirement_status(self.course.id, self.request.user.username, 'grade', 'grade') self.assertEqual(req_status[0]["status"], 'satisfied')
def assert_requirement_status(self, grade, due_date, expected_status): """ Verify the user's credit requirement status is as expected after simulating a grading calculation. """ listen_for_grade_calculation(None, self.user.username, {'percent': grade}, self.course.id, due_date) req_status = get_credit_requirement_status(self.course.id, self.request.user.username, 'grade', 'grade') self.assertEqual(req_status[0]['status'], expected_status) if expected_status == 'satisfied': expected_reason = {'final_grade': grade} self.assertEqual(req_status[0]['reason'], expected_reason)
def test_min_grade_requirement_failed_grade_expired_deadline(self): """Test with failed grades and deadline expire""" listen_for_grade_calculation(None, self.user.username, {'percent': 0.22}, self.course.id, self.EXPIRED_DUE_DATE) req_status = get_credit_requirement_status(self.course.id, self.request.user.username, 'grade', 'grade') self.assertEqual(req_status[0]["status"], 'failed')
def test_min_grade_credit_requirements_status(self, mode): """ Test for credit course. If user passes minimum grade requirement then status will be updated as satisfied in requirement status table. """ self.basic_setup() # Enroll student in credit eligible mode. # Note that we can't call self.enroll here since that goes through # the Django student views, and does not update enrollment if it already exists. CourseEnrollment.enroll(self.student_user, self.course.id, mode) # Enable the course for credit CreditCourse.objects.create(course_key=self.course.id, enabled=True) # Configure a credit provider for the course CreditProvider.objects.create( provider_id="ASU", enable_integration=True, provider_url="https://credit.example.com/request", ) requirements = [{ "namespace": "grade", "name": "grade", "display_name": "Grade", "criteria": {"min_grade": 0.52}, }] # Add a single credit requirement (final grade) set_credit_requirements(self.course.id, requirements) # Credit requirement is not satisfied before passing grade req_status = get_credit_requirement_status(self.course.id, self.student_user.username, 'grade', 'grade') self.assertEqual(req_status[0]["status"], None) self._stop_signal_patch() self.submit_question_answer('p1', {'2_1': 'Correct'}) self.submit_question_answer('p2', {'2_1': 'Correct'}) # Credit requirement is now satisfied after passing grade req_status = get_credit_requirement_status(self.course.id, self.student_user.username, 'grade', 'grade') self.assertEqual(req_status[0]["status"], 'satisfied')
def test_min_grade_requirement_failed_grade_valid_deadline( self, grade_achieved, due_date): """Test with failed grades and deadline is still open or not defined.""" listen_for_grade_calculation(None, self.user.username, {'percent': grade_achieved}, self.course.id, due_date) req_status = get_credit_requirement_status(self.course.id, self.request.user.username, 'grade', 'grade') self.assertEqual(req_status[0]["status"], None)
def assert_requirement_status(self, grade, due_date, expected_status): """ Verify the user's credit requirement status is as expected after simulating a grading calculation. """ course_grade = MagicMock() course_grade.percent = grade listen_for_grade_calculation(None, self.user, course_grade, self.course.id, due_date) req_status = get_credit_requirement_status(self.course.id, self.request.user.username, 'grade', 'grade') self.assertEqual(req_status[0]['status'], expected_status) if expected_status == 'satisfied': expected_reason = {'final_grade': grade} self.assertEqual(req_status[0]['reason'], expected_reason)
def test_remove_credit_requirement_status_req_not_configured(self): # Configure a credit course with no requirements self.add_credit_course() # A user satisfies a requirement. This could potentially # happen if there's a lag when the requirements are removed # after the course is published. api.remove_credit_requirement_status("bob", self.course_key, "grade", "grade") # Since the requirement hasn't been published yet, it won't show # up in the list of requirements. req_status = api.get_credit_requirement_status(self.course_key, "bob", namespace="grade", name="grade") self.assertEqual(len(req_status), 0)
def test_set_credit_requirement_status(self): username = "******" credit_course = self.add_credit_course() requirements = [ { "namespace": "grade", "name": "grade", "display_name": "Grade", "criteria": { "min_grade": 0.8 }, }, { "namespace": "reverification", "name": "i4x://edX/DemoX/edx-reverification-block/assessment_uuid", "display_name": "Assessment 1", "criteria": {}, } ] api.set_credit_requirements(self.course_key, requirements) course_requirements = api.get_credit_requirements(self.course_key) self.assertEqual(len(course_requirements), 2) # Initially, the status should be None self.assert_grade_requirement_status(None, 0) # Requirement statuses cannot be changed if a CreditRequest exists credit_request = CreditRequest.objects.create( course=credit_course, provider=CreditProvider.objects.first(), username=username, ) api.set_credit_requirement_status(username, self.course_key, "grade", "grade") self.assert_grade_requirement_status(None, 0) credit_request.delete() # Set the requirement to "satisfied" and check that it's actually set api.set_credit_requirement_status(username, self.course_key, "grade", "grade") self.assert_grade_requirement_status('satisfied', 0) # Set the requirement to "failed" and check that it's actually set api.set_credit_requirement_status(username, self.course_key, "grade", "grade", status="failed") self.assert_grade_requirement_status('failed', 0) req_status = api.get_credit_requirement_status(self.course_key, "staff") self.assertEqual(req_status[0]["status"], "failed") self.assertEqual(req_status[0]["order"], 0) # make sure the 'order' on the 2nd requirement is set correctly (aka 1) self.assertEqual(req_status[1]["status"], None) self.assertEqual(req_status[1]["order"], 1) # Set the requirement to "declined" and check that it's actually set api.set_credit_requirement_status( username, self.course_key, "reverification", "i4x://edX/DemoX/edx-reverification-block/assessment_uuid", status="declined" ) req_status = api.get_credit_requirement_status( self.course_key, username, namespace="reverification", name="i4x://edX/DemoX/edx-reverification-block/assessment_uuid" ) self.assertEqual(req_status[0]["status"], "declined")
def assert_grade_requirement_status(self, expected_status, expected_order): """ Assert the status and order of the grade requirement. """ req_status = api.get_credit_requirement_status(self.course_key, 'staff', namespace="grade", name="grade") self.assertEqual(req_status[0]["status"], expected_status) self.assertEqual(req_status[0]["order"], expected_order) return req_status
def test_min_grade_requirement_failed_grade_valid_deadline(self, grade_achieved, due_date): """Test with failed grades and deadline is still open or not defined.""" listen_for_grade_calculation(None, self.user.username, {'percent': grade_achieved}, self.course.id, due_date) req_status = get_credit_requirement_status(self.course.id, self.request.user.username, 'grade', 'grade') self.assertEqual(req_status[0]["status"], None)