From fe21f47573fc307c52d7e6f6cc65154921b1ead4 Mon Sep 17 00:00:00 2001 From: Gabe Mulley Date: Mon, 24 Feb 2014 11:42:31 -0500 Subject: [PATCH] Add module display name to module related server events This information will likely be used frequently for analytics purposes, so we would like to denormalize here to avoid having to join with the modulestore later. Fixes: AN-594 --- lms/djangoapps/courseware/module_render.py | 11 +++- .../courseware/tests/test_module_render.py | 60 +++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/lms/djangoapps/courseware/module_render.py b/lms/djangoapps/courseware/module_render.py index e4dde2e3f4..500e5b4a46 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 8c7357087b..ef7ae4cab3 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'))