diff --git a/common/djangoapps/track/views/segmentio.py b/common/djangoapps/track/views/segmentio.py index 7cdc35daf5..ba74d1fce0 100644 --- a/common/djangoapps/track/views/segmentio.py +++ b/common/djangoapps/track/views/segmentio.py @@ -1,9 +1,9 @@ """Handle events that were forwarded from the Segment webhook integration""" -import datetime import json import logging +from dateutil import parser from django.conf import settings from django.contrib.auth.models import User from django.http import HttpResponse @@ -266,4 +266,4 @@ def _get_segmentio_event_name(event_properties): def parse_iso8601_timestamp(timestamp): """Parse a particular type of ISO8601 formatted timestamp""" - return datetime.datetime.strptime(timestamp, "%Y-%m-%dT%H:%M:%S.%fZ") + return parser.parse(timestamp) diff --git a/common/djangoapps/track/views/tests/test_segmentio.py b/common/djangoapps/track/views/tests/test_segmentio.py index 663070b7ca..fb28d64a45 100644 --- a/common/djangoapps/track/views/tests/test_segmentio.py +++ b/common/djangoapps/track/views/tests/test_segmentio.py @@ -1,8 +1,7 @@ """Ensure we can parse events sent to us from the Segment webhook integration""" - -from datetime import datetime import json +from dateutil import parser from ddt import ddt, data, unpack from mock import sentinel @@ -36,6 +35,11 @@ class SegmentIOTrackingTestCase(SegmentIOTrackingTestCaseBase): """ shard = 3 + def setUp(self): + super(SegmentIOTrackingTestCase, self).setUp() + + User.objects.create(pk=SEGMENTIO_TEST_USER_ID, username=str(sentinel.username)) + def test_get_request(self): request = self.request_factory.get(SEGMENTIO_TEST_ENDPOINT) response = segmentio.segmentio_event(request) @@ -88,7 +92,6 @@ class SegmentIOTrackingTestCase(SegmentIOTrackingTestCaseBase): data=self.create_segmentio_event_json(data={'foo': 'bar'}, course_id=course_id), content_type='application/json' ) - User.objects.create(pk=SEGMENTIO_TEST_USER_ID, username=str(sentinel.username)) middleware.process_request(request) # The middleware normally emits an event, make sure it doesn't in this case. @@ -109,7 +112,7 @@ class SegmentIOTrackingTestCase(SegmentIOTrackingTestCaseBase): 'event': {'foo': 'bar'}, 'agent': str(sentinel.user_agent), 'page': None, - 'time': datetime.strptime("2014-08-27T16:33:39.215Z", "%Y-%m-%dT%H:%M:%S.%fZ"), + 'time': parser.parse("2014-08-27T16:33:39.215Z"), 'host': 'testserver', 'context': { 'application': { @@ -129,7 +132,7 @@ class SegmentIOTrackingTestCase(SegmentIOTrackingTestCaseBase): 'version': '1.0.1', }, }, - 'received_at': datetime.strptime("2014-08-27T16:33:39.100Z", "%Y-%m-%dT%H:%M:%S.%fZ"), + 'received_at': parser.parse("2014-08-27T16:33:39.100Z"), }, } finally: @@ -142,7 +145,6 @@ class SegmentIOTrackingTestCase(SegmentIOTrackingTestCaseBase): data=self.create_segmentio_event_json(course_id='invalid'), content_type='application/json' ) - User.objects.create(pk=SEGMENTIO_TEST_USER_ID, username=str(sentinel.username)) segmentio.track_segmentio_event(request) self.assert_events_emitted() @@ -154,7 +156,6 @@ class SegmentIOTrackingTestCase(SegmentIOTrackingTestCaseBase): data=json.dumps(sample_event_raw), content_type='application/json' ) - User.objects.create(pk=SEGMENTIO_TEST_USER_ID, username=str(sentinel.username)) segmentio.track_segmentio_event(request) @@ -166,7 +167,6 @@ class SegmentIOTrackingTestCase(SegmentIOTrackingTestCaseBase): data=json.dumps(sample_event_raw), content_type='application/json' ) - User.objects.create(pk=SEGMENTIO_TEST_USER_ID, username=str(sentinel.username)) segmentio.track_segmentio_event(request) @@ -177,7 +177,6 @@ class SegmentIOTrackingTestCase(SegmentIOTrackingTestCaseBase): data=json.dumps(sample_event_raw), content_type='application/json' ) - User.objects.create(pk=SEGMENTIO_TEST_USER_ID, username=str(sentinel.username)) segmentio.track_segmentio_event(request) @@ -188,7 +187,6 @@ class SegmentIOTrackingTestCase(SegmentIOTrackingTestCaseBase): data=json.dumps(sample_event_raw), content_type='application/json' ) - User.objects.create(pk=SEGMENTIO_TEST_USER_ID, username=str(sentinel.username)) segmentio.track_segmentio_event(request) @@ -203,17 +201,32 @@ class SegmentIOTrackingTestCase(SegmentIOTrackingTestCaseBase): return event def test_string_user_id(self): - User.objects.create(pk=SEGMENTIO_TEST_USER_ID, username=str(sentinel.username)) self.post_segmentio_event(user_id=str(SEGMENTIO_TEST_USER_ID)) self.assert_events_emitted() + @data( + '2018-12-11T07:27:28.015900357Z', + '2014-08-27T16:33:39.100Z', + '2014-08-27T16:33:39.215Z' + ) + def test_timestamp_success(self, timestamp): + sample_event_raw = self.create_segmentio_event() + sample_event_raw['receivedAt'] = timestamp + sample_event_raw['timestamp'] = timestamp + request = self.create_request( + data=json.dumps(sample_event_raw), + content_type='application/json' + ) + response = segmentio.segmentio_event(request) + self.assertEquals(response.status_code, 200) + self.assert_events_emitted() + def test_hiding_failure(self): sample_event_raw = self.create_event_without_fields('timestamp') request = self.create_request( data=json.dumps(sample_event_raw), content_type='application/json' ) - User.objects.create(pk=SEGMENTIO_TEST_USER_ID, username=str(sentinel.username)) response = segmentio.segmentio_event(request) self.assertEquals(response.status_code, 200) @@ -259,7 +272,6 @@ class SegmentIOTrackingTestCase(SegmentIOTrackingTestCaseBase): }), content_type='application/json' ) - User.objects.create(pk=SEGMENTIO_TEST_USER_ID, username=str(sentinel.username)) middleware.process_request(request) try: @@ -277,7 +289,7 @@ class SegmentIOTrackingTestCase(SegmentIOTrackingTestCaseBase): 'name': name, 'agent': str(sentinel.user_agent), 'page': 'https://testserver/courses/foo/bar/baz/courseware/Week_1/Activity', - 'time': datetime.strptime("2014-08-27T16:33:39.215Z", "%Y-%m-%dT%H:%M:%S.%fZ"), + 'time': parser.parse("2014-08-27T16:33:39.215Z"), 'host': 'testserver', 'context': { 'user_id': SEGMENTIO_TEST_USER_ID, @@ -298,7 +310,7 @@ class SegmentIOTrackingTestCase(SegmentIOTrackingTestCaseBase): 'version': '29', 'component': 'videoplayer' }, - 'received_at': datetime.strptime("2014-08-27T16:33:39.100Z", "%Y-%m-%dT%H:%M:%S.%fZ"), + 'received_at': parser.parse("2014-08-27T16:33:39.100Z"), }, 'event': { 'currentTime': 132.134456, @@ -393,7 +405,6 @@ class SegmentIOTrackingTestCase(SegmentIOTrackingTestCaseBase): ), content_type='application/json' ) - User.objects.create(pk=SEGMENTIO_TEST_USER_ID, username=str(sentinel.username)) middleware.process_request(request) try: @@ -411,7 +422,7 @@ class SegmentIOTrackingTestCase(SegmentIOTrackingTestCaseBase): 'name': expected_name, 'agent': str(sentinel.user_agent), 'page': 'https://testserver/courses/foo/bar/baz/courseware/Week_1/Activity', - 'time': datetime.strptime("2014-08-27T16:33:39.215Z", "%Y-%m-%dT%H:%M:%S.%fZ"), + 'time': parser.parse("2014-08-27T16:33:39.215Z"), 'host': 'testserver', 'context': { 'user_id': SEGMENTIO_TEST_USER_ID, @@ -432,7 +443,7 @@ class SegmentIOTrackingTestCase(SegmentIOTrackingTestCaseBase): 'version': version, 'component': 'videoplayer' }, - 'received_at': datetime.strptime("2014-08-27T16:33:39.100Z", "%Y-%m-%dT%H:%M:%S.%fZ"), + 'received_at': parser.parse("2014-08-27T16:33:39.100Z"), }, 'event': { "code": "mobile",