def test_lti_id_model_logic(self): # Test if a single lTI id can only be coupled to a singular assignment ltiAssignment1 = factory.LtiAssignment() ltiAssignment2 = factory.LtiAssignment() assert ltiAssignment1.active_lti_id != ltiAssignment2.active_lti_id, \ 'LTI ids of generated assignments should be unique.' ltiAssignment2.active_lti_id = ltiAssignment1.active_lti_id self.assertRaises( ValidationError, ltiAssignment2.save, msg= 'lti_id_set and assignment should be unique together for each arrayfield value' ) assert ltiAssignment2.active_lti_id in ltiAssignment2.lti_id_set, \ 'LTI ids added to the assignment should als be added to the lti_id_set' journal = factory.Journal(assignment=ltiAssignment1) journal.grade_url = 'Not None' journal.sourcedid = 'Not None' journal.save() ltiAssignment1.active_lti_id = 'new lti id' ltiAssignment1.save() # Refresh the journal instance after the assignment update journal = Journal.objects.get(pk=journal.pk) assert journal.grade_url is None and journal.sourcedid is None, \ 'Updating the active LTI id of an assignment should reset the grade_url and sourcedid of all nested ' \ 'journals'
def test_get_lti_params_from_valid_test_user(self): course = factory.LtiCourse() assignment = factory.LtiAssignment(courses=[course]) test_student = factory.TestUser() get_jwt( self, user=test_student, status=200, request_body={ 'user_id': test_student.lti_id, 'custom_course_id': course.active_lti_id, 'custom_assignment_id': assignment.active_lti_id }, response_value=lti_view.LTI_STATES.FINISH_S.value, assert_msg= 'With a course and assign linked, a test student should be forwarded to finish state.' ) test_student2 = factory.TestUser() get_jwt( self, user=test_student2, status=200, request_body={ 'user_id': test_student2.lti_id, 'custom_course_id': course.active_lti_id, 'custom_assignment_id': assignment.active_lti_id }, response_value=lti_view.LTI_STATES.FINISH_S.value, assert_msg= 'With a course and assign linked, a test student should be forwarded to finish state.' ) assert not User.objects.filter(lti_id=test_student.lti_id).exists( ), 'Max of 1 test student per course.' course2 = factory.LtiCourse() assignment2 = factory.LtiAssignment(courses=[course2]) test_student3 = factory.TestUser() get_jwt( self, user=test_student3, status=200, request_body={ 'user_id': test_student3.lti_id, 'custom_course_id': course2.active_lti_id, 'custom_assignment_id': assignment2.active_lti_id }, response_value=lti_view.LTI_STATES.FINISH_S.value, assert_msg= 'With a course and assign linked, a test student should be forwarded to finish state.' ) assert User.objects.filter(lti_id=test_student2.lti_id).exists(), \ 'Linking a test user to one course should not delete test users of a different course.'
def test_get_lti_params_from_jwt_old_assignment_teacher(self): course = factory.LtiCourse(author=self.teacher, name=REQUEST['custom_course_name']) assignment = factory.LtiAssignment( author=self.teacher, courses=[course], name=REQUEST['custom_assignment_title']) old_id = assignment.active_lti_id assignment.active_lti_id = assignment.active_lti_id + '_new' assignment.save() response = get_jwt( self, user=self.teacher, status=200, request_body={ 'user_id': self.teacher.lti_id, 'roles': 'Instructor', 'custom_course_id': course.active_lti_id, 'custom_assignment_id': old_id }, response_value=lti_view.LTI_STATES.FINISH_T.value, assert_msg= 'When a teacher joins via a no longer active lti assignment, he should still be normally' + ' forwarded.') assert response['params'][ 'jID'] is None, 'A teacher should receive no journal id'
def test_lti_delete(self): assignment = factory.LtiAssignment() course = assignment.courses.first() assert assignment.active_lti_id in course.assignment_lti_id_set, \ 'assignment lti_id should be in assignment_lti_id_set of course before anything is deleted' # Test if deletion is possible to delete assignment if it has only one lti id api.delete(self, 'assignments', params={ 'pk': assignment.pk, 'course_id': course.pk }, user=factory.Admin()) assert assignment.active_lti_id not in Course.objects.get(pk=course.pk).assignment_lti_id_set, \ 'assignment lti_id should get removed from the assignment_lti_id_set from the course' assignment = factory.LtiAssignment() course = assignment.courses.first() course2 = factory.LtiCourse() assignment.courses.add(course2) assignment.lti_id_set.append('second' + assignment.active_lti_id) assignment.save() # Test is deletion is not possible from connected LTI course api.delete(self, 'assignments', params={ 'pk': assignment.pk, 'course_id': course.pk }, user=factory.Admin(), status=400) # Test is deletion is possible from other course api.delete(self, 'assignments', params={ 'pk': assignment.pk, 'course_id': course2.pk }, user=factory.Admin())
def setUp(self): """Setup.""" self.student = factory.Student() self.teacher = factory.Teacher() self.course = factory.LtiCourse(author=self.teacher) self.assignment = factory.LtiAssignment(author=self.teacher, courses=[self.course]) self.journal = factory.Journal( assignment=self.assignment, user=self.student, sourcedid='f6d552', grade_url= 'https://uvadlo-tes.instructure.com/api/lti/v1/tools/267/grade_passback' )
def test_legit_student_from_old_uplink_update_passback(self): course = factory.LtiCourse(author=self.teacher, name=REQUEST['custom_course_name']) assignment = factory.LtiAssignment( author=self.teacher, courses=[course], name=REQUEST['custom_assignment_title']) student = factory.LtiStudent() journal = factory.Journal(user=student) assignment = journal.assignment journal_exists = Journal.objects.filter(user=student, assignment=assignment) journal_exists = journal_exists.count( ) == 1 and journal.pk == journal_exists.first().pk assert journal_exists, "The student is assumed to have a single nested journal beforehand" journal.grade_url = 'before' journal.sourcedid = 'before' course.active_lti_id = 'new' assignment.active_lti_id = 'new' course.save() assignment.save() journal.save() get_jwt( self, user=student, status=200, request_body={ 'user_id': student.lti_id, 'custom_course_id': 'new', 'custom_assignment_id': 'new', 'lis_outcome_service_url': REQUEST['lis_outcome_service_url'], 'lis_result_sourcedid': REQUEST['lis_result_sourcedid'], }, response_value=lti_view.LTI_STATES.FINISH_S.value, assert_msg= 'With a setup assignment, a legitimate student jwt connection should return FINISH_S state', ) journal = Journal.objects.get(user=student, assignment=assignment) assert journal.sourcedid == REQUEST['lis_result_sourcedid'], \ 'A legitimate student jwt route should set a journal sourcedid.' assert journal.grade_url == REQUEST['lis_outcome_service_url'], \ 'A legitimate student jwt route should set a journal grade_url.'
def test_get_lti_params_from_jwt_journal_student(self): course = factory.LtiCourse(author=self.teacher, name=REQUEST['custom_course_name']) assignment = factory.LtiAssignment( author=self.teacher, courses=[course], name=REQUEST['custom_assignment_title']) get_jwt( self, user=self.student, status=200, request_body={ 'user_id': self.student.lti_id, 'custom_course_id': course.active_lti_id, 'custom_assignment_id': assignment.active_lti_id }, response_value=lti_view.LTI_STATES.FINISH_S.value, assert_msg= 'When after assignment is created it should return the FINISH_S state for students' )
def test_legit_student_new_journal_update_passback(self): course = factory.LtiCourse(author=self.teacher, name=REQUEST['custom_course_name']) assignment = factory.LtiAssignment( author=self.teacher, courses=[course], name=REQUEST['custom_assignment_title']) student = factory.LtiStudent() journal_exists = Journal.objects.filter( user=student, assignment=assignment).exists() assert not journal_exists, "The student is assumed to have no journal beforehand" get_jwt( self, user=student, status=200, request_body={ 'user_id': student.lti_id, 'custom_course_id': course.active_lti_id, 'custom_assignment_id': assignment.active_lti_id, 'lis_outcome_service_url': REQUEST['lis_outcome_service_url'], 'lis_result_sourcedid': REQUEST['lis_result_sourcedid'], }, response_value=lti_view.LTI_STATES.FINISH_S.value, assert_msg= 'With a setup assignment, a legitimate student jwt connection should return FINISH_S state' ) journal_qry = Journal.objects.filter(user=student, assignment=assignment) assert journal_qry.count( ) == 1, 'A legitimate student jwt connection should create a single journal.' journal = journal_qry.first() assert journal.sourcedid == REQUEST['lis_result_sourcedid'], \ 'A legitimate student jwt route should set a journal sourcedid.' assert journal.grade_url == REQUEST['lis_outcome_service_url'], \ 'A legitimate student jwt route should set a journal grade_url.'
def test_get_lti_params_from_jwt_old_assignment_student_with_journal(self): course = factory.LtiCourse(author=self.teacher, name=REQUEST['custom_course_name']) assignment = factory.LtiAssignment( author=self.teacher, courses=[course], name=REQUEST['custom_assignment_title']) get_jwt( self, user=self.student, status=200, request_body={ 'user_id': self.student.lti_id, 'custom_course_id': course.active_lti_id, 'custom_assignment_id': assignment.active_lti_id }, response_value=lti_view.LTI_STATES.FINISH_S.value, assert_msg= 'When after assignment is created it should return the FINISH_S state for students' ) old_id = assignment.active_lti_id assignment.active_lti_id = assignment.active_lti_id + '_new' assignment.save() get_jwt( self, user=self.student, status=200, request_body={ 'user_id': self.student.lti_id, 'roles': 'Student', 'custom_course_id': course.active_lti_id, 'custom_assignment_id': old_id }, response_value=lti_view.LTI_STATES.FINISH_S.value, assert_msg= 'When a student with journal joins via an old LTI connection, he should still be normally ' + 'forwarded (FINISH_S state)')
def test_lti_flow_test_user(self): course = factory.LtiCourse() assignment = factory.LtiAssignment(courses=[course]) test_user_params = factory.JWTTestUserParams(user_id=get_new_lti_id()) resp = lti_launch( request_body=test_user_params, response_value=lti_view.LTI_STATES.LOGGED_IN.value, assert_msg= 'A test user should directly be created on lti launch if not exist.', ) test_student = User.objects.get(lti_id=test_user_params['user_id']) assert test_student.is_test_student, 'A new test user should be created and flagged accordingly.' total_users = User.objects.count() get_jwt( self, user=test_student, status=200, access=lti_launch_response_to_access_token(resp), request_body={ **test_user_params, 'custom_course_id': course.active_lti_id, 'custom_assignment_id': assignment.active_lti_id }, response_value=lti_view.LTI_STATES.FINISH_S.value, assert_msg= 'With a course and assign linked, a fresh test student should be forwarded to finish state.' ) resp = lti_launch( request_body=test_user_params, response_value=lti_view.LTI_STATES.LOGGED_IN.value, assert_msg= 'A reused test user can launch succesfully after being created.', ) get_jwt( self, user=test_student, status=200, access=lti_launch_response_to_access_token(resp), request_body={ **test_user_params, 'custom_course_id': course.active_lti_id, 'custom_assignment_id': assignment.active_lti_id }, response_value=lti_view.LTI_STATES.FINISH_S.value, assert_msg= 'With a course and assign linked, a reused test student should be forwarded to finish state.' ) assert total_users == User.objects.count( ), 'Launching and relaunching should create no additional users.' # Test the flow of another test user part of the same course and assignment test_user_params2 = factory.JWTTestUserParams(user_id=get_new_lti_id()) resp = lti_launch(request_body=test_user_params2, response_value=lti_view.LTI_STATES.LOGGED_IN.value) test_student2 = User.objects.get(lti_id=test_user_params2['user_id']) get_jwt( self, user=test_student2, status=200, access=lti_launch_response_to_access_token(resp), request_body={ **test_user_params2, 'custom_course_id': course.active_lti_id, 'custom_assignment_id': assignment.active_lti_id }, response_value=lti_view.LTI_STATES.FINISH_S.value, assert_msg= 'A second fresh test student from the same course and assign should be forwarded to finish state' ) assert User.objects.filter(lti_id=test_user_params2['user_id']).exists( ), 'Second test user should be created.' assert not User.objects.filter(lti_id=test_student.lti_id).exists( ), 'Can only be one test student per course.'
def test_check_if_need_VLE_publish_no_journals(self): """Hopefully doesnt crash.""" course = factory.LtiCourse() factory.LtiAssignment(courses=[course]) lti_beats.check_if_need_VLE_publish()