def test_get_item(self): # Setup an event store. event_store = self.construct_event_store() # Put an event in the event store. entity_id = uuid4() event_store.store( Example.Created( a=1, b=2, originator_id=entity_id, originator_topic=get_topic(Example), )) # Construct a repository. event_sourced_repo = EventSourcedRepository(event_store=event_store) # Check the entity attributes. example = event_sourced_repo[entity_id] self.assertEqual(1, example.a) self.assertEqual(2, example.b) self.assertEqual(entity_id, example.id) # Setup an example repository, using the subclass ExampleRepository. example_repo = ExampleRepository(event_store=event_store) # Check the repo has the example. self.assertIn(entity_id, example_repo) self.assertNotIn(uuid4(), example_repo) # Check the entity attributes. example = example_repo[entity_id] self.assertEqual(1, example.a) self.assertEqual(2, example.b) self.assertEqual(entity_id, example.id)
def test_get_item(self): # Setup an event store. event_store = self.construct_event_store() # Put an event in the event store. entity_id = uuid4() event_store.append(Example.Created(entity_id=entity_id, a=1, b=2)) # Check ValueError is raised if repo doesn't have a mutator function... with self.assertRaises(ValueError): EventSourcedRepository(event_store=event_store, mutator=None) # ...and isn't if we pass a mutator function as a constructor arg. event_sourced_repo = EventSourcedRepository(event_store=event_store, mutator=Example.mutate) # Check the entity attributes. example = event_sourced_repo[entity_id] self.assertEqual(1, example.a) self.assertEqual(2, example.b) self.assertEqual(entity_id, example.id) # Setup an example repository, using the subclass ExampleRepository. example_repo = ExampleRepository(event_store=event_store) # Check the repo has the example. self.assertIn(entity_id, example_repo) self.assertNotIn(uuid4(), example_repo) # Check the entity attributes. example = example_repo[entity_id] self.assertEqual(1, example.a) self.assertEqual(2, example.b) self.assertEqual(entity_id, example.id)
def __init__(self, **kwargs): super(ExampleApplication, self).__init__(**kwargs) self.snapshot_strategy = EventSourcedSnapshotStrategy( event_store=self.timestamp_entity_event_store, ) self.example_repo = ExampleRepository( event_store=self.version_entity_event_store, snapshot_strategy=self.snapshot_strategy, )
def __init__(self, **kwargs): super(ExampleApplication, self).__init__(**kwargs) self.snapshot_strategy = None if self.snapshot_event_store: self.snapshot_strategy = EventSourcedSnapshotStrategy( snapshot_store=self.snapshot_event_store) assert self.entity_event_store is not None self.example_repository = ExampleRepository( event_store=self.entity_event_store, snapshot_strategy=self.snapshot_strategy, )
def __init__(self): self.event_store = EventStore( record_manager=CassandraRecordManager( record_class=StoredEventRecord, sequenced_item_class=StoredEvent), event_mapper=SequencedItemMapper(sequenced_item_class=StoredEvent, other_attr_names=()), ) self.repository = ExampleRepository(event_store=self.event_store) self.persistence_policy = PersistencePolicy( event_store=self.event_store, persist_event_type=DomainEvent)
def __init__(self): self.event_store = EventStore( active_record_strategy=CassandraActiveRecordStrategy( active_record_class=StoredEventRecord, sequenced_item_class=StoredEvent, ), sequenced_item_mapper=SequencedItemMapper( sequenced_item_class=StoredEvent, other_attr_names=(), )) self.repository = ExampleRepository(event_store=self.event_store, ) self.persistence_policy = PersistencePolicy(self.event_store)
def test_get_item(self) -> None: # Setup an event store. event_store = self.construct_event_store() # Put an event in the event store. entity_id = uuid4() event_store.store_events([ Example.Created( a=1, b=2, originator_id=entity_id, originator_topic=get_topic(Example), ) ]) # Construct a repository. event_sourced_repo: EventSourcedRepository[ Example, Example.Event] = EventSourcedRepository(event_store=event_store) # Check the entity attributes. example = event_sourced_repo[entity_id] self.assertEqual(1, example.a) self.assertEqual(2, example.b) self.assertEqual(entity_id, example.id) # Check class-specific request. example = event_sourced_repo.get_instance_of(Example, entity_id) self.assertEqual(1, example.a) self.assertEqual(2, example.b) self.assertEqual(entity_id, example.id) # Check class-specific request fails on type. class SubExample(Example): pass self.assertIsNone( event_sourced_repo.get_instance_of(SubExample, entity_id)) # Setup an example repository, using the subclass ExampleRepository. example_repo = ExampleRepository(event_store=event_store) # Check the repo has the example. self.assertIn(entity_id, example_repo) self.assertNotIn(uuid4(), example_repo) # Check the entity attributes. example = example_repo[entity_id] self.assertEqual(1, example.a) self.assertEqual(2, example.b) self.assertEqual(entity_id, example.id)
def __init__(self, session): self.event_store = EventStore( record_manager=SQLAlchemyRecordManager( session=session, record_class=StoredEventRecord, sequenced_item_class=StoredEvent, ), sequenced_item_mapper=SequencedItemMapper( sequenced_item_class=StoredEvent, sequence_id_attr_name='originator_id', position_attr_name='originator_version', )) self.repository = ExampleRepository(event_store=self.event_store, ) self.persistence_policy = PersistencePolicy(self.event_store)
def __init__(self, datastore): self.event_store = EventStore( active_record_strategy=SQLAlchemyActiveRecordStrategy( datastore=datastore, active_record_class=SqlExtendedIntegerSequencedItem, sequenced_item_class=ExtendedSequencedItem, ), sequenced_item_mapper=ExtendedSequencedItemMapper( sequenced_item_class=ExtendedSequencedItem, event_sequence_id_attr='entity_id', event_position_attr='entity_version', )) self.repository = ExampleRepository(event_store=self.event_store, ) self.persistence_policy = PersistencePolicy(self.event_store)
def __init__(self, session): self.event_store = EventStore( active_record_strategy=SQLAlchemyActiveRecordStrategy( session=session, active_record_class=ExtendedIntegerSequencedItemRecord, sequenced_item_class=ExtendedSequencedItem, ), sequenced_item_mapper=ExtendedSequencedItemMapper( sequenced_item_class=ExtendedSequencedItem, sequence_id_attr_name='originator_id', position_attr_name='originator_version', other_attr_names=('timestamp', ), )) self.repository = ExampleRepository(event_store=self.event_store, ) self.persistence_policy = PersistencePolicy(self.event_store)
def __init__(self, session): self.event_store = EventStore( record_manager=SQLAlchemyRecordManager( session=session, record_class=ExtendedIntegerSequencedRecord, sequenced_item_class=ExtendedSequencedItem, ), event_mapper=ExtendedSequencedItemMapper( sequenced_item_class=ExtendedSequencedItem, sequence_id_attr_name="originator_id", position_attr_name="originator_version", other_attr_names=("timestamp", ), ), ) self.repository = ExampleRepository(event_store=self.event_store) self.persistence_policy = PersistencePolicy( event_store=self.event_store, persist_event_type=DomainEvent)
def test_entity_lifecycle(self): # Check the factory creates an instance. example1 = Example.__create__(a=1, b=2) self.assertIsInstance(example1, Example) # Check the instance is equal to itself. self.assertEqual(example1, example1) # Check the instance is equal to a clone of itself. clone = object.__new__(type(example1)) clone.__dict__.update(example1.__dict__) self.assertEqual(example1, clone) # Check the properties of the Example class. self.assertEqual(1, example1.a) self.assertEqual(2, example1.b) # Check the properties of the TimestampedVersionedEntity class. self.assertTrue(example1.id) self.assertEqual(example1.__version__, 0) self.assertTrue(example1.__created_on__) self.assertLess(example1.__created_on__, time.time()) self.assertGreater(example1.__created_on__, time.time() - 1) self.assertTrue(example1.__last_modified__) self.assertEqual(example1.__created_on__, example1.__last_modified__) # Test the datetime_from_timestamp() converts ok. tt = time.time() dt = datetime.datetime.utcnow() self.assertEqual(datetime_from_timestamp(tt).hour, dt.hour) # Check can get datetime from timestamps, and it corresponds to UTC. dt = datetime_from_timestamp(example1.__created_on__) self.assertLess(dt, datetime.datetime.utcnow()) self.assertGreater(dt, datetime.datetime.utcnow() - datetime.timedelta(1)) # Check a different type with the same values is not "equal" to the first. class Subclass(Example): pass other = object.__new__(Subclass) other.__dict__.update(example1.__dict__) self.assertEqual(example1.__dict__, other.__dict__) self.assertNotEqual(example1, other) # Check a second instance with the same values is not "equal" to the first. example2 = create_new_example(a=1, b=2) self.assertEqual(type(example1), type(example2)) self.assertNotEqual(example1, example2) # Check entity not hashable. with self.assertRaises(TypeError): hash(example1) # Setup the repo. repo = ExampleRepository(self.entity_event_store) # Check the example entities can be retrieved from the example repository. entity1 = repo[example1.id] self.assertIsInstance(entity1, Example) self.assertEqual(1, entity1.a) self.assertEqual(2, entity1.b) entity2 = repo[example2.id] self.assertIsInstance(entity2, Example) self.assertEqual(1, entity2.a) self.assertEqual(2, entity2.b) # Check the entity can be updated. entity1.a = 100 self.assertEqual(100, repo[entity1.id].a) entity1.b = -200 self.assertEqual(-200, repo[entity1.id].b) self.assertEqual(repo[entity1.id].__created_on__, entity1.__created_on__) self.assertEqual(repo[entity1.id].__last_modified__, entity1.__last_modified__) self.assertNotEqual(entity1.__last_modified__, entity1.__created_on__) self.assertEqual(0, entity1.count_heartbeats()) entity1.beat_heart() entity1.beat_heart() entity1.beat_heart() self.assertEqual(3, entity1.count_heartbeats()) self.assertEqual(3, repo[entity1.id].count_heartbeats()) # Check the entity can publish multiple events simultaneously. entity1.beat_heart(number_of_beats=3) self.assertEqual(6, repo[entity1.id].count_heartbeats()) # Check the entity can be discarded. entity1.__discard__() # Check the repo now raises a KeyError. self.assertRaises(RepositoryKeyError, repo.__getitem__, entity1.id) # Check the entity can't be discarded twice. self.assertRaises(AssertionError, entity1.__discard__) # Should fail to validate event with wrong entity ID. with self.assertRaises(OriginatorIDError): VersionedEntity.Event( originator_id=uuid4(), originator_version=0, ).__check_obj__(entity2) # Should fail to validate event with wrong entity version. with self.assertRaises(OriginatorVersionError): VersionedEntity.Event( originator_id=entity2.id, originator_version=0, __previous_hash__=entity2.__head__, ).__check_obj__(entity2) # Should validate event with correct entity ID and version. VersionedEntity.Event( originator_id=entity2.id, originator_version=entity2.__version__ + 1, __previous_hash__=entity2.__head__, ).__check_obj__(entity2) # Check an entity cannot be reregistered with the ID of a discarded entity. replacement_event = Example.Created( originator_id=entity1.id, a=11, b=12, originator_topic=get_topic(Example), ) with self.assertRaises(ConcurrencyError): publish(event=replacement_event)
def test_entity_lifecycle(self): # Check the factory creates an instance. example1 = create_new_example(a=1, b=2) self.assertIsInstance(example1, Example) # Check the instance is equal to itself. self.assertEqual(example1, example1) # Check the instance is equal to a clone of itself. clone = object.__new__(type(example1)) clone.__dict__.update(example1.__dict__) self.assertEqual(example1, clone) # Check the properties of the Example class. self.assertEqual(1, example1.a) self.assertEqual(2, example1.b) # Check the properties of the TimestampedVersionedEntity class. self.assertTrue(example1.id) self.assertEqual(1, example1.version) self.assertTrue(example1.created_on) self.assertTrue(example1.last_modified) self.assertEqual(example1.created_on, example1.last_modified) # Check a different type with the same values is not "equal" to the first. class Subclass(Example): pass other = object.__new__(Subclass) other.__dict__.update(example1.__dict__) self.assertEqual(example1.__dict__, other.__dict__) self.assertNotEqual(example1, other) # Check a second instance with the same values is not "equal" to the first. example2 = create_new_example(a=1, b=2) self.assertEqual(type(example1), type(example2)) self.assertNotEqual(example1, example2) # Setup the repo. repo = ExampleRepository(self.entity_event_store) # Check the example entities can be retrieved from the example repository. entity1 = repo[example1.id] self.assertIsInstance(entity1, Example) self.assertEqual(1, entity1.a) self.assertEqual(2, entity1.b) entity2 = repo[example2.id] self.assertIsInstance(entity2, Example) self.assertEqual(1, entity2.a) self.assertEqual(2, entity2.b) # Check the entity can be updated. entity1.a = 100 self.assertEqual(100, repo[entity1.id].a) entity1.b = -200 self.assertEqual(-200, repo[entity1.id].b) self.assertEqual(repo[entity1.id].created_on, entity1.created_on) self.assertEqual(repo[entity1.id].last_modified, entity1.last_modified) self.assertNotEqual(entity1.last_modified, entity1.created_on) self.assertEqual(0, entity1.count_heartbeats()) entity1.beat_heart() entity1.beat_heart() entity1.beat_heart() self.assertEqual(3, entity1.count_heartbeats()) self.assertEqual(3, repo[entity1.id].count_heartbeats()) # Check the entity can publish multiple events simultaneously. entity1.beat_heart(number_of_beats=3) self.assertEqual(6, repo[entity1.id].count_heartbeats()) # Check the entity can be discarded. entity1.discard() # Check the repo now raises a KeyError. self.assertRaises(RepositoryKeyError, repo.__getitem__, entity1.id) # Check the entity can't be discarded twice. self.assertRaises(AssertionError, entity1.discard) # Should fail to validate event with wrong entity ID. with self.assertRaises(MismatchedOriginatorIDError): entity2._validate_originator( VersionedEntity.Event(originator_id=uuid4(), originator_version=0)) # Should fail to validate event with wrong entity version. with self.assertRaises(MismatchedOriginatorVersionError): entity2._validate_originator( VersionedEntity.Event( originator_id=entity2.id, originator_version=0, )) # Should validate event with correct entity ID and version. entity2._validate_originator( VersionedEntity.Event( originator_id=entity2.id, originator_version=entity2.version, )) # Check an entity cannot be reregistered with the ID of a discarded entity. replacement_event = Example.Created(originator_id=entity1.id, a=11, b=12) with self.assertRaises(ConcurrencyError): publish(event=replacement_event)