def test_persist_event(): brq = Baroque() assert len(brq._persistance_backend) == 0 evt = Event(GenericEventType(), payload=dict(test=123)) brq._persist_event(evt) assert len(brq._persistance_backend) == 1 assert evt in brq._persistance_backend
def test_on_any_event_run(): brq = Baroque() assert len(brq.reactors.jolly_bag) == 0 r = ReactorFactory.stdout() result = brq.on_any_event_run(r) assert isinstance(result, Reactor) assert r in brq.reactors.jolly_bag
def test_update_event_status(): eventtype = GenericEventType() evt = Event(eventtype, payload=dict()) assert evt.status == EventStatus.UNPUBLISHED brq = Baroque() brq._update_event_status(evt) assert evt.status == EventStatus.PUBLISHED
def test_on(): brq = Baroque() eventtype = GenericEventType() result = brq.on(eventtype) assert isinstance(result, ReactorsBag) brq.reactors.registered_types[type(eventtype)] = ReactorsBag() result = brq.on(eventtype) assert isinstance(result, ReactorsBag)
def test_count_event(): brq = Baroque() eventtype = GenericEventType() evt = Event(eventtype, payload=dict()) assert brq.events.count(eventtype) == 0 assert brq.events.count_all() == 0 brq._count_event(evt) assert brq.events.count(eventtype) == 1 assert brq.events.count_all() == 1
def test_reset(): brq = Baroque() class MyEventType1(EventType): def __init__(self, owner=None): EventType.__init__(self, '''{ "$schema": "http://json-schema.org/draft-04/schema#" }''', description='test', owner=owner) class MyEventType2(EventType): def __init__(self, owner=None): EventType.__init__(self, '''{ "$schema": "http://json-schema.org/draft-04/schema#" }''', description='test', owner=owner) eventtype1 = MyEventType1() eventtype2 = MyEventType2() brq.on(eventtype1).run(ReactorFactory.stdout()) brq.on(eventtype2).run(ReactorFactory.stdout()) brq.publish(Event(eventtype1)) brq.publish(Event(eventtype2)) assert brq.events.count_all() == 2 assert brq.eventtypes.count() == 2 + len( DEFAULT_CONFIG['eventtypes']['pre_registered']) assert len(brq.reactors.registered_types) == 2 brq.reset() assert brq.events.count_all() == 0 assert brq.eventtypes.count() == 0 assert len(brq.reactors.registered_types) == 0
def test_persistence_backend(): brq = Baroque() # test we're actually using the claimed persistence backend cfg['events']['persist'] = True cfg['events'][ 'persistence_backend'] = 'tests.test_configuration.FakePersistenceBackend' brq.config = cfg pb = brq._persistance_backend assert len(pb) == 0 evt = Event(GenericEventType()) brq.publish(evt) assert len(pb) == 1 assert evt in pb
def test_register_on_binding(): # do register topics upon reactor binding cfg['topics']['register_on_binding'] = True brq = Baroque() brq.config = cfg t = Topic('test-topic') assert len(brq.topics) == 0 brq.on_topic_run(t, ReactorFactory.stdout()) assert len(brq.topics) == 1 # do not register topics upon reactor binding: throw an exception cfg['topics']['register_on_binding'] = False brq = Baroque() brq.config = cfg with pytest.raises(UnregisteredTopicError): brq.on_topic_run(t, ReactorFactory.stdout())
def test_ignore_unregistered_eventtypes(): # do ignore cfg['eventtypes']['ignore_unregistered'] = True brq = Baroque() brq.config = cfg try: brq.publish(Event(GenericEventType())) except UnregisteredEventTypeError: pytest.fail() # do not ignore cfg['eventtypes']['ignore_unregistered'] = False brq = Baroque() brq.config = cfg with pytest.raises(UnregisteredEventTypeError): brq.publish(Event(FakeEventType())) pytest.fail()
def test_publish(): # using a databox to keep state and make assertions box = Box() r1 = ReactorFactory.call_function(box, 'test_eventtype') r2 = ReactorFactory.call_function(box, 'any_eventtype') brq = Baroque() eventtype = GenericEventType() brq.on(eventtype).run(r1) brq.on_any_event_run(r2) evt = Event(eventtype) assert not box.reacted_on_test_eventtype assert not box.reacted_on_any_eventtype assert brq.events.count_all() == 0 brq.publish(evt) assert box.reacted_on_test_eventtype assert box.reacted_on_any_eventtype assert brq.events.count_all() == 1 assert evt.status == EventStatus.PUBLISHED with pytest.raises(AssertionError): brq.publish('not-an-event') pytest.fail()
def test_fire(): # using a databox to keep state and make assertions box = Box() r1 = ReactorFactory.call_function(box, 'test_eventtype') r2 = ReactorFactory.call_function(box, 'any_eventtype') brq = Baroque() eventtype = GenericEventType() brq.on(eventtype).run(r1) brq.on_any_event_run(r2) evt = Event(eventtype) assert not box.reacted_on_test_eventtype assert not box.reacted_on_any_eventtype assert brq.events.count_all() == 0 brq.fire(evt) assert box.reacted_on_test_eventtype assert box.reacted_on_any_eventtype assert brq.events.count_all() == 1
def test_validate_schema(): cfg['eventtypes']['pre_registered'] = [ 'baroque.defaults.eventtypes.MetricEventType' ] brq = Baroque() brq.config = cfg et = MetricEventType() event = Event(et, payload=dict(a=1, b=2)) # do not validate cfg['events']['validate_schema'] = False brq.config = cfg try: brq.publish(event) except InvalidEventSchemaError: pytest.fail() # do validate cfg['events']['validate_schema'] = True with pytest.raises(InvalidEventSchemaError): brq.publish(event)
def test_on_topic_run(): brq = Baroque() t1 = Topic('test-topic1', eventtypes=[MetricEventType(), GenericEventType()]) assert len(brq.topics.topics) == 0 brq.on_topic_run(t1, ReactorFactory.stdout()) assert len(brq.topics.topics) == 1 assert len(brq.topics.topics[t1]) == 1 # one more reactor on the same topic brq.on_topic_run(t1, ReactorFactory.stdout()) assert len(brq.topics.topics) == 1 assert len(brq.topics.topics[t1]) == 2 # let's register another topic t2 = Topic('test-topic2', eventtypes=[MetricEventType()]) brq.on_topic_run(t2, ReactorFactory.stdout()) assert len(brq.topics.topics) == 2 assert len(brq.topics.topics[t1]) == 2 assert len(brq.topics.topics[t2]) == 1
def test_publish_on_topic(): brq = Baroque() t = brq.topics.new('test-topic1', eventtypes=[MetricEventType(), GenericEventType()]) evt = Event(MetricEventType()) # trying to publish events to an unregistered topic with pytest.raises(UnregisteredTopicError): brq.publish_on_topic(evt, Topic('unregistered')) pytest.fail() # using a box to keep state and make assertions box = Box() brq.on_topic_run(t, ReactorFactory.call_function(box, 'mark_called')) assert not box.called assert brq.events.count_all() == 0 brq.publish_on_topic(evt, t) assert box.called assert brq.events.count_all() == 1 assert evt.status == EventStatus.PUBLISHED
def test_validate_event_schema(): brq = Baroque() et = MetricEventType() event_valid = Event(et, payload={ 'metric': 'temperature', 'value': 56.7793, 'timestamp': '2017-02-15T13:56:09Z' }) event_invalid = Event(et, payload={'metric': 'temperature'}) # Publish invalid event with pytest.raises(InvalidEventSchemaError): brq.publish(event_invalid) pytest.fail() # Publish valid event try: brq.publish(event_valid) except InvalidEventSchemaError: pytest.fail()
def test_topics(): brq = Baroque() result = brq.topics assert isinstance(result, TopicsRegistry)
from baroque import Baroque, Event, Reactor, GenericEventType, ReactorFactory # instantiate the library brq = Baroque() # EventTypes mark categories of events eventtype = GenericEventType() # Events are simple objects with properties event = Event(eventtype) # Reactors are stateless functions # instantiate a predefined reactor that mirrors the triggering event on stdout reactor = ReactorFactory.stdout() # attach the reactor to any incoming event of type "eventtype" brq.on(eventtype).run(reactor) # same as: brq.on("foobar").trigger(reactor) # now fire the event brq.publish(event) # same as: brq.fire(event) # view all tracked event types print(brq.eventtypes) print(brq.eventtypes.count()) # remove a reactor for a given event type brq.reactors.to(eventtype).remove(reactor) # ... or all reactors for it brq.reactors.to(eventtype).remove_all()
def test_events(): brq = Baroque() result = brq.events assert isinstance(result, EventCounter)
def test_eventtypes(): brq = Baroque() result = brq.eventtypes assert isinstance(result, EventTypesRegistry)
def append(evt): self.messages[evt.timestamp] = { 'pk': evt.payload['datum']['pk'], 'operation': evt.payload['operation'] } event_broker.on_topic_run(topic, Reactor(append)) def print_history(self): for ts, message in self.messages.items(): print('{} : {} of row with pk={}'.format(ts, message['operation'], message['pk'])) brq = Baroque() topic = brq.topics.new('datasource_changes', eventtypes=[DataOperationEventType()], description='changes in a datasource', owner='me') journal = Journal(brq, topic) # let's make new friends! friends = DataSource('friends', brq, topic) pk_louis = friends.add('Louis', 'Armstrong', 'US') pk_mick = friends.add('Mick', 'Jagger', 'GB') pk_luciano = friends.add('Luciano', 'Pavarotti', 'FR') friends.update(pk_luciano, 'Luciano', 'Pavarotti', 'IT') friends.delete(pk_mick) # and now let's review the history of changes to the datasource
def test_reactors(): brq = Baroque() result = brq.reactors assert isinstance(result, ReactorsRegistry)
def test_print(): print(Baroque())
def test_persist(): # persist events brq = Baroque() cfg['eventtypes']['ignore_unregistered'] = True cfg['eventtypes']['pre_registered'] = [ 'baroque.defaults.eventtypes.GenericEventType' ] cfg['topics']['register_on_binding'] = True cfg['events']['persist'] = True brq.config = cfg evt1 = Event(GenericEventType()) assert len(brq._persistance_backend) == 0 brq.publish(evt1) assert len(brq._persistance_backend) == 1 assert evt1 in brq._persistance_backend evt2 = Event(GenericEventType()) t = brq.topics.new('test-topic', eventtypes=[MetricEventType(), GenericEventType()]) assert len(brq._persistance_backend) == 1 brq.publish_on_topic(evt2, t) assert len(brq._persistance_backend) == 2 assert evt2 in brq._persistance_backend # do not persist events brq = Baroque() cfg['events']['persist'] = False brq.config = cfg evt3 = Event(GenericEventType()) assert len(brq._persistance_backend) == 0 brq.publish(evt3) assert len(brq._persistance_backend) == 0 evt4 = Event(GenericEventType()) t = brq.topics.new('test-topic', eventtypes=[MetricEventType(), GenericEventType()]) assert len(brq._persistance_backend) == 0 brq.publish_on_topic(evt4, t) assert len(brq._persistance_backend) == 0
def test_exception_bubbling(): # do propagate cfg['reactors']['propagate_exceptions'] = True brq = Baroque() brq.config = cfg def reaction_raising_error(evt): raise FileNotFoundError() r = Reactor(reaction_raising_error) brq.on(GenericEventType()).run(r) with pytest.raises(FileNotFoundError): brq.publish(Event(GenericEventType())) pytest.fail() # do not propagate cfg['reactors']['propagate_exceptions'] = False brq = Baroque() brq.config = cfg brq.on(GenericEventType()).run(r) try: brq.publish(Event(GenericEventType())) except FileNotFoundError: pytest.fail()
from baroque import Baroque, Event, DataOperationEventType, Reactor from baroque.utils.timestamp import stringify, utc_now ''' We want to keep in sync the value of a property of a target object instance (we will call it: target instance) with the values of a property of an observed instance, as the latter change. This is a one-way syncing. The syncing mechanism is as follows: - The update on the observed instance is notified using Baroque's out-of-the-box `DataOperationEventType` event type (but one can also develop its own `EventType` subclass and use it!) - every time the observed property changes, an event is published on the broker - the publication triggers the execution of a reactor, which is the update of the target object instance's property ''' brq = Baroque() class Observed: field = None def __init__(self, val): self.field = val def __setattr__(self, key, value): event = Event(DataOperationEventType, payload={ 'datum': { 'class': 'Observed', 'property': 'field'
def test_preregistered_eventtypes(): fake = 'tests.test_configuration.FakeEventType' cfg['eventtypes']['pre_registered'] = [fake] brq = Baroque() assert FakeEventType() in brq.eventtypes
def test_load_persistence_backend(): brq = Baroque() brq._load_persistence_backend() klass = class_from_dotted_path( DEFAULT_CONFIG['events']['persistence_backend']) assert isinstance(brq._persistance_backend, klass)
def test_load_preregistered_eventtypes(): brq = Baroque() assert brq.eventtypes.count() == len( DEFAULT_CONFIG['eventtypes']['pre_registered'])