def test_sender_sets_lineitems_url_with_the_value_in_auth_state_dict( self, lti_config_environ): sut = LTI13GradeSender('course-id', 'lab', { 'course_lineitems': 'canvas.docker.com/api/lti/courses/1/line_items' }) assert sut.lineitems_url == 'canvas.docker.com/api/lti/courses/1/line_items'
async def test_sender_raises_AssignmentWithoutGradesError_if_there_are_no_grades( self, lti13_config_environ, mock_nbhelper): sut = LTI13GradeSender('course-id', 'lab') with patch.object(LTI13GradeSender, '_retrieve_grades_from_db', return_value=(lambda: 10, [])): with pytest.raises(AssignmentWithoutGradesError): await sut.send_grades()
async def test_get_lineitems_from_url_method_sets_all_lineitems_property( self, lti13_config_environ, mock_nbhelper, http_async_httpclient_with_simple_response): sut = LTI13GradeSender('course-id', 'lab') await sut._get_lineitems_from_url( 'https://example.canvas.com/api/lti/courses/111/line_items') assert len(sut.all_lineitems) == 1
async def test_sender_raises_AssignmentWithoutGradesError_if_there_are_not_grades( self, lti_config_environ): sut = LTI13GradeSender('course-id', 'lab', { 'course_lineitems': 'canvas.docker.com/api/lti/courses/1/line_items' }) with patch.object(LTI13GradeSender, '_retrieve_grades_from_db', return_value=(lambda: 10, [])): with pytest.raises(AssignmentWithoutGradesError): await sut.send_grades()
async def test_get_lineitems_from_url_method_does_fetch_lineitems_from_url( self, lti13_config_environ, mock_nbhelper, make_http_response, make_mock_request_handler): local_handler = make_mock_request_handler(RequestHandler) sut = LTI13GradeSender('course-id', 'lab') lineitems_url = 'https://example.canvas.com/api/lti/courses/111/line_items' with patch.object(AsyncHTTPClient, 'fetch', return_value=make_http_response( handler=local_handler.request)) as mock_client: await sut._get_lineitems_from_url(lineitems_url) assert mock_client.called mock_client.assert_called_with(lineitems_url, method='GET', headers={})
async def test_sender_raises_an_error_if_no_line_items_were_found( self, lti13_config_environ, http_async_httpclient_with_simple_response, mock_nbhelper): sut = LTI13GradeSender('course-id', 'lab') access_token_result = {'token_type': '', 'access_token': ''} with patch('illumidesk.grades.senders.get_lms_access_token', return_value=access_token_result): with patch.object(LTI13GradeSender, '_retrieve_grades_from_db', return_value=(lambda: 10, [{ 'score': 10 }])): with pytest.raises(GradesSenderMissingInfoError): await sut.send_grades()
async def post(self, course_id: str, assignment_name: str) -> None: """ Receives a request with the course name and the assignment name as path parameters which then uses the appropriate class to send grades to the platform based on the LTI authenticator version (1.1 or 1.3). Arguments: course_id: course name which has been previously normalized by the LTIUtils.normalize_string function. assignment_name: assignment name which should coincide with the assignment name within the LMS. Raises: GradesSenderCriticalError if there was a critical error when either extracting grades from the db or sending grades to the tool consumer / platform. AssignmentWithoutGradesError if the assignment does not have any grades associated to it. GradesSenderMissingInfoError if ther is missing information when attempting to send grades. """ self.log.debug( f'Data received to send grades-> course:{course_id}, assignment:{assignment_name}' ) lti_grade_sender = None # check lti version by the authenticator setting if isinstance(self.authenticator, LTI11Authenticator ) or self.authenticator is LTI11Authenticator: lti_grade_sender = LTIGradeSender(course_id, assignment_name) else: lti_grade_sender = LTI13GradeSender(course_id, assignment_name) try: await lti_grade_sender.send_grades() except exceptions.GradesSenderCriticalError: raise web.HTTPError( 400, 'There was an critical error, please check logs.') except exceptions.AssignmentWithoutGradesError: raise web.HTTPError(400, 'There are no grades yet to submit') except exceptions.GradesSenderMissingInfoError as e: self.log.error(f'There are missing values.{e}') raise web.HTTPError( 400, f'Impossible to send grades. There are missing values, please check logs.{e}' ) self.write(json.dumps({"success": True}))
async def test_sender_calls__set_access_token_header_before_to_send_grades( self, lti_config_environ): sut = LTI13GradeSender('course-id', 'lab', { 'course_lineitems': 'canvas.docker.com/api/lti/courses/1/line_items' }) local_handler = mock_handler(RequestHandler) access_token_result = {'token_type': '', 'access_token': ''} line_item_result = { 'label': 'lab', 'id': 'line_item_url', 'scoreMaximum': 40 } with patch('illumidesk.grades.senders.get_lms_access_token', return_value=access_token_result) as mock_method: with patch.object( LTI13GradeSender, '_retrieve_grades_from_db', return_value=(lambda: 10, [{ 'score': 10, 'lms_user_id': 'id' }]), ): with patch.object( AsyncHTTPClient, 'fetch', side_effect=[ factory_http_response( handler=local_handler.request, body=[line_item_result]), factory_http_response( handler=local_handler.request, body=line_item_result), factory_http_response( handler=local_handler.request, body=[]), ], ): await sut.send_grades() assert mock_method.called
async def test_get_lineitems_from_url_method_calls_itself_recursively( self, lti13_config_environ, mock_nbhelper, make_http_response, make_mock_request_handler): local_handler = make_mock_request_handler(RequestHandler) sut = LTI13GradeSender('course-id', 'lab') lineitems_body_result = { 'body': [{ "id": "value", "scoreMaximum": 0.0, "label": "label", "resourceLinkId": "abc" }] } lineitems_body_result['headers'] = HTTPHeaders({ 'content-type': 'application/vnd.ims.lis.v2.lineitemcontainer+json', 'link': '<https://learning.flatironschool.com/api/lti/courses/691/line_items?page=2&per_page=10>; rel="next"', }) with patch.object( AsyncHTTPClient, 'fetch', side_effect=[ make_http_response(handler=local_handler.request, **lineitems_body_result), make_http_response(handler=local_handler.request, body=lineitems_body_result['body']), ], ) as mock_fetch: # initial call then the method will detect the Link header to get the next items await sut._get_lineitems_from_url( 'https://example.canvas.com/api/lti/courses/111/line_items') # assert the lineitems number assert len(sut.all_lineitems) == 2 # assert the number of calls assert mock_fetch.call_count == 2
def test_sender_sets_lineitems_url_with_the_value_in_auth_state_dict( self, lti13_config_environ, mock_nbhelper): sut = LTI13GradeSender('course-id', 'lab') assert sut.course.lms_lineitems_endpoint == 'canvas.docker.com/api/lti/courses/1/line_items'
def test_sender_raises_an_error_without_auth_state_information(self): with pytest.raises(GradesSenderMissingInfoError): LTI13GradeSender('course-id', 'lab', None)