def student_view(self, context=None): user_allowed = False user_state = {} message = "" lti_parameters = {} fragment = Fragment() context.update(self._get_context_for_template()) child_fragments = self.runtime.render_children(block=self, view_name='student_view', context=context) context.update({"child_fragments": child_fragments}) if self._is_studio(): # studio view context["lms_link"] = get_lms_link_for_item(self.location) if get_lms_link_for_item else "" fragment.add_content(self._render_template('static/html/studio.html', context)) else: # Student view if self.launch_url and self._get_exam_id(): try: lti_consumer = LtiConsumer(self) lti_parameters = lti_consumer.get_signed_lti_parameters() exam_id = self._get_exam_id() user_state = self.get_proctorexam_user_state( self._get_exam_id(), lti_parameters ) context["user_state"] = user_state except LtiError: message = _("Proctor Exam xblock configuration is incomplete, LTI passport is invalid") else: message = _("Proctor Exam xblock configuration is incomplete, exam URL is missing") if user_state and "student" in user_state and (user_state["student"].get("status") == "exam_started"): # User have completed Proctor Exam indentification process, # we show him exam content html = self._render_template('static/html/sequence.html', context) fragment.add_content(html) fragment.add_frags_resources(child_fragments) else: if self._allowed_verified(): # User have to complete Proctor Exam indentification process context.update({'lti_parameters': lti_parameters, "message": message}) html = self._render_template("static/html/student.html", context) else: html = self._render_template("static/html/honor.html", context) fragment.add_content(html) fragment.add_css(self.resource_string('static/css/student.css')) return fragment
def setUp(self): super(TestLtiConsumer, self).setUp() self.lti_consumer = LtiConsumer(self.xblock)
class TestLtiConsumer(TestLtiConsumerXBlock): """ Unit tests for LtiConsumer """ def setUp(self): super(TestLtiConsumer, self).setUp() self.lti_consumer = LtiConsumer(self.xblock) @patch( 'lti_consumer.lti.get_oauth_request_signature', Mock(return_value=( 'OAuth oauth_nonce="fake_nonce", ' 'oauth_timestamp="fake_timestamp", oauth_version="fake_version", oauth_signature_method="fake_method", ' 'oauth_consumer_key="fake_consumer_key", oauth_signature="fake_signature"' )) ) @patch( 'lti_consumer.lti_consumer.LtiConsumerXBlock.prefixed_custom_parameters', PropertyMock(return_value={u'custom_param_1': 'custom1', u'custom_param_2': 'custom2'}) ) @patch( 'lti_consumer.lti_consumer.LtiConsumerXBlock.lti_provider_key_secret', PropertyMock(return_value=('t', 's')) ) @patch('lti_consumer.lti_consumer.LtiConsumerXBlock.user_id', PropertyMock(return_value=FAKE_USER_ID)) def test_get_signed_lti_parameters(self): """ Test `get_signed_lti_parameters` returns the correct dict """ expected_lti_parameters = { u'user_id': self.lti_consumer.xblock.user_id, u'oauth_callback': u'about:blank', u'launch_presentation_return_url': '', u'lti_message_type': u'basic-lti-launch-request', u'lti_version': 'LTI-1p0', u'roles': self.lti_consumer.xblock.role, u'resource_link_id': self.lti_consumer.xblock.resource_link_id, u'lis_result_sourcedid': self.lti_consumer.xblock.lis_result_sourcedid, u'context_id': self.lti_consumer.xblock.context_id, u'lis_outcome_service_url': self.lti_consumer.xblock.outcome_service_url, 'lis_person_sourcedid': 'edx', 'lis_person_contact_email_primary': '*****@*****.**', u'custom_param_1': 'custom1', u'custom_param_2': 'custom2', u'oauth_nonce': 'fake_nonce', 'oauth_timestamp': 'fake_timestamp', 'oauth_version': 'fake_version', 'oauth_signature_method': 'fake_method', 'oauth_consumer_key': 'fake_consumer_key', 'oauth_signature': u'fake_signature' } self.lti_consumer.xblock.has_score = True self.lti_consumer.xblock.ask_to_send_username = True self.lti_consumer.xblock.ask_to_send_email = True self.lti_consumer.xblock.runtime.get_real_user.return_value = Mock(email='*****@*****.**', username='******') self.assertEqual(self.lti_consumer.get_signed_lti_parameters(), expected_lti_parameters) # Test that `lis_person_sourcedid` and `lis_person_contact_email_primary` are not included # in the returned LTI parameters when a user cannot be found self.lti_consumer.xblock.runtime.get_real_user.return_value = {} del expected_lti_parameters['lis_person_sourcedid'] del expected_lti_parameters['lis_person_contact_email_primary'] self.assertEqual(self.lti_consumer.get_signed_lti_parameters(), expected_lti_parameters) def test_get_result(self): """ Test `get_result` returns valid json response """ self.xblock.module_score = 0.9 self.xblock.score_comment = 'Great Job!' response = dict(GET_RESULT_RESPONSE) response.update({ "resultScore": self.xblock.module_score, "comment": self.xblock.score_comment }) self.assertEqual(self.lti_consumer.get_result(Mock()), response) self.xblock.module_score = None self.xblock.score_comment = '' self.assertEqual(self.lti_consumer.get_result(Mock()), GET_RESULT_RESPONSE) @patch('lti_consumer.lti_consumer.LtiConsumerXBlock.clear_user_module_score') def test_delete_result(self, mock_clear): """ Test `delete_result` calls `LtiConsumerXBlock.clear_user_module_score` """ user = Mock() response = self.lti_consumer.delete_result(user) mock_clear.assert_called_with(user) self.assertEqual(response, {}) @patch('lti_consumer.lti_consumer.LtiConsumerXBlock.max_score', Mock(return_value=1.0)) @patch('lti_consumer.lti_consumer.LtiConsumerXBlock.set_user_module_score') @patch('lti_consumer.lti_consumer.LtiConsumerXBlock.clear_user_module_score') @patch('lti_consumer.lti.parse_result_json') def test_put_result(self, mock_parse, mock_clear, mock_set): """ Test `put_result` calls `LtiConsumerXBlock.set_user_module_score` or `LtiConsumerXblock.clear_user_module_score` if resultScore not included in request """ user = Mock() score = 0.9 comment = 'Great Job!' mock_parse.return_value = (score, comment) response = self.lti_consumer.put_result(user, '') mock_set.assert_called_with(user, score, 1.0, comment) self.assertEqual(response, {}) mock_parse.return_value = (None, '') response = self.lti_consumer.put_result(user, '') mock_clear.assert_called_with(user) self.assertEqual(response, {}) @patch('lti_consumer.lti.log') def test_verify_result_headers_verify_content_type_true(self, mock_log): """ Test wrong content type raises exception if `verify_content_type` is True """ request = make_request('') with self.assertRaises(LtiError): self.lti_consumer.verify_result_headers(request) self.assertTrue(mock_log.called) @patch('lti_consumer.lti.verify_oauth_body_signature', Mock(return_value=True)) @patch('lti_consumer.lti_consumer.LtiConsumerXBlock.lti_provider_key_secret', PropertyMock(return_value=('t', 's'))) def test_verify_result_headers_verify_content_type_false(self): """ Test content type check skipped if `verify_content_type` is False """ request = make_request('') request.environ['CONTENT_TYPE'] = LtiConsumer.CONTENT_TYPE_RESULT_JSON response = self.lti_consumer.verify_result_headers(request, False) self.assertTrue(response) @patch('lti_consumer.lti.verify_oauth_body_signature', Mock(return_value=True)) @patch('lti_consumer.lti_consumer.LtiConsumerXBlock.lti_provider_key_secret', PropertyMock(return_value=('t', 's'))) def test_verify_result_headers_valid(self): """ Test True is returned if request is valid """ request = make_request('') request.environ['CONTENT_TYPE'] = LtiConsumer.CONTENT_TYPE_RESULT_JSON response = self.lti_consumer.verify_result_headers(request) self.assertTrue(response) @patch('lti_consumer.lti.verify_oauth_body_signature', Mock(side_effect=LtiError)) @patch('lti_consumer.lti_consumer.LtiConsumerXBlock.lti_provider_key_secret', PropertyMock(return_value=('t', 's'))) @patch('lti_consumer.lti.log') def test_verify_result_headers_lti_error(self, mock_log): """ Test exception raised if request header verification raises error """ request = make_request('') request.environ['CONTENT_TYPE'] = LtiConsumer.CONTENT_TYPE_RESULT_JSON with self.assertRaises(LtiError): self.lti_consumer.verify_result_headers(request) self.assertTrue(mock_log.called) @patch('lti_consumer.lti.verify_oauth_body_signature', Mock(side_effect=ValueError)) @patch('lti_consumer.lti_consumer.LtiConsumerXBlock.lti_provider_key_secret', PropertyMock(return_value=('t', 's'))) @patch('lti_consumer.lti.log') def test_verify_result_headers_value_error(self, mock_log): """ Test exception raised if request header verification raises error """ request = make_request('') request.environ['CONTENT_TYPE'] = LtiConsumer.CONTENT_TYPE_RESULT_JSON with self.assertRaises(LtiError): self.lti_consumer.verify_result_headers(request) self.assertTrue(mock_log.called)
class TestLtiConsumer(TestLtiConsumerXBlock): """ Unit tests for LtiConsumer """ def setUp(self): super(TestLtiConsumer, self).setUp() self.lti_consumer = LtiConsumer(self.xblock) @patch( 'lti_consumer.lti.get_oauth_request_signature', Mock(return_value=( 'OAuth oauth_nonce="fake_nonce", ' 'oauth_timestamp="fake_timestamp", oauth_version="fake_version", oauth_signature_method="fake_method", ' 'oauth_consumer_key="fake_consumer_key", oauth_signature="fake_signature"' )) ) @patch( 'lti_consumer.lti_consumer.LtiConsumerXBlock.prefixed_custom_parameters', PropertyMock(return_value={u'custom_param_1': 'custom1', u'custom_param_2': 'custom2'}) ) @patch( 'lti_consumer.lti_consumer.LtiConsumerXBlock.lti_provider_key_secret', PropertyMock(return_value=('t', 's')) ) @patch('lti_consumer.lti_consumer.LtiConsumerXBlock.user_id', PropertyMock(return_value=FAKE_USER_ID)) def test_get_signed_lti_parameters(self): """ Test `get_signed_lti_parameters` returns the correct dict """ self.lti_consumer.xblock.due = timezone.now() self.lti_consumer.xblock.graceperiod = timedelta(days=1) expected_lti_parameters = { u'user_id': self.lti_consumer.xblock.user_id, u'oauth_callback': u'about:blank', u'launch_presentation_return_url': '', u'lti_message_type': u'basic-lti-launch-request', u'lti_version': 'LTI-1p0', u'roles': self.lti_consumer.xblock.role, u'resource_link_id': self.lti_consumer.xblock.resource_link_id, u'lis_result_sourcedid': self.lti_consumer.xblock.lis_result_sourcedid, u'context_id': self.lti_consumer.xblock.context_id, u'lis_outcome_service_url': self.lti_consumer.xblock.outcome_service_url, u'custom_component_display_name': self.lti_consumer.xblock.display_name, u'custom_component_due_date': self.lti_consumer.xblock.due.strftime('%Y-%m-%d %H:%M:%S'), u'custom_component_graceperiod': str(self.lti_consumer.xblock.graceperiod.total_seconds()), u'custom_user_id': unicode(5), 'lis_person_sourcedid': 'edx', 'lis_person_contact_email_primary': '*****@*****.**', 'lis_person_name_given': 'Jane', 'lis_person_name_family': 'Doe', 'lis_person_name_full': 'Jane Doe', 'launch_presentation_locale': 'en', u'custom_param_1': 'custom1', u'custom_param_2': 'custom2', u'oauth_nonce': 'fake_nonce', 'oauth_timestamp': 'fake_timestamp', 'oauth_version': 'fake_version', 'oauth_signature_method': 'fake_method', 'oauth_consumer_key': 'fake_consumer_key', 'oauth_signature': u'fake_signature' } self.lti_consumer.xblock.has_score = True self.lti_consumer.xblock.ask_to_send_username = True self.lti_consumer.xblock.ask_to_send_email = True self.lti_consumer.xblock.ask_to_send_first_name = True self.lti_consumer.xblock.ask_to_send_last_name = True self.lti_consumer.xblock.ask_to_send_full_name = True self.lti_consumer.xblock.runtime.get_real_user.return_value = Mock( id=5, email='*****@*****.**', username='******', profile=Mock(filter=Mock(return_value=[Mock(value='Jane Doe')])), preferences=Mock(filter=Mock(return_value=[Mock(value='en')])) ) self.assertEqual(self.lti_consumer.get_signed_lti_parameters(), expected_lti_parameters) # Test that `lis_person_name_family` returns empty string when `lis_person_name_full` # contains only one name expected_lti_parameters.update({ "lis_person_name_family": "", "lis_person_name_full": "Jane" }) self.lti_consumer.xblock.runtime.get_real_user.return_value = Mock( id=5, email='*****@*****.**', username='******', profile=Mock(filter=Mock(return_value=[Mock(value='Jane')])), preferences=Mock(filter=Mock(return_value=[Mock(value='en')])) ) self.assertEqual(self.lti_consumer.get_signed_lti_parameters(), expected_lti_parameters) # Test that `custom_user_id`, `lis_person_sourcedid`, `lis_person_contact_email_primary`, # `lis_person_name_given`, `lis_person_name_family`, `lis_person_name_full` # and `launch_presentation_locale` are not included in the returned # LTI parameters when a user cannot be found self.lti_consumer.xblock.runtime.get_real_user.return_value = {} del expected_lti_parameters['custom_user_id'] del expected_lti_parameters['lis_person_sourcedid'] del expected_lti_parameters['lis_person_contact_email_primary'] del expected_lti_parameters['lis_person_name_given'] del expected_lti_parameters['lis_person_name_family'] del expected_lti_parameters['lis_person_name_full'] del expected_lti_parameters['launch_presentation_locale'] self.assertEqual(self.lti_consumer.get_signed_lti_parameters(), expected_lti_parameters) def test_get_result(self): """ Test `get_result` returns valid json response """ self.xblock.module_score = 0.9 self.xblock.score_comment = 'Great Job!' response = dict(GET_RESULT_RESPONSE) response.update({ "resultScore": self.xblock.module_score, "comment": self.xblock.score_comment }) self.assertEqual(self.lti_consumer.get_result(Mock()), response) self.xblock.module_score = None self.xblock.score_comment = '' self.assertEqual(self.lti_consumer.get_result(Mock()), GET_RESULT_RESPONSE) @patch('lti_consumer.lti_consumer.LtiConsumerXBlock.clear_user_module_score') def test_delete_result(self, mock_clear): """ Test `delete_result` calls `LtiConsumerXBlock.clear_user_module_score` """ user = Mock() response = self.lti_consumer.delete_result(user) mock_clear.assert_called_with(user) self.assertEqual(response, {}) @patch('lti_consumer.lti_consumer.LtiConsumerXBlock.max_score', Mock(return_value=1.0)) @patch('lti_consumer.lti_consumer.LtiConsumerXBlock.set_user_module_score') @patch('lti_consumer.lti_consumer.LtiConsumerXBlock.clear_user_module_score') @patch('lti_consumer.lti.parse_result_json') def test_put_result(self, mock_parse, mock_clear, mock_set): """ Test `put_result` calls `LtiConsumerXBlock.set_user_module_score` or `LtiConsumerXblock.clear_user_module_score` if resultScore not included in request """ user = Mock() score = 0.9 comment = 'Great Job!' mock_parse.return_value = (score, comment) response = self.lti_consumer.put_result(user, '') mock_set.assert_called_with(user, score, 1.0, comment) self.assertEqual(response, {}) mock_parse.return_value = (None, '') response = self.lti_consumer.put_result(user, '') mock_clear.assert_called_with(user) self.assertEqual(response, {}) @patch('lti_consumer.lti.log') def test_verify_result_headers_verify_content_type_true(self, mock_log): """ Test wrong content type raises exception if `verify_content_type` is True """ request = make_request('') with self.assertRaises(LtiError): self.lti_consumer.verify_result_headers(request) self.assertTrue(mock_log.called) @patch('lti_consumer.lti.verify_oauth_body_signature', Mock(return_value=True)) @patch('lti_consumer.lti_consumer.LtiConsumerXBlock.lti_provider_key_secret', PropertyMock(return_value=('t', 's'))) def test_verify_result_headers_verify_content_type_false(self): """ Test content type check skipped if `verify_content_type` is False """ request = make_request('') request.environ['CONTENT_TYPE'] = LtiConsumer.CONTENT_TYPE_RESULT_JSON response = self.lti_consumer.verify_result_headers(request, False) self.assertTrue(response) @patch('lti_consumer.lti.verify_oauth_body_signature', Mock(return_value=True)) @patch('lti_consumer.lti_consumer.LtiConsumerXBlock.lti_provider_key_secret', PropertyMock(return_value=('t', 's'))) def test_verify_result_headers_valid(self): """ Test True is returned if request is valid """ request = make_request('') request.environ['CONTENT_TYPE'] = LtiConsumer.CONTENT_TYPE_RESULT_JSON response = self.lti_consumer.verify_result_headers(request) self.assertTrue(response) @patch('lti_consumer.lti.verify_oauth_body_signature', Mock(side_effect=LtiError)) @patch('lti_consumer.lti_consumer.LtiConsumerXBlock.lti_provider_key_secret', PropertyMock(return_value=('t', 's'))) @patch('lti_consumer.lti.log') def test_verify_result_headers_lti_error(self, mock_log): """ Test exception raised if request header verification raises error """ request = make_request('') request.environ['CONTENT_TYPE'] = LtiConsumer.CONTENT_TYPE_RESULT_JSON with self.assertRaises(LtiError): self.lti_consumer.verify_result_headers(request) self.assertTrue(mock_log.called) @patch('lti_consumer.lti.verify_oauth_body_signature', Mock(side_effect=ValueError)) @patch('lti_consumer.lti_consumer.LtiConsumerXBlock.lti_provider_key_secret', PropertyMock(return_value=('t', 's'))) @patch('lti_consumer.lti.log') def test_verify_result_headers_value_error(self, mock_log): """ Test exception raised if request header verification raises error """ request = make_request('') request.environ['CONTENT_TYPE'] = LtiConsumer.CONTENT_TYPE_RESULT_JSON with self.assertRaises(LtiError): self.lti_consumer.verify_result_headers(request) self.assertTrue(mock_log.called)
class TestLtiConsumer(TestLtiConsumerXBlock): """ Unit tests for LtiConsumer """ def setUp(self): super(TestLtiConsumer, self).setUp() self.lti_consumer = LtiConsumer(self.xblock) def _update_xblock_for_signed_parameters(self): """ Prepare the LTI XBlock for signing the parameters. """ self.lti_consumer.xblock.due = timezone.now() self.lti_consumer.xblock.graceperiod = timedelta(days=1) self.lti_consumer.xblock.has_score = True self.lti_consumer.xblock.ask_to_send_username = True self.lti_consumer.xblock.ask_to_send_email = True self.lti_consumer.xblock.runtime.get_real_user.return_value = Mock( email='*****@*****.**', username='******', preferences=Mock(filter=Mock(return_value=[Mock(value='en')]))) @patch_signed_parameters def test_get_signed_lti_parameters(self): """ Test `get_signed_lti_parameters` returns the correct dict """ self._update_xblock_for_signed_parameters() expected_lti_parameters = { text_type('user_id'): self.lti_consumer.xblock.user_id, text_type('oauth_callback'): 'about:blank', text_type('launch_presentation_return_url'): '', text_type('lti_message_type'): 'basic-lti-launch-request', text_type('lti_version'): 'LTI-1p0', text_type('roles'): self.lti_consumer.xblock.role, text_type('resource_link_id'): self.lti_consumer.xblock.resource_link_id, text_type('lis_result_sourcedid'): self.lti_consumer.xblock.lis_result_sourcedid, text_type('context_id'): self.lti_consumer.xblock.context_id, text_type('lis_outcome_service_url'): self.lti_consumer.xblock.outcome_service_url, text_type('custom_component_display_name'): self.lti_consumer.xblock.display_name, text_type('custom_component_due_date'): self.lti_consumer.xblock.due.strftime('%Y-%m-%d %H:%M:%S'), text_type('custom_component_graceperiod'): str(self.lti_consumer.xblock.graceperiod.total_seconds()), 'lis_person_sourcedid': 'edx', 'lis_person_contact_email_primary': '*****@*****.**', 'launch_presentation_locale': 'en', text_type('custom_param_1'): 'custom1', text_type('custom_param_2'): 'custom2', text_type('oauth_nonce'): 'fake_nonce', 'oauth_timestamp': 'fake_timestamp', 'oauth_version': 'fake_version', 'oauth_signature_method': 'fake_method', 'oauth_consumer_key': 'fake_consumer_key', 'oauth_signature': 'fake_signature', text_type('context_label'): self.lti_consumer.xblock.course.display_org_with_default, text_type('context_title'): self.lti_consumer.xblock.course.display_name_with_default, } self.assertEqual(self.lti_consumer.get_signed_lti_parameters(), expected_lti_parameters) # Test that `lis_person_sourcedid`, `lis_person_contact_email_primary`, and `launch_presentation_locale` # are not included in the returned LTI parameters when a user cannot be found self.lti_consumer.xblock.runtime.get_real_user.return_value = {} del expected_lti_parameters['lis_person_sourcedid'] del expected_lti_parameters['lis_person_contact_email_primary'] del expected_lti_parameters['launch_presentation_locale'] self.assertEqual(self.lti_consumer.get_signed_lti_parameters(), expected_lti_parameters) @patch_signed_parameters @patch('lti_consumer.lti.log') def test_parameter_processors(self, mock_log): self._update_xblock_for_signed_parameters() self.xblock.enable_processors = True mock_value = { 'parameter_processors': ['lti_consumer.tests.unit.test_utils:dummy_processor'] } with patch('lti_consumer.lti_consumer.LtiConsumerXBlock.get_settings', return_value=mock_value): params = self.lti_consumer.get_signed_lti_parameters() assert params['custom_author_country'] == u'' assert params['custom_author_email'] == u'*****@*****.**' assert not mock_log.exception.called @patch_signed_parameters @patch('lti_consumer.lti.log') def test_default_params(self, mock_log): self._update_xblock_for_signed_parameters() self.xblock.enable_processors = True mock_value = { 'parameter_processors': ['lti_consumer.tests.unit.test_utils:defaulting_processor'] } with patch('lti_consumer.lti_consumer.LtiConsumerXBlock.get_settings', return_value=mock_value): params = self.lti_consumer.get_signed_lti_parameters() assert params['custom_country'] == u'' assert params['custom_name'] == u'Lex' assert not mock_log.exception.called @patch_signed_parameters @patch('lti_consumer.lti.log') def test_default_params_with_error(self, mock_log): self._update_xblock_for_signed_parameters() self.xblock.enable_processors = True mock_value = { 'parameter_processors': ['lti_consumer.tests.unit.test_utils:faulty_processor'] } with patch('lti_consumer.lti_consumer.LtiConsumerXBlock.get_settings', return_value=mock_value): params = self.lti_consumer.get_signed_lti_parameters() assert params['custom_name'] == u'Lex' assert mock_log.exception.called def test_get_result(self): """ Test `get_result` returns valid json response """ self.xblock.module_score = 0.9 self.xblock.score_comment = 'Great Job!' response = dict(GET_RESULT_RESPONSE) response.update({ "resultScore": self.xblock.module_score, "comment": self.xblock.score_comment }) self.assertEqual(self.lti_consumer.get_result(Mock()), response) self.xblock.module_score = None self.xblock.score_comment = '' self.assertEqual(self.lti_consumer.get_result(Mock()), GET_RESULT_RESPONSE) @patch( 'lti_consumer.lti_consumer.LtiConsumerXBlock.clear_user_module_score') def test_delete_result(self, mock_clear): """ Test `delete_result` calls `LtiConsumerXBlock.clear_user_module_score` """ user = Mock() response = self.lti_consumer.delete_result(user) mock_clear.assert_called_with(user) self.assertEqual(response, {}) @patch('lti_consumer.lti_consumer.LtiConsumerXBlock.max_score', Mock(return_value=1.0)) @patch('lti_consumer.lti_consumer.LtiConsumerXBlock.set_user_module_score') @patch( 'lti_consumer.lti_consumer.LtiConsumerXBlock.clear_user_module_score') @patch('lti_consumer.lti.parse_result_json') def test_put_result(self, mock_parse, mock_clear, mock_set): """ Test `put_result` calls `LtiConsumerXBlock.set_user_module_score` or `LtiConsumerXblock.clear_user_module_score` if resultScore not included in request """ user = Mock() score = 0.9 comment = 'Great Job!' mock_parse.return_value = (score, comment) response = self.lti_consumer.put_result(user, '') mock_set.assert_called_with(user, score, 1.0, comment) self.assertEqual(response, {}) mock_parse.return_value = (None, '') response = self.lti_consumer.put_result(user, '') mock_clear.assert_called_with(user) self.assertEqual(response, {}) @patch('lti_consumer.lti.log') def test_verify_result_headers_verify_content_type_true(self, mock_log): """ Test wrong content type raises exception if `verify_content_type` is True """ request = make_request('') with self.assertRaises(LtiError): self.lti_consumer.verify_result_headers(request) assert mock_log.error.called @patch('lti_consumer.lti.verify_oauth_body_signature', Mock(return_value=True)) @patch( 'lti_consumer.lti_consumer.LtiConsumerXBlock.lti_provider_key_secret', PropertyMock(return_value=('t', 's'))) def test_verify_result_headers_verify_content_type_false(self): """ Test content type check skipped if `verify_content_type` is False """ request = make_request('') request.environ['CONTENT_TYPE'] = LtiConsumer.CONTENT_TYPE_RESULT_JSON response = self.lti_consumer.verify_result_headers(request, False) self.assertTrue(response) @patch('lti_consumer.lti.verify_oauth_body_signature', Mock(return_value=True)) @patch( 'lti_consumer.lti_consumer.LtiConsumerXBlock.lti_provider_key_secret', PropertyMock(return_value=('t', 's'))) def test_verify_result_headers_valid(self): """ Test True is returned if request is valid """ request = make_request('') request.environ['CONTENT_TYPE'] = LtiConsumer.CONTENT_TYPE_RESULT_JSON response = self.lti_consumer.verify_result_headers(request) self.assertTrue(response) @patch('lti_consumer.lti.verify_oauth_body_signature', Mock(side_effect=LtiError)) @patch( 'lti_consumer.lti_consumer.LtiConsumerXBlock.lti_provider_key_secret', PropertyMock(return_value=('t', 's'))) @patch('lti_consumer.lti.log') def test_verify_result_headers_lti_error(self, mock_log): """ Test exception raised if request header verification raises error """ request = make_request('') request.environ['CONTENT_TYPE'] = LtiConsumer.CONTENT_TYPE_RESULT_JSON with self.assertRaises(LtiError): self.lti_consumer.verify_result_headers(request) assert mock_log.error.called @patch('lti_consumer.lti.verify_oauth_body_signature', Mock(side_effect=ValueError)) @patch( 'lti_consumer.lti_consumer.LtiConsumerXBlock.lti_provider_key_secret', PropertyMock(return_value=('t', 's'))) @patch('lti_consumer.lti.log') def test_verify_result_headers_value_error(self, mock_log): """ Test exception raised if request header verification raises error """ request = make_request('') request.environ['CONTENT_TYPE'] = LtiConsumer.CONTENT_TYPE_RESULT_JSON with self.assertRaises(LtiError): self.lti_consumer.verify_result_headers(request) assert mock_log.error.called
class TestLtiConsumer(TestLtiConsumerXBlock): """ Unit tests for LtiConsumer """ def setUp(self): super(TestLtiConsumer, self).setUp() self.lti_consumer = LtiConsumer(self.xblock) @patch( "lti_consumer.lti.get_oauth_request_signature", Mock( return_value=( 'OAuth oauth_nonce="fake_nonce", ' 'oauth_timestamp="fake_timestamp", oauth_version="fake_version", oauth_signature_method="fake_method", ' 'oauth_consumer_key="fake_consumer_key", oauth_signature="fake_signature"' ) ), ) @patch( "lti_consumer.lti_consumer.LtiConsumerXBlock.prefixed_custom_parameters", PropertyMock(return_value={u"custom_param_1": "custom1", u"custom_param_2": "custom2"}), ) @patch("lti_consumer.lti_consumer.LtiConsumerXBlock.lti_provider_key_secret", PropertyMock(return_value=("t", "s"))) @patch("lti_consumer.lti_consumer.LtiConsumerXBlock.user_id", PropertyMock(return_value=FAKE_USER_ID)) def test_get_signed_lti_parameters(self): """ Test `get_signed_lti_parameters` returns the correct dict """ self.lti_consumer.xblock.due = timezone.now() self.lti_consumer.xblock.graceperiod = timedelta(days=1) expected_lti_parameters = { u"user_id": self.lti_consumer.xblock.user_id, u"oauth_callback": u"about:blank", u"launch_presentation_return_url": "", u"lti_message_type": u"basic-lti-launch-request", u"lti_version": "LTI-1p0", u"roles": self.lti_consumer.xblock.role, u"resource_link_id": self.lti_consumer.xblock.resource_link_id, u"lis_result_sourcedid": self.lti_consumer.xblock.lis_result_sourcedid, u"context_id": self.lti_consumer.xblock.context_id, u"lis_outcome_service_url": self.lti_consumer.xblock.outcome_service_url, u"custom_component_display_name": self.lti_consumer.xblock.display_name, u"custom_component_due_date": self.lti_consumer.xblock.due.strftime("%Y-%m-%d %H:%M:%S"), u"custom_component_graceperiod": str(self.lti_consumer.xblock.graceperiod.total_seconds()), "lis_person_sourcedid": "edx", "lis_person_contact_email_primary": "*****@*****.**", "launch_presentation_locale": "en", u"custom_param_1": "custom1", u"custom_param_2": "custom2", u"oauth_nonce": "fake_nonce", "oauth_timestamp": "fake_timestamp", "oauth_version": "fake_version", "oauth_signature_method": "fake_method", "oauth_consumer_key": "fake_consumer_key", "oauth_signature": u"fake_signature", } self.lti_consumer.xblock.has_score = True self.lti_consumer.xblock.ask_to_send_username = True self.lti_consumer.xblock.ask_to_send_email = True self.lti_consumer.xblock.runtime.get_real_user.return_value = Mock( email="*****@*****.**", username="******", preferences=Mock(filter=Mock(return_value=[Mock(value="en")])) ) self.assertEqual(self.lti_consumer.get_signed_lti_parameters(), expected_lti_parameters) # Test that `lis_person_sourcedid`, `lis_person_contact_email_primary`, and `launch_presentation_locale` # are not included in the returned LTI parameters when a user cannot be found self.lti_consumer.xblock.runtime.get_real_user.return_value = {} del expected_lti_parameters["lis_person_sourcedid"] del expected_lti_parameters["lis_person_contact_email_primary"] del expected_lti_parameters["launch_presentation_locale"] self.assertEqual(self.lti_consumer.get_signed_lti_parameters(), expected_lti_parameters) def test_get_result(self): """ Test `get_result` returns valid json response """ self.xblock.module_score = 0.9 self.xblock.score_comment = "Great Job!" response = dict(GET_RESULT_RESPONSE) response.update({"resultScore": self.xblock.module_score, "comment": self.xblock.score_comment}) self.assertEqual(self.lti_consumer.get_result(Mock()), response) self.xblock.module_score = None self.xblock.score_comment = "" self.assertEqual(self.lti_consumer.get_result(Mock()), GET_RESULT_RESPONSE) @patch("lti_consumer.lti_consumer.LtiConsumerXBlock.clear_user_module_score") def test_delete_result(self, mock_clear): """ Test `delete_result` calls `LtiConsumerXBlock.clear_user_module_score` """ user = Mock() response = self.lti_consumer.delete_result(user) mock_clear.assert_called_with(user) self.assertEqual(response, {}) @patch("lti_consumer.lti_consumer.LtiConsumerXBlock.max_score", Mock(return_value=1.0)) @patch("lti_consumer.lti_consumer.LtiConsumerXBlock.set_user_module_score") @patch("lti_consumer.lti_consumer.LtiConsumerXBlock.clear_user_module_score") @patch("lti_consumer.lti.parse_result_json") def test_put_result(self, mock_parse, mock_clear, mock_set): """ Test `put_result` calls `LtiConsumerXBlock.set_user_module_score` or `LtiConsumerXblock.clear_user_module_score` if resultScore not included in request """ user = Mock() score = 0.9 comment = "Great Job!" mock_parse.return_value = (score, comment) response = self.lti_consumer.put_result(user, "") mock_set.assert_called_with(user, score, 1.0, comment) self.assertEqual(response, {}) mock_parse.return_value = (None, "") response = self.lti_consumer.put_result(user, "") mock_clear.assert_called_with(user) self.assertEqual(response, {}) @patch("lti_consumer.lti.log") def test_verify_result_headers_verify_content_type_true(self, mock_log): """ Test wrong content type raises exception if `verify_content_type` is True """ request = make_request("") with self.assertRaises(LtiError): self.lti_consumer.verify_result_headers(request) self.assertTrue(mock_log.called) @patch("lti_consumer.lti.verify_oauth_body_signature", Mock(return_value=True)) @patch("lti_consumer.lti_consumer.LtiConsumerXBlock.lti_provider_key_secret", PropertyMock(return_value=("t", "s"))) def test_verify_result_headers_verify_content_type_false(self): """ Test content type check skipped if `verify_content_type` is False """ request = make_request("") request.environ["CONTENT_TYPE"] = LtiConsumer.CONTENT_TYPE_RESULT_JSON response = self.lti_consumer.verify_result_headers(request, False) self.assertTrue(response) @patch("lti_consumer.lti.verify_oauth_body_signature", Mock(return_value=True)) @patch("lti_consumer.lti_consumer.LtiConsumerXBlock.lti_provider_key_secret", PropertyMock(return_value=("t", "s"))) def test_verify_result_headers_valid(self): """ Test True is returned if request is valid """ request = make_request("") request.environ["CONTENT_TYPE"] = LtiConsumer.CONTENT_TYPE_RESULT_JSON response = self.lti_consumer.verify_result_headers(request) self.assertTrue(response) @patch("lti_consumer.lti.verify_oauth_body_signature", Mock(side_effect=LtiError)) @patch("lti_consumer.lti_consumer.LtiConsumerXBlock.lti_provider_key_secret", PropertyMock(return_value=("t", "s"))) @patch("lti_consumer.lti.log") def test_verify_result_headers_lti_error(self, mock_log): """ Test exception raised if request header verification raises error """ request = make_request("") request.environ["CONTENT_TYPE"] = LtiConsumer.CONTENT_TYPE_RESULT_JSON with self.assertRaises(LtiError): self.lti_consumer.verify_result_headers(request) self.assertTrue(mock_log.called) @patch("lti_consumer.lti.verify_oauth_body_signature", Mock(side_effect=ValueError)) @patch("lti_consumer.lti_consumer.LtiConsumerXBlock.lti_provider_key_secret", PropertyMock(return_value=("t", "s"))) @patch("lti_consumer.lti.log") def test_verify_result_headers_value_error(self, mock_log): """ Test exception raised if request header verification raises error """ request = make_request("") request.environ["CONTENT_TYPE"] = LtiConsumer.CONTENT_TYPE_RESULT_JSON with self.assertRaises(LtiError): self.lti_consumer.verify_result_headers(request) self.assertTrue(mock_log.called)