Commit 66d523ae by Gabe Mulley

addressed review comments

parent b605265b
......@@ -24,13 +24,14 @@ class RoutingBackend(object):
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
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
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.
`backends` is a collection that supports iteration over it's 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.
`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. Each
backend in this collection is registered in order sorted alphanumeric ascending by key.
`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
......@@ -51,7 +52,7 @@ class RoutingBackend(object):
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.
"""
......
......@@ -7,34 +7,67 @@ from unittest import TestCase
from mock import sentinel
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"""
def test_filtering_out(self):
whitelist = WhitelistProcessor(whitelist=[sentinel.allowed_event])
whitelist = NameWhitelistProcessor(whitelist=[sentinel.allowed_event])
with self.assertRaises(EventEmissionExit):
whitelist({'name': sentinel.not_allowed_event})
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})
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)
def test_empty_whitelist(self):
whitelist = WhitelistProcessor(whitelist=[])
whitelist = NameWhitelistProcessor(whitelist=[])
with self.assertRaises(EventEmissionExit):
whitelist({'name': sentinel.not_allowed_event})
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):
whitelist({'name': sentinel.not_allowed_event})
self.assert_event_passed_through(whitelist, {'name': sentinel.allowed_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 @@
from eventtracking.processors.exceptions import EventEmissionExit
class WhitelistProcessor(object):
class NameWhitelistProcessor(object):
"""
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):
self.whitelist = frozenset(kwargs.get('whitelist', []))
def __init__(self, whitelist=None, **_kwargs):
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):
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