Commit a611c3dd by Chris Dodge

address feedback from analytics team

parent 74eaaa9f
...@@ -66,9 +66,21 @@ from .utils import ( ...@@ -66,9 +66,21 @@ from .utils import (
from edx_proctoring.tests.test_services import ( from edx_proctoring.tests.test_services import (
MockCreditService, MockCreditService,
MockInstructorService, MockInstructorService,
MockAnalyticsService,
) )
from edx_proctoring.runtime import set_runtime_service, get_runtime_service from edx_proctoring.runtime import set_runtime_service, get_runtime_service
from eventtracking import tracker
from eventtracking.tracker import Tracker, TRACKERS
class MockTracker(Tracker):
"""
A mocked out tracker which implements the emit method
"""
def emit(self, name=None, data=None):
"""
Overload this method to do nothing
"""
pass
@ddt.ddt @ddt.ddt
...@@ -125,7 +137,8 @@ class ProctoredExamApiTests(LoggedInTestCase): ...@@ -125,7 +137,8 @@ class ProctoredExamApiTests(LoggedInTestCase):
set_runtime_service('credit', MockCreditService()) set_runtime_service('credit', MockCreditService())
set_runtime_service('instructor', MockInstructorService(is_user_course_staff=True)) set_runtime_service('instructor', MockInstructorService(is_user_course_staff=True))
set_runtime_service('analytics', MockAnalyticsService())
tracker.register_tracker(MockTracker())
self.prerequisites = [ self.prerequisites = [
{ {
...@@ -193,6 +206,12 @@ class ProctoredExamApiTests(LoggedInTestCase): ...@@ -193,6 +206,12 @@ class ProctoredExamApiTests(LoggedInTestCase):
}, },
] ]
def tearDown(self):
"""
Cleanup
"""
del TRACKERS['default']
def _create_proctored_exam(self): def _create_proctored_exam(self):
""" """
Calls the api's create_exam to create an exam object. Calls the api's create_exam to create an exam object.
......
...@@ -109,17 +109,6 @@ class MockInstructorService(object): ...@@ -109,17 +109,6 @@ class MockInstructorService(object):
return self.is_user_course_staff return self.is_user_course_staff
class MockAnalyticsService(object):
"""
A mock implementation of the 'analytics' service
"""
def emit_event(self, name, context, data):
"""
Do nothing
"""
pass
class TestProctoringService(unittest.TestCase): class TestProctoringService(unittest.TestCase):
""" """
Tests for ProctoringService Tests for ProctoringService
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
File that contains tests for the util methods. File that contains tests for the util methods.
""" """
import unittest import unittest
from edx_proctoring.utils import humanized_time from edx_proctoring.utils import humanized_time, _emit_event
class TestHumanizedTime(unittest.TestCase): class TestHumanizedTime(unittest.TestCase):
...@@ -45,3 +45,24 @@ class TestHumanizedTime(unittest.TestCase): ...@@ -45,3 +45,24 @@ class TestHumanizedTime(unittest.TestCase):
human_time = humanized_time(-60) human_time = humanized_time(-60)
self.assertEqual(human_time, "error") self.assertEqual(human_time, "error")
class TestUtils(unittest.TestCase):
"""
Class to test misc utilities
"""
def test_emit_event(self):
"""
Call through to emit event to the analytics pipeline.
NOTE: We're just testing one specific case where the context is None
We get full coverage on other cases, via the test_api.py file
"""
# call without a context
_emit_event(
'foo.bar',
None,
{
'one': 'two'
}
)
...@@ -16,7 +16,11 @@ from edx_proctoring.models import ( ...@@ -16,7 +16,11 @@ from edx_proctoring.models import (
ProctoredExamStudentAttemptHistory, ProctoredExamStudentAttemptHistory,
) )
from edx_proctoring import constants from edx_proctoring import constants
from edx_proctoring.runtime import get_runtime_service
# import dependent libraries (in local_requirements.txt otherwise pick up from running Open edX LMS runtime)
from eventtracking import tracker
from opaque_keys.edx.keys import CourseKey
from opaque_keys import InvalidKeyError
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
...@@ -181,16 +185,42 @@ def emit_event(exam, event_short_name, attempt=None, override_data=None): ...@@ -181,16 +185,42 @@ def emit_event(exam, event_short_name, attempt=None, override_data=None):
'attempt_event_elapsed_time_secs': attempt_event_elapsed_time_secs 'attempt_event_elapsed_time_secs': attempt_event_elapsed_time_secs
} }
data.update(attempt_data) data.update(attempt_data)
name = '.'.join(['edx', 'special-exam', exam_type, 'attempt', event_short_name]) name = '.'.join(['edx', 'special_exam', exam_type, 'attempt', event_short_name])
else: else:
name = '.'.join(['edx', 'special-exam', exam_type, event_short_name]) name = '.'.join(['edx', 'special_exam', exam_type, event_short_name])
# allow caller to override event data # allow caller to override event data
if override_data: if override_data:
data.update(override_data) data.update(override_data)
service = get_runtime_service('analytics') _emit_event(name, context, data)
if service:
service.emit_event(name, context, data)
else: def _emit_event(name, context, data):
log.warn('Analytics event service not configured. If this is a production environment, please resolve.') """
Do the actual integration into the event-tracker
"""
try:
if context:
# try to parse out the org_id from the course_id
if 'course_id' in context:
try:
course_key = CourseKey.from_string(context['course_id'])
context['org_id'] = course_key.org
except InvalidKeyError:
# leave org_id blank
pass
with tracker.get_tracker().context(name, context):
tracker.emit(name, data)
else:
# if None is passed in then we don't construct the 'with' context stack
tracker.emit(name, data)
except KeyError:
# This happens when a default tracker has not been registered by the host application
# aka LMS. This is normal when running unit tests in isolation.
log.warning(
'Analytics tracker not properly configured. '
'If this message appears in a production environment, please investigate'
)
...@@ -5,3 +5,6 @@ djangorestframework>=3.1,<3.2 ...@@ -5,3 +5,6 @@ djangorestframework>=3.1,<3.2
django-ipware==1.1.0 django-ipware==1.1.0
pytz>=2012h pytz>=2012h
pycrypto>=2.6 pycrypto>=2.6
-e git+https://github.com/edx/event-tracking.git@0.2.1#egg=event-tracking==0.2.1
-e git+https://github.com/edx/opaque-keys.git@27dc382ea587483b1e3889a3d19cbd90b9023a06#egg=opaque-keys
...@@ -39,7 +39,7 @@ INSTALLED_APPS = ( ...@@ -39,7 +39,7 @@ INSTALLED_APPS = (
'django.contrib.staticfiles', 'django.contrib.staticfiles',
'rest_framework', 'rest_framework',
'edx_proctoring', 'edx_proctoring',
'django_nose', 'django_nose'
) )
# Static files (CSS, JavaScript, Images) # Static files (CSS, JavaScript, Images)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment