class LtiUserDataTest(TestCase): minimal_valid_lti_parameters = { 'lis_result_sourcedid': 'result-sourced-id', 'lis_outcome_service_url': 'lis-outcome-service-url' } def setUp(self): self.model = LtiUserData( edx_lti_parameters=self.minimal_valid_lti_parameters) def test_send_lti_grade_empty_lti_parameters_raises_value_error(self, _): self.model.edx_lti_parameters = None with self.assertRaises(ValueError) as exc: self.model.send_lti_grade(0) self.assertEqual("LTI grade parameters is not set", exc.message) @ddt.data( {'lis_result_sourcedid': '111'}, {'lis_outcome_service_url': '111'}, { 'lis_result_sourcedid': '', 'lis_outcome_service_url': '111' }, { 'lis_result_sourcedid': '111', 'lis_outcome_service_url': '' }, ) def test_send_lti_grade_missing_lti_parameters_raises_value_error( self, lti_parameters, _): self.model.edx_lti_parameters = lti_parameters with self.assertRaises(ValueError) as exc: self.model.send_lti_grade(0) self.assertIn("Following required LTI parameters are not set", exc.message) @ddt.data(-1, 2, 1 + 10**-10, -10**-10, 7, 5, 42, -14) def test_send_lti_grade_incorrect_grade_raises_value_error( self, incorrect_grade, _): with self.assertRaises(ValueError) as exc: self.model.send_lti_grade(incorrect_grade) self.assertIn("Grade should be in range [0..1]", exc.message) @override_settings(LTI_CLIENT_KEY='client_key', LTI_CLIENT_SECRET='lti_client_secret') def test_send_lti_grade_creates_tool_provider( self, tool_provider_constructor_mock): self.model.send_lti_grade(0) tool_provider_constructor_mock.assert_called_with( 'client_key', 'lti_client_secret', self.model.edx_lti_parameters) @ddt.data(*[1.0 - i * 0.1 for i in xrange(10, -1, -1)]) def test_send_lti_grade_sends_replace_result_request( self, grade, tool_provider_constructor_mock): tool_provider_mock = tool_provider_constructor_mock.return_value self.model.send_lti_grade(grade) tool_provider_mock.post_replace_result.assert_called_with(grade)
def log_in_with_lti(self, user=None, password=None, lti_params=None): """Log a user in with fake LTI data.""" if user is None: user = self.user if lti_params is None: lti_params = self.LTI_PARAMS.copy() lti_params['lis_person_sourcedid'] = user.username lti_params['lis_person_contact_email_primary'] = user.email lti_params['custom_assignment_id'] = unicode(self.assignment.pk) lti_params['custom_question_id'] = unicode(self.question.pk) LtiUserData.store_lti_parameters(user, LTIView.authentication_manager, lti_params) self.client.login(username=user.username, password=password or 'test')
class LtiUserDataTest(TestCase): minimal_valid_lti_parameters = { 'lis_result_sourcedid': 'result-sourced-id', 'lis_outcome_service_url': 'lis-outcome-service-url' } def setUp(self): self.model = LtiUserData(edx_lti_parameters=self.minimal_valid_lti_parameters) def test_send_lti_grade_empty_lti_parameters_raises_value_error(self, _): self.model.edx_lti_parameters = None with self.assertRaises(ValueError) as exc: self.model.send_lti_grade(0) self.assertEqual("LTI grade parameters is not set", exc.message) @ddt.data( {'lis_result_sourcedid': '111'}, {'lis_outcome_service_url': '111'}, {'lis_result_sourcedid': '', 'lis_outcome_service_url': '111'}, {'lis_result_sourcedid': '111', 'lis_outcome_service_url': ''}, ) def test_send_lti_grade_missing_lti_parameters_raises_value_error(self, lti_parameters, _): self.model.edx_lti_parameters = lti_parameters with self.assertRaises(ValueError) as exc: self.model.send_lti_grade(0) self.assertIn("Following required LTI parameters are not set", exc.message) @ddt.data( -1, 2, 1 + 10 ** -10, -10 ** -10, 7, 5, 42, -14 ) def test_send_lti_grade_incorrect_grade_raises_value_error(self, incorrect_grade, _): with self.assertRaises(ValueError) as exc: self.model.send_lti_grade(incorrect_grade) self.assertIn("Grade should be in range [0..1]", exc.message) @override_settings(LTI_CLIENT_KEY='client_key', LTI_CLIENT_SECRET='lti_client_secret') def test_send_lti_grade_creates_tool_provider(self, tool_provider_constructor_mock): self.model.send_lti_grade(0) tool_provider_constructor_mock.assert_called_with('client_key', 'lti_client_secret', self.model.edx_lti_parameters) @ddt.data(*[1.0 - i * 0.1 for i in xrange(10, -1, -1)]) def test_send_lti_grade_sends_replace_result_request(self, grade, tool_provider_constructor_mock): tool_provider_mock = tool_provider_constructor_mock.return_value self.model.send_lti_grade(grade) tool_provider_mock.post_replace_result.assert_called_with(grade)
def test_send_grade_loose_suppresses_and_logs_does_not_exist( self, get_user_data): get_user_data.side_effect = LtiUserData.DoesNotExist() with self.assertRaises(LtiUserData.DoesNotExist), \ patch("django_lti_tool_provider.signals._logger.info") as patched_log_info: _send_grade(Mock(), 0, None) patched_log_info.assert_called_once() call_args = patched_log_info.call_args[0] self.assertIn("No LTI parameters", call_args[0])
def _right_user(cls, user, lti_parameters): try: info, created = LtiUserData.get_or_create_by_parameters( user, cls.authentication_manager, cls.lti_param_filter(lti_parameters), create=False ) if created: # If this is the first time the user's data is being created, that means # that the user predated the LTI request. info.delete() return False return True except (WrongUserError, LtiUserData.DoesNotExist): return False
def _right_user(cls, user, lti_parameters): try: info, created = LtiUserData.get_or_create_by_parameters( user, cls.authentication_manager, cls.lti_param_filter(lti_parameters), create=False) if created: # If this is the first time the user's data is being created, that means # that the user predated the LTI request. info.delete() return False return True except (WrongUserError, LtiUserData.DoesNotExist): return False
2. This is OpenID redirect from edx if actual LTI request was send anonymously - already validated LTI parameters and stored them in session - take them from session When lti parameters are ready (either taken from session or parsed and validated from request) store them in DB for later """ if cls.SESSION_KEY in request.session and not cls._is_new_lti_request( request): lti_parameters = request.session[cls.SESSION_KEY] del request.session[cls.SESSION_KEY] else: try: lti_parameters = cls._get_lti_parameters_from_request(request) except oauth2.Error, e: _logger.exception(u"Invalid LTI Request") return HttpResponseBadRequest(u"Invalid LTI Request: " + e.message) lti_data = LtiUserData.store_lti_parameters( request.user, cls.authentication_manager, cls.lti_param_filter(lti_parameters)) Signals.LTI.received.send(cls, user=request.user, lti_data=lti_data) return HttpResponseRedirect( cls.authentication_manager.authenticated_redirect_to( request, lti_parameters)) @classmethod def _is_new_lti_request(cls, request): return 'lis_result_sourcedid' in request.POST
def process_authenticated_lti(cls, request): """ There are two options: 1. This is actual LTI request made with cookies already set - need parsing and validating LTI parameters 2. This is OpenID redirect from edx if actual LTI request was send anonymously - already validated LTI parameters and stored them in session - take them from session When lti parameters are ready (either taken from session or parsed and validated from request) store them in DB for later """ if cls.SESSION_KEY in request.session and not cls._is_new_lti_request(request): lti_parameters = request.session[cls.SESSION_KEY] del request.session[cls.SESSION_KEY] else: try: lti_parameters = cls._get_lti_parameters_from_request(request) except oauth2.Error, e: _logger.exception(u"Invalid LTI Request") return HttpResponseBadRequest(u"Invalid LTI Request: " + e.message) lti_data = LtiUserData.store_lti_parameters( request.user, cls.authentication_manager, cls.lti_param_filter(lti_parameters) ) Signals.LTI.received.send(cls, user=request.user, lti_data=lti_data) return HttpResponseRedirect(cls.authentication_manager.authenticated_redirect_to(request, lti_parameters)) @classmethod def _is_new_lti_request(cls, request): return 'lis_result_sourcedid' in request.POST
def setUp(self): self.model = LtiUserData(edx_lti_parameters=self.minimal_valid_lti_parameters)
def setUp(self): self.model = LtiUserData( edx_lti_parameters=self.minimal_valid_lti_parameters)
def test_send_grade_no_lti_user_data_raises_does_not_exist( self, get_user_data): get_user_data.side_effect = LtiUserData.DoesNotExist() with self.assertRaises(LtiUserData.DoesNotExist): _send_grade(Mock(), 0, None)