def test_entity_lifecycle(self): # Check the factory creates an instance. example1 = register_new_example(a=1, b=2) self.assertIsInstance(example1, Example) self.assertEqual(1, example1.a) self.assertEqual(2, example1.b) # Check a second instance with the same values is not "equal" to the first. example2 = register_new_example(a=1, b=2) self.assertNotEqual(example1, example2) # Setup the repo. repo = ExampleRepository(self.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(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 be discarded. entity1.discard() self.assertRaises(KeyError, repo.__getitem__, entity1.id)
def test_with_snapshots(self): # Check the EventPlayer's take_snapshot() method. stored_event_repo = PythonObjectsStoredEventRepository() event_store = EventStore(stored_event_repo) self.ps = PersistenceSubscriber(event_store) event_player = EventPlayer( event_store=event_store, id_prefix='Example', mutate_func=Example.mutate, snapshot_strategy=EventSourcedSnapshotStrategy( event_store=event_store)) # Check the method returns None when there are no events. snapshot = event_player.take_snapshot('wrong') self.assertIsNone(snapshot) # Create a new entity. example = register_new_example(a=123, b=234) # Take a snapshot with the entity. snapshot1 = event_player.take_snapshot(example.id) self.assertIsInstance(snapshot1, Snapshot) # Take another snapshot with the entity. snapshot2 = event_player.take_snapshot(example.id) # - should return the previous snapshot self.assertIsInstance(snapshot2, Snapshot) self.assertEqual(snapshot2.at_event_id, snapshot1.at_event_id) # Generate a domain event. example.beat_heart() # Take another snapshot with the entity. # - should use the previous snapshot and the heartbeat event snapshot3 = event_player.take_snapshot(example.id) self.assertNotEqual(snapshot3.at_event_id, snapshot1.at_event_id)
def test_with_snapshots(self): # Check the EventPlayer's take_snapshot() method. stored_event_repo = PythonObjectsStoredEventRepository() event_store = EventStore(stored_event_repo) self.ps = PersistenceSubscriber(event_store) event_player = EventPlayer( event_store=event_store, id_prefix='Example', mutate_func=Example.mutate, snapshot_strategy=EventSourcedSnapshotStrategy(event_store=event_store) ) # Check the method returns None when there are no events. snapshot = event_player.take_snapshot('wrong') self.assertIsNone(snapshot) # Create a new entity. example = register_new_example(a=123, b=234) # Take a snapshot with the entity. snapshot1 = event_player.take_snapshot(example.id) self.assertIsInstance(snapshot1, Snapshot) # Take another snapshot with the entity. snapshot2 = event_player.take_snapshot(example.id) # - should return the previous snapshot self.assertIsInstance(snapshot2, Snapshot) self.assertEqual(snapshot2.at_event_id, snapshot1.at_event_id) # Generate a domain event. example.beat_heart() # Take another snapshot with the entity. # - should use the previous snapshot and the heartbeat event snapshot3 = event_player.take_snapshot(example.id) self.assertNotEqual(snapshot3.at_event_id, snapshot1.at_event_id)
def register_new_example(self, a, b): return register_new_example(a=a, b=b)
def test_entity_performance(self): """ Reports on the performance of Example entity and repo. NB: This test doesn't actually check anything, so it isn't really a test. """ # Initialise dict of entities. self.entities = {} report_name = type(self).__name__[4:] print("\n\n{} report:\n".format(report_name)) repetitions = 10 # NB: Use range(1, 5) to test whether we can get more than 10000 event from Cassandra. for i in six.moves.range(0, 5): # Setup a number of entities, with different lengths of event history. payload = 3 # payload = str([uuid4().hex for _ in six.moves.range(100000)]) example = register_new_example(a=1, b=payload) self.entities[i] = example # Beat a number of times. start_beating = utc_now() num_beats = int(floor(10 ** i)) for _ in six.moves.range(num_beats): example.beat_heart() time_beating = utc_now() - start_beating print("Time to beat {} times: {:.2f}s ({:.0f} beats/s, {:.6f}s each)" "".format(num_beats, time_beating, num_beats / time_beating, time_beating / num_beats)) # Get the last n events from the repo. def last_n(n): n = min(n, num_beats + 1) stored_entity_id = make_stored_entity_id('Example', example.id) repo = self.app.example_repo.event_player.event_store.stored_event_repo start_last_n = utc_now() last_n_stored_events = [] for _ in six.moves.range(repetitions): last_n_stored_events = repo.get_most_recent_events(stored_entity_id, limit=n) time_last_n = (utc_now() - start_last_n) / repetitions num_retrieved_events = len(list(last_n_stored_events)) events_per_second = num_retrieved_events / time_last_n print(("Time to get last {:>"+str(i+1)+"} events after {} events: {:.6f}s ({:.0f} events/s)" "").format(n, num_beats + 1, time_last_n, events_per_second)) for j in range(0, i+1): last_n(10**j) # Get the entity by replaying all events (which it must since there isn't a snapshot). start_replay = utc_now() for _ in six.moves.range(repetitions): example = self.app.example_repo[example.id] assert isinstance(example, Example) heartbeats = example.count_heartbeats() assert heartbeats == num_beats, (heartbeats, num_beats) time_replaying = (utc_now() - start_replay) / repetitions print("Time to replay {} beats: {:.2f}s ({:.0f} beats/s, {:.6f}s each)" "".format(num_beats, time_replaying, num_beats / time_replaying, time_replaying / num_beats)) # Take snapshot, and beat heart a few more times. self.app.example_repo.event_player.take_snapshot(example.id, until=uuid1().hex) extra_beats = 4 for _ in six.moves.range(extra_beats): example.beat_heart() num_beats += extra_beats # Get the entity using snapshot and replaying events since the snapshot. start_replay = utc_now() for _ in six.moves.range(repetitions): example = self.app.example_repo[example.id] time_replaying = (utc_now() - start_replay) / repetitions events_per_second = (extra_beats + 1) / time_replaying # +1 for the snapshot event beats_per_second = num_beats / time_replaying print("Time to replay snapshot with {} extra beats: {:.6f}s ({:.0f} events/s, {:.0f} beats/s)" "".format(extra_beats, time_replaying, events_per_second, beats_per_second)) print("")
def test_snapshots(self): stored_event_repo = PythonObjectsStoredEventRepository() event_store = EventStore(stored_event_repo) self.ps = PersistenceSubscriber(event_store) event_player = EventPlayer(event_store=event_store, id_prefix='Example', mutate_func=Example.mutate) # Create a new entity. registered_example = register_new_example(a=123, b=234) # Take a snapshot. snapshot = take_snapshot(registered_example, uuid1().hex) # Replay from this snapshot. after = snapshot.at_event_id initial_state = entity_from_snapshot(snapshot) retrieved_example = event_player.replay_events( registered_example.id, initial_state=initial_state, after=after) # Check the attributes are correct. self.assertEqual(retrieved_example.a, 123) # Remember the time now. timecheck1 = uuid1().hex # Change attribute value. retrieved_example.a = 999 # Check the initial state doesn't move. self.assertEqual(initial_state.a, 123) # Remember the time now. timecheck2 = uuid1().hex # Change attribute value. retrieved_example.a = 9999 # Remember the time now. timecheck3 = uuid1().hex # Check the event sourced entities are correct. assert initial_state.a == 123 retrieved_example = event_player.replay_events(registered_example.id) self.assertEqual(retrieved_example.a, 9999) # Take another snapshot. snapshot2 = take_snapshot(retrieved_example, uuid1().hex) # Check we can replay from this snapshot. initial_state2 = entity_from_snapshot(snapshot2) after2 = snapshot2.domain_event_id retrieved_example = event_player.replay_events( registered_example.id, initial_state=initial_state2, after=after2) # Check the attributes are correct. self.assertEqual(retrieved_example.a, 9999) # Check we can get historical state at timecheck1. retrieved_example = event_player.replay_events(registered_example.id, until=timecheck1) self.assertEqual(retrieved_example.a, 123) # Check we can get historical state at timecheck2. retrieved_example = event_player.replay_events(registered_example.id, until=timecheck2) self.assertEqual(retrieved_example.a, 999) # Check we can get historical state at timecheck3. retrieved_example = event_player.replay_events(registered_example.id, until=timecheck3) self.assertEqual(retrieved_example.a, 9999) # Similarly, check we can get historical state using a snapshot retrieved_example = event_player.replay_events( registered_example.id, initial_state=initial_state, after=after, until=timecheck2) self.assertEqual(retrieved_example.a, 999)
def test_snapshots(self): stored_event_repo = PythonObjectsStoredEventRepository() event_store = EventStore(stored_event_repo) self.ps = PersistenceSubscriber(event_store) event_player = EventPlayer(event_store=event_store, id_prefix='Example', mutate_func=Example.mutate) # Create a new entity. registered_example = register_new_example(a=123, b=234) # Take a snapshot. snapshot = take_snapshot(registered_example, uuid1().hex) # Replay from this snapshot. after = snapshot.at_event_id initial_state = entity_from_snapshot(snapshot) retrieved_example = event_player.replay_events(registered_example.id, initial_state=initial_state, after=after) # Check the attributes are correct. self.assertEqual(retrieved_example.a, 123) # Remember the time now. timecheck1 = uuid1().hex # Change attribute value. retrieved_example.a = 999 # Check the initial state doesn't move. self.assertEqual(initial_state.a, 123) # Remember the time now. timecheck2 = uuid1().hex # Change attribute value. retrieved_example.a = 9999 # Remember the time now. timecheck3 = uuid1().hex # Check the event sourced entities are correct. assert initial_state.a == 123 retrieved_example = event_player.replay_events(registered_example.id) self.assertEqual(retrieved_example.a, 9999) # Take another snapshot. snapshot2 = take_snapshot(retrieved_example, uuid1().hex) # Check we can replay from this snapshot. initial_state2 = entity_from_snapshot(snapshot2) after2 = snapshot2.domain_event_id retrieved_example = event_player.replay_events(registered_example.id, initial_state=initial_state2, after=after2) # Check the attributes are correct. self.assertEqual(retrieved_example.a, 9999) # Check we can get historical state at timecheck1. retrieved_example = event_player.replay_events(registered_example.id, until=timecheck1) self.assertEqual(retrieved_example.a, 123) # Check we can get historical state at timecheck2. retrieved_example = event_player.replay_events(registered_example.id, until=timecheck2) self.assertEqual(retrieved_example.a, 999) # Check we can get historical state at timecheck3. retrieved_example = event_player.replay_events(registered_example.id, until=timecheck3) self.assertEqual(retrieved_example.a, 9999) # Similarly, check we can get historical state using a snapshot retrieved_example = event_player.replay_events(registered_example.id, initial_state=initial_state, after=after, until=timecheck2) self.assertEqual(retrieved_example.a, 999)
def test_entity_lifecycle(self): # Check the factory creates an instance. example1 = register_new_example(a=1, b=2) self.assertIsInstance(example1, Example) # Check the properties of the Example class. self.assertEqual(1, example1.a) self.assertEqual(2, example1.b) # Check the properties of the EventSourcedEntity class. self.assertTrue(example1.id) self.assertEqual(1, example1.version) self.assertTrue(example1.created_on) # Check a second instance with the same values is not "equal" to the first. example2 = register_new_example(a=1, b=2) self.assertNotEqual(example1, example2) # Setup the repo. repo = ExampleRepo(self.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(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 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. self.assertRaises( EntityIDConsistencyError, entity2._validate_originator, DomainEvent(entity_id=entity2.id + 'wrong', entity_version=0)) # Should fail to validate event with wrong entity version. self.assertRaises(EntityVersionConsistencyError, entity2._validate_originator, DomainEvent(entity_id=entity2.id, entity_version=0)) # Should validate event with correct entity ID and version. entity2._validate_originator( DomainEvent(entity_id=entity2.id, entity_version=entity2.version)) # Check an entity can be reregistered with the same ID. replacement_event = Example.Created(entity_id=entity1.id, a=11, b=12) # replacement = Example.mutate(event=replacement_event) publish(event=replacement_event) # Check the replacement entity can be retrieved from the example repository. replacement = repo[entity1.id] assert isinstance(replacement, Example) self.assertEqual(replacement.a, 11) self.assertEqual(replacement.b, 12)
def test_entity_lifecycle(self): # Check the factory creates an instance. example1 = register_new_example(a=1, b=2) self.assertIsInstance(example1, Example) # Check the properties of the Example class. self.assertEqual(1, example1.a) self.assertEqual(2, example1.b) # Check the properties of the EventSourcedEntity class. self.assertTrue(example1.id) self.assertEqual(1, example1.version) self.assertTrue(example1.created_on) # Check a second instance with the same values is not "equal" to the first. example2 = register_new_example(a=1, b=2) self.assertNotEqual(example1, example2) # Setup the repo. repo = ExampleRepo(self.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(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 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. self.assertRaises(EntityIDConsistencyError, entity2._validate_originator, DomainEvent(entity_id=entity2.id+'wrong', entity_version=0) ) # Should fail to validate event with wrong entity version. self.assertRaises(EntityVersionConsistencyError, entity2._validate_originator, DomainEvent(entity_id=entity2.id, entity_version=0) ) # Should validate event with correct entity ID and version. entity2._validate_originator( DomainEvent(entity_id=entity2.id, entity_version=entity2.version) ) # Check an entity can be reregistered with the same ID. replacement_event = Example.Created(entity_id=entity1.id, a=11, b=12) # replacement = Example.mutate(event=replacement_event) publish(event=replacement_event) # Check the replacement entity can be retrieved from the example repository. replacement = repo[entity1.id] assert isinstance(replacement, Example) self.assertEqual(replacement.a, 11) self.assertEqual(replacement.b, 12)