Handle more kinds of bad data in segment events. (#25506)
This commit is contained in:
@@ -123,16 +123,16 @@ def track_segmentio_event(request): # pylint: disable=too-many-statements
|
||||
full_segment_event = request.json
|
||||
|
||||
# We mostly care about the properties
|
||||
segment_properties = full_segment_event.get('properties', {})
|
||||
segment_properties = _get_dict_value_with_default(full_segment_event, 'properties', {})
|
||||
|
||||
# Start with the context provided by Segment in the "client" field if it exists
|
||||
# We should tightly control which fields actually get included in the event emitted.
|
||||
segment_context = full_segment_event.get('context', {})
|
||||
segment_context = _get_dict_value_with_default(full_segment_event, 'context', {})
|
||||
|
||||
# Build up the event context by parsing fields out of the event received from Segment
|
||||
context = {}
|
||||
|
||||
library_name = segment_context.get('library', {}).get('name')
|
||||
library_name = _get_dict_value_with_default(segment_context, 'library', {}).get('name')
|
||||
source_map = getattr(settings, 'TRACKING_SEGMENTIO_SOURCE_MAP', {})
|
||||
event_source = source_map.get(library_name)
|
||||
if not event_source:
|
||||
@@ -268,3 +268,12 @@ def _get_segmentio_event_name(event_properties):
|
||||
def parse_iso8601_timestamp(timestamp):
|
||||
"""Parse a particular type of ISO8601 formatted timestamp"""
|
||||
return parser.parse(timestamp)
|
||||
|
||||
|
||||
def _get_dict_value_with_default(dict_object, key, default):
|
||||
"""
|
||||
Returns default if the dict doesn't have the key or if the value is Falsey.
|
||||
Otherwise, returns the dict's value for the key.
|
||||
"""
|
||||
value = dict_object.get(key, None)
|
||||
return value if value else default
|
||||
|
||||
@@ -60,6 +60,14 @@ class SegmentIOTrackingTestCaseBase(EventTrackingTestCase):
|
||||
)
|
||||
segmentio.track_segmentio_event(request)
|
||||
|
||||
def post_modified_segmentio_event(self, event):
|
||||
"""Post an externally-defined fake Segment event to the view that processes it"""
|
||||
request = self.create_request(
|
||||
data=json.dumps(event),
|
||||
content_type='application/json'
|
||||
)
|
||||
segmentio.track_segmentio_event(request)
|
||||
|
||||
def create_segmentio_event(self, **kwargs):
|
||||
"""Populate a fake Segment event with data of interest"""
|
||||
action = kwargs.get('action', 'Track')
|
||||
|
||||
@@ -68,10 +68,46 @@ class SegmentIOTrackingTestCase(SegmentIOTrackingTestCaseBase):
|
||||
self.post_segmentio_event(action=action)
|
||||
self.assert_no_events_emitted()
|
||||
|
||||
def test_segmentio_ignore_missing_context_entry(self):
|
||||
sample_event_raw = self.create_segmentio_event()
|
||||
del sample_event_raw['context']
|
||||
self.post_modified_segmentio_event(sample_event_raw)
|
||||
self.assert_no_events_emitted()
|
||||
|
||||
def test_segmentio_ignore_null_context_entry(self):
|
||||
sample_event_raw = self.create_segmentio_event()
|
||||
sample_event_raw['context'] = None
|
||||
self.post_modified_segmentio_event(sample_event_raw)
|
||||
self.assert_no_events_emitted()
|
||||
|
||||
def test_segmentio_ignore_missing_library_entry(self):
|
||||
sample_event_raw = self.create_segmentio_event()
|
||||
del sample_event_raw['context']['library']
|
||||
self.post_modified_segmentio_event(sample_event_raw)
|
||||
self.assert_no_events_emitted()
|
||||
|
||||
def test_segmentio_ignore_null_library_entry(self):
|
||||
sample_event_raw = self.create_segmentio_event()
|
||||
sample_event_raw['context']['library'] = None
|
||||
self.post_modified_segmentio_event(sample_event_raw)
|
||||
self.assert_no_events_emitted()
|
||||
|
||||
def test_segmentio_ignore_unknown_libraries(self):
|
||||
self.post_segmentio_event(library_name='foo')
|
||||
self.assert_no_events_emitted()
|
||||
|
||||
@expect_failure_with_message(segmentio.ERROR_MISSING_NAME)
|
||||
def test_segmentio_ignore_missing_properties_entry(self):
|
||||
sample_event_raw = self.create_segmentio_event()
|
||||
del sample_event_raw['properties']
|
||||
self.post_modified_segmentio_event(sample_event_raw)
|
||||
|
||||
@expect_failure_with_message(segmentio.ERROR_MISSING_NAME)
|
||||
def test_segmentio_ignore_null_properties_entry(self):
|
||||
sample_event_raw = self.create_segmentio_event()
|
||||
sample_event_raw['properties'] = None
|
||||
self.post_modified_segmentio_event(sample_event_raw)
|
||||
|
||||
@expect_failure_with_message(segmentio.ERROR_USER_NOT_EXIST)
|
||||
def test_no_user_for_user_id(self):
|
||||
self.post_segmentio_event(user_id=40)
|
||||
@@ -148,43 +184,23 @@ class SegmentIOTrackingTestCase(SegmentIOTrackingTestCaseBase):
|
||||
def test_missing_name(self):
|
||||
sample_event_raw = self.create_segmentio_event()
|
||||
del sample_event_raw['properties']['name']
|
||||
request = self.create_request(
|
||||
data=json.dumps(sample_event_raw),
|
||||
content_type='application/json'
|
||||
)
|
||||
|
||||
segmentio.track_segmentio_event(request)
|
||||
self.post_modified_segmentio_event(sample_event_raw)
|
||||
|
||||
@expect_failure_with_message(segmentio.ERROR_MISSING_DATA)
|
||||
def test_missing_data(self):
|
||||
sample_event_raw = self.create_segmentio_event()
|
||||
del sample_event_raw['properties']['data']
|
||||
request = self.create_request(
|
||||
data=json.dumps(sample_event_raw),
|
||||
content_type='application/json'
|
||||
)
|
||||
|
||||
segmentio.track_segmentio_event(request)
|
||||
self.post_modified_segmentio_event(sample_event_raw)
|
||||
|
||||
@expect_failure_with_message(segmentio.ERROR_MISSING_TIMESTAMP)
|
||||
def test_missing_timestamp(self):
|
||||
sample_event_raw = self.create_event_without_fields('timestamp')
|
||||
request = self.create_request(
|
||||
data=json.dumps(sample_event_raw),
|
||||
content_type='application/json'
|
||||
)
|
||||
|
||||
segmentio.track_segmentio_event(request)
|
||||
self.post_modified_segmentio_event(sample_event_raw)
|
||||
|
||||
@expect_failure_with_message(segmentio.ERROR_MISSING_RECEIVED_AT)
|
||||
def test_missing_received_at(self):
|
||||
sample_event_raw = self.create_event_without_fields('receivedAt')
|
||||
request = self.create_request(
|
||||
data=json.dumps(sample_event_raw),
|
||||
content_type='application/json'
|
||||
)
|
||||
|
||||
segmentio.track_segmentio_event(request)
|
||||
self.post_modified_segmentio_event(sample_event_raw)
|
||||
|
||||
def create_event_without_fields(self, *fields):
|
||||
"""Create a fake event and remove some fields from it"""
|
||||
|
||||
Reference in New Issue
Block a user