class TestEventPlayer(SQLAlchemyDatastoreTestCase): def setUp(self): assert_event_handlers_empty() super(TestEventPlayer, self).setUp() self.datastore.setup_connection() self.datastore.setup_tables() # Setup an event store for versioned entity events. self.entity_event_store = EventStore( active_record_strategy=SQLAlchemyActiveRecordStrategy( session=self.datastore.session, active_record_class=IntegerSequencedItemRecord, sequenced_item_class=SequencedItem, ), sequenced_item_mapper=SequencedItemMapper( sequenced_item_class=SequencedItem, sequence_id_attr_name='originator_id', position_attr_name='originator_version', ), ) # Setup an event store for snapshots. self.snapshot_store = EventStore( active_record_strategy=SQLAlchemyActiveRecordStrategy( session=self.datastore.session, active_record_class=SnapshotRecord, sequenced_item_class=SequencedItem, ), sequenced_item_mapper=SequencedItemMapper( sequenced_item_class=SequencedItem, sequence_id_attr_name='originator_id', position_attr_name='originator_version', ), ) self.entity_persistence_policy = None self.snapshot_persistence_policy = None def tearDown(self): self.datastore.drop_tables() self.datastore.drop_connection() if self.entity_persistence_policy is not None: self.entity_persistence_policy.close() if self.snapshot_persistence_policy is not None: self.snapshot_persistence_policy.close() super(TestEventPlayer, self).tearDown() assert_event_handlers_empty() def test_replay_entity(self): # Store example events. # Create entity1. entity_id1 = uuid4() event1 = Example.Created(originator_id=entity_id1, a=1, b=2) self.entity_event_store.append(event1) # Create entity2. entity_id2 = uuid4() event2 = Example.Created(originator_id=entity_id2, a=2, b=4) self.entity_event_store.append(event2) # Create entity3. entity_id3 = uuid4() event3 = Example.Created(originator_id=entity_id3, a=3, b=6) self.entity_event_store.append(event3) # Discard entity3. event4 = Example.Discarded(originator_id=entity_id3, originator_version=1) self.entity_event_store.append(event4) # Check the entities can be replayed. event_player = EventPlayer(event_store=self.entity_event_store, mutator=Example._mutate) # Check recovered entities have correct attribute values. recovered1 = event_player.replay_entity(entity_id1) self.assertEqual(entity_id1, recovered1.id) self.assertEqual(1, recovered1.a) recovered2 = event_player.replay_entity(entity_id2) self.assertEqual(2, recovered2.a) recovered3 = event_player.replay_entity(entity_id3) self.assertEqual(None, recovered3) # Check it works for "short" entities (should be faster, but the main thing is that it still works). # - just use a trivial mutate that always instantiates the 'Example'. event5 = Example.AttributeChanged(originator_id=entity_id1, originator_version=1, name='a', value=10) self.entity_event_store.append(event5) recovered1 = event_player.replay_entity(entity_id1) self.assertEqual(10, recovered1.a) event_player = EventPlayer( event_store=self.entity_event_store, mutator=Example._mutate, is_short=True, ) self.assertEqual(10, event_player.replay_entity(entity_id1).a) def test_take_snapshot(self): self.entity_persistence_policy = PersistencePolicy( event_store=self.entity_event_store, event_type=VersionedEntity.Event, ) self.snapshot_persistence_policy = PersistencePolicy( event_store=self.snapshot_store, event_type=Snapshot, ) snapshot_strategy = EventSourcedSnapshotStrategy( event_store=self.snapshot_store) event_player = EventPlayer(event_store=self.entity_event_store, mutator=Example._mutate, snapshot_strategy=snapshot_strategy) # Take a snapshot with a non-existent ID. unregistered_id = uuid4() # Check no snapshot is taken. self.assertIsNone(event_player.take_snapshot(unregistered_id)) # Check no snapshot is available. self.assertIsNone(event_player.get_snapshot(unregistered_id)) # Create a new entity. registered_example = create_new_example(a=123, b=234) # Take a snapshot of the new entity (no previous snapshots). snapshot1 = event_player.take_snapshot(registered_example.id, lt=registered_example.version) # Check the snapshot is pegged to the last applied version. self.assertEqual(snapshot1.originator_version, 0) # Replay from this snapshot. entity_from_snapshot1 = entity_from_snapshot(snapshot1) retrieved_example = event_player.replay_entity( registered_example.id, initial_state=entity_from_snapshot1, gte=entity_from_snapshot1._version) # Check the attributes are correct. self.assertEqual(retrieved_example.a, 123) # Remember the version now. version1 = retrieved_example._version self.assertEqual(version1, 1) # Change attribute value. retrieved_example.a = 999 # Remember the version now. version2 = retrieved_example._version self.assertEqual(version2, 2) # Change attribute value. retrieved_example.a = 9999 # Remember the version now. version3 = retrieved_example._version self.assertEqual(version3, 3) # Check the event sourced entities are correct. retrieved_example = event_player.replay_entity(registered_example.id) self.assertEqual(retrieved_example.a, 9999) # Take another snapshot. snapshot2 = event_player.take_snapshot(retrieved_example.id, lt=retrieved_example.version) # Replay from this snapshot. initial_state = entity_from_snapshot(snapshot2) retrieved_example = event_player.replay_entity( registered_example.id, initial_state=initial_state, gte=initial_state._version, ) # Check the attributes are correct. self.assertEqual(retrieved_example.a, 9999) # Check we can get historical state at version1. retrieved_example = event_player.replay_entity(registered_example.id, lt=version1) self.assertEqual(retrieved_example.a, 123) # Check we can get historical state at version2. retrieved_example = event_player.replay_entity(registered_example.id, lt=version2) self.assertEqual(retrieved_example.a, 999) # Check we can get historical state at version3. retrieved_example = event_player.replay_entity(registered_example.id, lt=version3) self.assertEqual(retrieved_example.a, 9999) # Similarly, check we can get historical state using a snapshot initial_state = entity_from_snapshot(snapshot1) retrieved_example = event_player.replay_entity( registered_example.id, initial_state=initial_state, gte=initial_state._version, lt=version2, ) self.assertEqual(retrieved_example.a, 999) # Discard the entity. registered_example = event_player.replay_entity(registered_example.id) registered_example.discard() # Take snapshot of discarded entity. snapshot3 = event_player.take_snapshot(registered_example.id) self.assertIsNone(snapshot3.state) self.assertIsNone(entity_from_snapshot(snapshot3))
class TestEventPlayer(SQLAlchemyDatastoreTestCase): def setUp(self): assert_event_handlers_empty() super(TestEventPlayer, self).setUp() self.datastore.setup_connection() self.datastore.setup_tables() # Setup an event store for versioned entity events. self.entity_event_store = EventStore( active_record_strategy=SQLAlchemyActiveRecordStrategy( session=self.datastore.session, active_record_class=IntegerSequencedItemRecord, sequenced_item_class=SequencedItem, ), sequenced_item_mapper=SequencedItemMapper( sequenced_item_class=SequencedItem, sequence_id_attr_name='originator_id', position_attr_name='originator_version', ), ) # Setup an event store for snapshots. self.snapshot_store = EventStore( active_record_strategy=SQLAlchemyActiveRecordStrategy( session=self.datastore.session, active_record_class=SnapshotRecord, sequenced_item_class=SequencedItem, ), sequenced_item_mapper=SequencedItemMapper( sequenced_item_class=SequencedItem, sequence_id_attr_name='originator_id', position_attr_name='originator_version', ), ) self.entity_persistence_policy = None self.snapshot_persistence_policy = None def tearDown(self): self.datastore.drop_tables() self.datastore.drop_connection() if self.entity_persistence_policy is not None: self.entity_persistence_policy.close() if self.snapshot_persistence_policy is not None: self.snapshot_persistence_policy.close() super(TestEventPlayer, self).tearDown() assert_event_handlers_empty() def test_replay_entity(self): # Store example events. # Create entity1. entity_id1 = uuid4() event1 = Example.Created(originator_id=entity_id1, a=1, b=2) self.entity_event_store.append(event1) # Create entity2. entity_id2 = uuid4() event2 = Example.Created(originator_id=entity_id2, a=2, b=4) self.entity_event_store.append(event2) # Create entity3. entity_id3 = uuid4() event3 = Example.Created(originator_id=entity_id3, a=3, b=6) self.entity_event_store.append(event3) # Discard entity3. event4 = Example.Discarded(originator_id=entity_id3, originator_version=1) self.entity_event_store.append(event4) # Check the entities can be replayed. event_player = EventPlayer(event_store=self.entity_event_store, mutator=Example._mutate) # Check recovered entities have correct attribute values. recovered1 = event_player.replay_entity(entity_id1) self.assertEqual(entity_id1, recovered1.id) self.assertEqual(1, recovered1.a) recovered2 = event_player.replay_entity(entity_id2) self.assertEqual(2, recovered2.a) recovered3 = event_player.replay_entity(entity_id3) self.assertEqual(None, recovered3) # Check it works for "short" entities (should be faster, but the main thing is that it still works). # - just use a trivial mutate that always instantiates the 'Example'. event5 = Example.AttributeChanged(originator_id=entity_id1, originator_version=1, name='a', value=10) self.entity_event_store.append(event5) recovered1 = event_player.replay_entity(entity_id1) self.assertEqual(10, recovered1.a) event_player = EventPlayer( event_store=self.entity_event_store, mutator=Example._mutate, is_short=True, ) self.assertEqual(10, event_player.replay_entity(entity_id1).a) def test_take_snapshot(self): self.entity_persistence_policy = PersistencePolicy( event_store=self.entity_event_store, event_type=VersionedEntity.Event, ) self.snapshot_persistence_policy = PersistencePolicy( event_store=self.snapshot_store, event_type=Snapshot, ) snapshot_strategy = EventSourcedSnapshotStrategy( event_store=self.snapshot_store ) event_player = EventPlayer( event_store=self.entity_event_store, mutator=Example._mutate, snapshot_strategy=snapshot_strategy ) # Take a snapshot with a non-existent ID. unregistered_id = uuid4() # Check no snapshot is taken. self.assertIsNone(event_player.take_snapshot(unregistered_id)) # Check no snapshot is available. self.assertIsNone(event_player.get_snapshot(unregistered_id)) # Create a new entity. registered_example = create_new_example(a=123, b=234) # Take a snapshot of the new entity (no previous snapshots). snapshot1 = event_player.take_snapshot(registered_example.id, lt=registered_example.version) # Check the snapshot is pegged to the last applied version. self.assertEqual(snapshot1.originator_version, 0) # Replay from this snapshot. entity_from_snapshot1 = entity_from_snapshot(snapshot1) retrieved_example = event_player.replay_entity(registered_example.id, initial_state=entity_from_snapshot1, gte=entity_from_snapshot1._version) # Check the attributes are correct. self.assertEqual(retrieved_example.a, 123) # Remember the version now. version1 = retrieved_example._version self.assertEqual(version1, 1) # Change attribute value. retrieved_example.a = 999 # Remember the version now. version2 = retrieved_example._version self.assertEqual(version2, 2) # Change attribute value. retrieved_example.a = 9999 # Remember the version now. version3 = retrieved_example._version self.assertEqual(version3, 3) # Check the event sourced entities are correct. retrieved_example = event_player.replay_entity(registered_example.id) self.assertEqual(retrieved_example.a, 9999) # Take another snapshot. snapshot2 = event_player.take_snapshot(retrieved_example.id, lt=retrieved_example.version) # Replay from this snapshot. initial_state = entity_from_snapshot(snapshot2) retrieved_example = event_player.replay_entity( registered_example.id, initial_state=initial_state, gte=initial_state._version, ) # Check the attributes are correct. self.assertEqual(retrieved_example.a, 9999) # Check we can get historical state at version1. retrieved_example = event_player.replay_entity(registered_example.id, lt=version1) self.assertEqual(retrieved_example.a, 123) # Check we can get historical state at version2. retrieved_example = event_player.replay_entity(registered_example.id, lt=version2) self.assertEqual(retrieved_example.a, 999) # Check we can get historical state at version3. retrieved_example = event_player.replay_entity(registered_example.id, lt=version3) self.assertEqual(retrieved_example.a, 9999) # Similarly, check we can get historical state using a snapshot initial_state = entity_from_snapshot(snapshot1) retrieved_example = event_player.replay_entity( registered_example.id, initial_state=initial_state, gte=initial_state._version, lt=version2, ) self.assertEqual(retrieved_example.a, 999) # Discard the entity. registered_example = event_player.replay_entity(registered_example.id) registered_example.discard() # Take snapshot of discarded entity. snapshot3 = event_player.take_snapshot(registered_example.id) self.assertIsNone(snapshot3.state) self.assertIsNone(entity_from_snapshot(snapshot3))
class TestEventPlayer(SQLAlchemyDatastoreTestCase): def setUp(self): assert_event_handlers_empty() super(TestEventPlayer, self).setUp() self.datastore.setup_connection() self.datastore.setup_tables() # Setup an event store for version entity events. self.version_entity_event_store = EventStore( active_record_strategy=SQLAlchemyActiveRecordStrategy( datastore=self.datastore, active_record_class=SqlIntegerSequencedItem, sequenced_item_class=SequencedItem, ), sequenced_item_mapper=SequencedItemMapper( sequenced_item_class=SequencedItem, event_sequence_id_attr='entity_id', event_position_attr='entity_version', ), ) # Setup an event store for timestamp entity events. self.timestamp_entity_event_store = EventStore( active_record_strategy=SQLAlchemyActiveRecordStrategy( datastore=self.datastore, active_record_class=SqlTimestampSequencedItem, sequenced_item_class=SequencedItem, ), sequenced_item_mapper=SequencedItemMapper( sequenced_item_class=SequencedItem, event_sequence_id_attr='entity_id', event_position_attr='timestamp', ), ) self.policy = None def tearDown(self): self.datastore.drop_tables() self.datastore.drop_connection() if self.policy is not None: self.policy.close() super(TestEventPlayer, self).tearDown() assert_event_handlers_empty() def test_get_entity(self): # Store example events. entity_id1 = uuid4() event1 = Example.Created(entity_id=entity_id1, a=1, b=2) self.version_entity_event_store.append(event1) entity_id2 = uuid4() event2 = Example.Created(entity_id=entity_id2, a=2, b=4) self.version_entity_event_store.append(event2) entity_id3 = uuid4() event3 = Example.Created(entity_id=entity_id3, a=3, b=6) self.version_entity_event_store.append(event3) event4 = Example.Discarded(entity_id=entity_id3, entity_version=1) self.version_entity_event_store.append(event4) # Check the event sourced entities are correct. # - just use a trivial mutate that always instantiates the 'Example'. event_player = EventPlayer(event_store=self.version_entity_event_store, mutator=Example.mutate) # The the reconstituted entity has correct attribute values. self.assertEqual(entity_id1, event_player.replay_entity(entity_id1).id) self.assertEqual(1, event_player.replay_entity(entity_id1).a) self.assertEqual(2, event_player.replay_entity(entity_id2).a) self.assertEqual(None, event_player.replay_entity(entity_id3)) # Check entity3 raises KeyError. self.assertEqual(event_player.replay_entity(entity_id3), None) # Check it works for "short" entities (should be faster, but the main thing is that it still works). # - just use a trivial mutate that always instantiates the 'Example'. event5 = Example.AttributeChanged(entity_id=entity_id1, entity_version=1, name='a', value=10) self.version_entity_event_store.append(event5) event_player = EventPlayer(event_store=self.version_entity_event_store, mutator=Example.mutate) self.assertEqual(10, event_player.replay_entity(entity_id1).a) event_player = EventPlayer( event_store=self.version_entity_event_store, mutator=Example.mutate, is_short=True, ) self.assertEqual(10, event_player.replay_entity(entity_id1).a) # Todo: Maybe this is an application-level test? If not, test event player capabilities here only. def test_snapshots(self): self.policy = CombinedPersistencePolicy( versioned_entity_event_store=self.version_entity_event_store, timestamped_entity_event_store=self.timestamp_entity_event_store, ) event_player = EventPlayer( event_store=self.version_entity_event_store, mutator=Example.mutate, snapshot_strategy=EventSourcedSnapshotStrategy( event_store=self.timestamp_entity_event_store ) ) # Take a snapshot with a non-existent ID. self.assertIsNone(event_player.take_snapshot(uuid4())) # Create a new entity. registered_example = register_new_example(a=123, b=234) # Take a snapshot. snapshot1 = event_player.take_snapshot(registered_example.id) # Replay from this snapshot. initial_state = entity_from_snapshot(snapshot1) retrieved_example = event_player.replay_entity(registered_example.id, initial_state=initial_state, gte=initial_state._version) # Check the attributes are correct. self.assertEqual(retrieved_example.a, 123) # Remember the version now. version1 = retrieved_example._version # Change attribute value. retrieved_example.a = 999 # Remember the version now. version2 = retrieved_example._version # Change attribute value. retrieved_example.a = 9999 # Remember the version now. version3 = retrieved_example._version # Check the event sourced entities are correct. retrieved_example = event_player.replay_entity(registered_example.id) self.assertEqual(retrieved_example.a, 9999) # Take another snapshot. snapshot2 = event_player.take_snapshot(retrieved_example.id) # Check we can replay from this snapshot. initial_state = entity_from_snapshot(snapshot2) retrieved_example = event_player.replay_entity( registered_example.id, initial_state=initial_state, gte=initial_state._version, ) # Check the attributes are correct. self.assertEqual(retrieved_example.a, 9999) # Check we can get historical state at version1. retrieved_example = event_player.replay_entity(registered_example.id, lt=version1) self.assertEqual(retrieved_example.a, 123) # Check we can get historical state at version2. retrieved_example = event_player.replay_entity(registered_example.id, lt=version2) self.assertEqual(retrieved_example.a, 999) # Check we can get historical state at version3. retrieved_example = event_player.replay_entity(registered_example.id, lt=version3) self.assertEqual(retrieved_example.a, 9999) # Similarly, check we can get historical state using a snapshot initial_state = entity_from_snapshot(snapshot1) retrieved_example = event_player.replay_entity( registered_example.id, initial_state=initial_state, gte=initial_state._version, lt=version2, ) self.assertEqual(retrieved_example.a, 999)