Skip to content

Commit

Permalink
Merge 65b8ecc into 5def4ed
Browse files Browse the repository at this point in the history
  • Loading branch information
Rudi committed Nov 4, 2015
2 parents 5def4ed + 65b8ecc commit ddc3177
Show file tree
Hide file tree
Showing 2 changed files with 140 additions and 1 deletion.
90 changes: 89 additions & 1 deletion vumi/tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
from vumi.utils import (
normalize_msisdn, vumi_resource_path, cleanup_msisdn, get_operator_name,
http_request, http_request_full, get_first_word, redis_from_config,
build_web_site, LogFilterSite, PkgResources, HttpTimeoutError)
build_web_site, LogFilterSite, PkgResources, HttpTimeoutError,
StatusEdgeDetector)
from vumi.message import TransportStatus
from vumi.persist.fake_redis import FakeRedis
from vumi.tests.fake_connection import (
FakeServer, FakeHttpServer, ProxyAgentWithContext, wait0)
Expand Down Expand Up @@ -439,3 +441,89 @@ def test_relative_path(self):
pkg = PkgResources("vumi.tests")
self.assertEqual(os.path.join(self.vumi_tests_path, 'foo/bar'),
pkg.path('foo/bar'))


class TestStatusEdgeDetector(VumiTestCase):
def test_status_not_change(self):
'''If the status doesn't change, None should be returned.'''
sed = StatusEdgeDetector()
status1 = TransportStatus(
component='foo',
status='ok',
type='bar',
message='test')
self.assertEqual(sed.check_status(status1), status1)

status2 = TransportStatus(
component='foo',
status='ok',
type='bar',
message='another test')
self.assertEqual(sed.check_status(status2), None)

def test_status_change(self):
'''If the status does change, the status should be returned.'''
sed = StatusEdgeDetector()
status1 = TransportStatus(
component='foo',
status='ok',
type='bar',
message='test')
self.assertEqual(sed.check_status(status1), status1)

status2 = TransportStatus(
component='foo',
status='degraded',
type='bar',
message='another test')
self.assertEqual(sed.check_status(status2), status2)

def test_components_separate(self):
'''A state change in one component should not affect other
components.'''
sed = StatusEdgeDetector()
comp1_status1 = TransportStatus(
component='foo',
status='ok',
type='bar',
message='test')
self.assertEqual(sed.check_status(comp1_status1), comp1_status1)

comp2_status1 = TransportStatus(
component='bar',
status='ok',
type='bar',
message='another test')
self.assertEqual(sed.check_status(comp2_status1), comp2_status1)

comp2_status2 = TransportStatus(
component='bar',
status='degraded',
type='bar',
message='another test')
self.assertEqual(sed.check_status(comp2_status2), comp2_status2)

comp1_status2 = TransportStatus(
component='foo',
status='ok',
type='bar',
message='test')
self.assertEqual(sed.check_status(comp1_status2), None)

def test_type_change(self):
'''A change in status type should result in the status being
returned.'''
sed = StatusEdgeDetector()
status1 = TransportStatus(
component='foo',
status='ok',
type='bar',
message='test')
self.assertEqual(sed.check_status(status1), status1)

status2 = TransportStatus(
component='foo',
status='ok',
type='baz',
message='test')
self.assertEqual(sed.check_status(status2), status2)
51 changes: 51 additions & 0 deletions vumi/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -452,3 +452,54 @@ def safe_routing_key(routing_key):

def generate_worker_id(system_id, worker_id):
return "%s:%s" % (system_id, worker_id,)


class StatusEdgeDetector(object):
'''Assists with finding if a TransportStatus is a change in the status,
compared to previous statuses, or just a repeat. Will be useful to only
publish statuses on state change.'''

def __init__(self):
self.state = dict()
self.types = dict()

def check_status(self, status):
'''
Checks to see if the current status is a repeat. If it is, None is
returned. If it isn't, the status is returned.
:param status: The status to check.
:type status: :class:`TransportStatus`
'''
self._check_state(status['status'], status['component'])
if self._check_type(status['type'], status['component']):
return status

def _get_state(self, component):
return self.state.get(component, None)

def _set_state(self, component, state):
self.state[component] = state

def _get_types(self, component):
return self.types.get(component, set())

def _add_type(self, component, type):
if component not in self.types:
self.types[component] = set()
self.types[component].add(type)

def _remove_types(self, component):
self.types.pop(component, None)

def _check_state(self, status, component):
state = self._get_state(component)
if state != status:
self._remove_types(component)
self._set_state(component, status)

def _check_type(self, type, component):
types = self._get_types(component)
if type not in types:
self._add_type(component, type)
return True

0 comments on commit ddc3177

Please sign in to comment.