Commit 66d523ae by Gabe Mulley

addressed review comments

parent b605265b
...@@ -24,13 +24,14 @@ class RoutingBackend(object): ...@@ -24,13 +24,14 @@ class RoutingBackend(object):
logged and swallowed, subsequent processors will execute and the event will be emitted. logged and swallowed, subsequent processors will execute and the event will be emitted.
2) Backends - Backends are intended to not mutate the event and each receive the same event data. They are not 2) Backends - Backends are intended to not mutate the event and each receive the same event data. They are not
chained like processors. Once an event has been processed by the processor chain, it is passed to each backend in chained like processors. Once an event has been processed by the processor chain, it is passed to each backend in
order, sorted by the name of the backend. Backends typically persist the event in some way, either by sending it the order that they were registered. Backends typically persist the event in some way, either by sending it
to an external system or saving it to disk. They are called synchronously and in sequence, so a long running to an external system or saving it to disk. They are called synchronously and in sequence, so a long running
backend will block other backends until it is done persisting the event. Note that you can register another backend will block other backends until it is done persisting the event. Note that you can register another
`RoutingBackend` as a backend of a `RoutingBackend`, allowing for arbitrary processing trees. `RoutingBackend` as a backend of a `RoutingBackend`, allowing for arbitrary processing trees.
`backends` is a collection that supports iteration over it's items using `iteritems()`. The keys are expected to be `backends` is a collection that supports iteration over its items using `iteritems()`. The keys are expected to be
sortable and the values are expected to expose a `send(event)` method that will be called for each event. sortable and the values are expected to expose a `send(event)` method that will be called for each event. Each
backend in this collection is registered in order sorted alphanumeric ascending by key.
`processors` is an iterable of callables. `processors` is an iterable of callables.
Raises a `ValueError` if any of the provided backends do not have a callable "send" attribute or any of the Raises a `ValueError` if any of the provided backends do not have a callable "send" attribute or any of the
...@@ -51,7 +52,7 @@ class RoutingBackend(object): ...@@ -51,7 +52,7 @@ class RoutingBackend(object):
def register_backend(self, name, backend): def register_backend(self, name, backend):
""" """
Register a new backend that will be called for each processed event Register a new backend that will be called for each processed event.
Note that backends are called in the order that they are registered. Note that backends are called in the order that they are registered.
""" """
......
...@@ -7,34 +7,67 @@ from unittest import TestCase ...@@ -7,34 +7,67 @@ from unittest import TestCase
from mock import sentinel from mock import sentinel
from eventtracking.processors.exceptions import EventEmissionExit from eventtracking.processors.exceptions import EventEmissionExit
from eventtracking.processors.whitelist import WhitelistProcessor from eventtracking.processors.whitelist import NameWhitelistProcessor
class TestWhitelistProcessor(TestCase): class TestNameWhitelistProcessor(TestCase):
"""Test the whitelist processor""" """Test the whitelist processor"""
def test_filtering_out(self): def test_filtering_out(self):
whitelist = WhitelistProcessor(whitelist=[sentinel.allowed_event]) whitelist = NameWhitelistProcessor(whitelist=[sentinel.allowed_event])
with self.assertRaises(EventEmissionExit): with self.assertRaises(EventEmissionExit):
whitelist({'name': sentinel.not_allowed_event}) whitelist({'name': sentinel.not_allowed_event})
def test_allowed_event(self): def test_allowed_event(self):
whitelist = WhitelistProcessor(whitelist=[sentinel.allowed_event]) whitelist = NameWhitelistProcessor(whitelist=[sentinel.allowed_event])
self.assert_event_passed_through(whitelist, {'name': sentinel.allowed_event}) self.assert_event_passed_through(whitelist, {'name': sentinel.allowed_event})
def assert_event_passed_through(self, whitelist, event): def assert_event_passed_through(self, whitelist, event):
"""Assert that the whitelist allowed the event processing to procede""" """Assert that the whitelist allowed the event processing to proceed"""
self.assertEquals(whitelist(event), event) self.assertEquals(whitelist(event), event)
def test_empty_whitelist(self): def test_empty_whitelist(self):
whitelist = WhitelistProcessor(whitelist=[]) whitelist = NameWhitelistProcessor(whitelist=[])
with self.assertRaises(EventEmissionExit): with self.assertRaises(EventEmissionExit):
whitelist({'name': sentinel.not_allowed_event}) whitelist({'name': sentinel.not_allowed_event})
def test_multi_entry_whitelist(self): def test_multi_entry_whitelist(self):
whitelist = WhitelistProcessor(whitelist=[sentinel.allowed_event, sentinel.another_event]) whitelist = NameWhitelistProcessor(whitelist=[sentinel.allowed_event, sentinel.another_event])
with self.assertRaises(EventEmissionExit): with self.assertRaises(EventEmissionExit):
whitelist({'name': sentinel.not_allowed_event}) whitelist({'name': sentinel.not_allowed_event})
self.assert_event_passed_through(whitelist, {'name': sentinel.allowed_event}) self.assert_event_passed_through(whitelist, {'name': sentinel.allowed_event})
self.assert_event_passed_through(whitelist, {'name': sentinel.another_event}) self.assert_event_passed_through(whitelist, {'name': sentinel.another_event})
def test_no_whitelist_param(self):
with self.assert_initialization_fails():
NameWhitelistProcessor()
def assert_initialization_fails(self):
"""Assert that the constructor raises the expected initialization exception"""
return self.assertRaisesRegexp(TypeError, r'The NameWhitelistProcessor must be passed')
def test_whitelist_param_not_iterable(self):
with self.assert_initialization_fails():
NameWhitelistProcessor(10)
def test_whitelist_param_just_a_string(self):
with self.assert_initialization_fails():
NameWhitelistProcessor('foobar')
def test_whitelist_param_is_none(self):
with self.assert_initialization_fails():
NameWhitelistProcessor(None)
def test_initialize_with_set(self):
self.assert_properly_configured(frozenset([sentinel.allowed_event]))
def assert_properly_configured(self, allowed_names):
"""Assert that whitelist was configured properly by correctly passing and/or filtering events"""
whitelist = NameWhitelistProcessor(whitelist=allowed_names)
self.assert_event_passed_through(whitelist, {'name': sentinel.allowed_event})
with self.assertRaises(EventEmissionExit):
whitelist({'name': sentinel.not_allowed_event})
def test_initialize_with_dict(self):
self.assert_properly_configured({sentinel.allowed_event: sentinel.discarded})
...@@ -3,16 +3,25 @@ ...@@ -3,16 +3,25 @@
from eventtracking.processors.exceptions import EventEmissionExit from eventtracking.processors.exceptions import EventEmissionExit
class WhitelistProcessor(object): class NameWhitelistProcessor(object):
""" """
Filter out events whose names aren't on a pre-configured whitelist. Filter out events whose names aren't on a pre-configured whitelist.
`whitelist` is an iterable containing event names that should be allowed to pass. `whitelist` is an iterable collection containing event names that should be allowed to pass.
""" """
def __init__(self, **kwargs): def __init__(self, whitelist=None, **_kwargs):
self.whitelist = frozenset(kwargs.get('whitelist', [])) try:
if isinstance(whitelist, basestring):
raise TypeError
self.whitelist = frozenset(whitelist)
except TypeError:
raise TypeError(
'The NameWhitelistProcessor must be passed a collection of allowed names '
'using the "whitelist" parameter'
)
def __call__(self, event): def __call__(self, event):
if event['name'] not in self.whitelist: if event['name'] not in self.whitelist:
......
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