diff --git a/lms/djangoapps/courseware/module_render.py b/lms/djangoapps/courseware/module_render.py index e4dde2e3f4fbecdadb9ce6326154d07e4dcc1bd0..500e5b4a465cd1ce7437d403d189bd037572b366 100644 --- a/lms/djangoapps/courseware/module_render.py +++ b/lms/djangoapps/courseware/module_render.py @@ -22,6 +22,7 @@ from courseware.model_data import FieldDataCache, DjangoKeyValueStore from lms.lib.xblock.field_data import LmsFieldData from lms.lib.xblock.runtime import LmsModuleSystem, unquote_slashes from edxmako.shortcuts import render_to_string +from eventtracking import tracker from psychometrics.psychoanalyze import make_psychometrics_data_update_handler from student.models import anonymous_id_for_user, user_by_anonymous_id from xblock.core import XBlock @@ -571,6 +572,13 @@ def _invoke_xblock_handler(request, course_id, usage_id, handler, suffix, user): ) raise Http404 + tracking_context_name = 'module_callback_handler' + tracking_context = { + 'module': { + 'display_name': descriptor.display_name_with_default, + } + } + field_data_cache = FieldDataCache.cache_for_descriptor_descendents( course_id, user, @@ -585,7 +593,8 @@ def _invoke_xblock_handler(request, course_id, usage_id, handler, suffix, user): req = django_to_webob_request(request) try: - resp = instance.handle(handler, req, suffix) + with tracker.get_tracker().context(tracking_context_name, tracking_context): + resp = instance.handle(handler, req, suffix) except NoSuchHandlerError: log.exception("XBlock %s attempted to access missing handler %r", instance, handler) diff --git a/lms/djangoapps/courseware/tests/test_module_render.py b/lms/djangoapps/courseware/tests/test_module_render.py index 8c7357087bf3d5653fca07d23d51028bcae51e80..ef7ae4cab3ef8051363d7c17fd91c33fb0d893f7 100644 --- a/lms/djangoapps/courseware/tests/test_module_render.py +++ b/lms/djangoapps/courseware/tests/test_module_render.py @@ -698,3 +698,63 @@ class TestAnonymousStudentId(ModuleStoreTestCase, LoginEnrollmentTestCase): 'f82b5416c9f54b5ce33989511bb5ef2e', self._get_anonymous_id('MITx/6.00x/2013_Spring', descriptor_class) ) + + +@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE) +@patch('track.views.tracker') +class TestModuleTrackingContext(ModuleStoreTestCase): + """ + Ensure correct tracking information is included in events emitted during XBlock callback handling. + """ + + def setUp(self): + self.user = UserFactory.create() + self.request = RequestFactory().get('/') + self.request.user = self.user + self.request.session = {} + self.course = CourseFactory.create() + + self.problem_xml = OptionResponseXMLFactory().build_xml( + question_text='The correct answer is Correct', + num_inputs=2, + weight=2, + options=['Correct', 'Incorrect'], + correct_option='Correct' + ) + + def test_context_contains_display_name(self, mock_tracker): + problem_display_name = u'Option Response Problem' + actual_display_name = self.handle_callback_and_get_display_name_from_event(mock_tracker, problem_display_name) + self.assertEquals(problem_display_name, actual_display_name) + + def handle_callback_and_get_display_name_from_event(self, mock_tracker, problem_display_name=None): + """ + Creates a fake module, invokes the callback and extracts the display name from the emitted problem_check event. + """ + descriptor_kwargs = { + 'category': 'problem', + 'data': self.problem_xml + } + if problem_display_name: + descriptor_kwargs['display_name'] = problem_display_name + + descriptor = ItemFactory.create(**descriptor_kwargs) + + render.handle_xblock_callback( + self.request, + self.course.id, + quote_slashes(str(descriptor.location)), + 'xmodule_handler', + 'problem_check', + ) + + self.assertEquals(len(mock_tracker.send.mock_calls), 1) + mock_call = mock_tracker.send.mock_calls[0] + event = mock_call[1][0] + + self.assertEquals(event['event_type'], 'problem_check') + return event['context']['module']['display_name'] + + def test_missing_display_name(self, mock_tracker): + actual_display_name = self.handle_callback_and_get_display_name_from_event(mock_tracker) + self.assertTrue(actual_display_name.startswith('problem'))