def test(self): # Define fixture that receives prompts. class FollowerFixture(RecordingEventReceiver): def __init__(self): self.num_received = 0 def receive_recording_event( self, recording_event: RecordingEvent) -> None: self.num_received += 1 # Test fixture is working. follower = FollowerFixture() follower.receive_recording_event(RecordingEvent("Leader", [], 1)) self.assertEqual(follower.num_received, 1) # Construct leader. leader = Leader() leader.lead(follower) # Check follower receives a prompt when there are new events. leader.save(Aggregate()) self.assertEqual(follower.num_received, 2) # Check follower doesn't receive prompt when no new events. leader.save() self.assertEqual(follower.num_received, 2) # Check follower doesn't receive prompt when recordings are filtered out. leader.notify_topics = ["topic1"] leader.save(Aggregate()) self.assertEqual(follower.num_received, 2)
def test_trigger_event(self): a = Aggregate() # Check the aggregate can trigger further events. a.trigger_event(AggregateEvent) self.assertLess(a.created_on, a.modified_on) pending = a.collect_events() self.assertEqual(len(pending), 2) self.assertIsInstance(pending[0], AggregateCreated) self.assertEqual(pending[0].originator_version, 1) self.assertIsInstance(pending[1], AggregateEvent) self.assertEqual(pending[1].originator_version, 2)
def test_call_base_class(self): before_created = datetime.now(tz=TZINFO) a = Aggregate() after_created = datetime.now(tz=TZINFO) self.assertIsInstance(a, Aggregate) self.assertIsInstance(a.id, UUID) self.assertIsInstance(a.version, int) self.assertEqual(a.version, 1) self.assertIsInstance(a.created_on, datetime) self.assertIsInstance(a.modified_on, datetime) self.assertEqual(a.created_on, a.modified_on) self.assertGreater(a.created_on, before_created) self.assertGreater(after_created, a.created_on) events = a.collect_events() self.assertIsInstance(events[0], AggregateCreated) self.assertEqual("Aggregate.Created", type(events[0]).__qualname__)
def test_repr_baseclass(self): a = Aggregate() expect = (f"Aggregate(id={a.id!r}, " "version=1, " f"created_on={a.created_on!r}, " f"modified_on={a.modified_on!r}" ")") self.assertEqual(expect, repr(a)) a.trigger_event(AggregateEvent) expect = (f"Aggregate(id={a.id!r}, " "version=2, " f"created_on={a.created_on!r}, " f"modified_on={a.modified_on!r}" ")") self.assertEqual(expect, repr(a))
def test_contains(self): transcoder = JSONTranscoder() transcoder.register(UUIDAsHex()) transcoder.register(DecimalAsStr()) transcoder.register(DatetimeAsISO()) event_recorder = POPOAggregateRecorder() event_store = EventStore( mapper=Mapper(transcoder=transcoder), recorder=event_recorder, ) aggregate = Aggregate() event_store.put(aggregate.collect_events()) repository = Repository(event_store) self.assertTrue(aggregate.id in repository) self.assertFalse(uuid4() in repository)
def test_save_returns_recording_event(self): app = Application() recordings = app.save() self.assertEqual(recordings, []) recordings = app.save(None) self.assertEqual(recordings, []) recordings = app.save(Aggregate()) self.assertEqual(len(recordings), 1) self.assertEqual(recordings[0].notification.id, 1) recordings = app.save(Aggregate()) self.assertEqual(len(recordings), 1) self.assertEqual(recordings[0].notification.id, 2) recordings = app.save(Aggregate(), Aggregate()) self.assertEqual(len(recordings), 2) self.assertEqual(recordings[0].notification.id, 3) self.assertEqual(recordings[1].notification.id, 4)
def test_event_mutate_raises_version_error(self): a = Aggregate() # Try to mutate aggregate with an invalid domain event. event = AggregateEvent( originator_id=a.id, originator_version=a.version, # NB not +1. timestamp=datetime.now(tz=TZINFO), ) # Check raises "VersionError". with self.assertRaises(VersionError): event.mutate(a)
def test_event_mutate_raises_originator_id_error(self): a = Aggregate() # Try to mutate aggregate with an invalid domain event. event = AggregateEvent( originator_id=uuid4(), originator_version=a.version + 1, timestamp=AggregateEvent.create_timestamp(), ) # Check raises "VersionError". with self.assertRaises(OriginatorIDError): event.mutate(a)
def test_cache_raises_aggregate_not_found_when_projector_func_returns_none( self): transcoder = JSONTranscoder() transcoder.register(UUIDAsHex()) transcoder.register(DecimalAsStr()) transcoder.register(DatetimeAsISO()) transcoder.register(EmailAddressAsStr()) event_recorder = SQLiteAggregateRecorder(SQLiteDatastore(":memory:")) event_recorder.create_table() event_store = EventStore( mapper=Mapper(transcoder=transcoder), recorder=event_recorder, ) repository = Repository( event_store, cache_maxsize=2, ) aggregate = Aggregate() event_store.put(aggregate.collect_events()) self.assertEqual(1, repository.get(aggregate.id).version) aggregate.trigger_event(Aggregate.Event) event_store.put(aggregate.collect_events()) with self.assertRaises(AggregateNotFound): repository.get(aggregate.id, projector_func=lambda _, __: None)
def test_cache_fastforward_false(self): transcoder = JSONTranscoder() transcoder.register(UUIDAsHex()) transcoder.register(DecimalAsStr()) transcoder.register(DatetimeAsISO()) transcoder.register(EmailAddressAsStr()) event_recorder = SQLiteAggregateRecorder(SQLiteDatastore(":memory:")) event_recorder.create_table() event_store = EventStore( mapper=Mapper(transcoder=transcoder), recorder=event_recorder, ) repository = Repository( event_store, cache_maxsize=2, fastforward=False, ) aggregate = Aggregate() event_store.put(aggregate.collect_events()) self.assertEqual(1, repository.get(aggregate.id).version) aggregate.trigger_event(Aggregate.Event) event_store.put(aggregate.collect_events()) self.assertEqual(1, repository.get(aggregate.id).version)
def test_call_class_method_create(self): # Check the _create() method creates a new aggregate. before_created = datetime.now(tz=TZINFO) uuid = uuid4() a = Aggregate._create( event_class=AggregateCreated, id=uuid, ) after_created = datetime.now(tz=TZINFO) self.assertIsInstance(a, Aggregate) self.assertEqual(a.id, uuid) self.assertEqual(a.version, 1) self.assertEqual(a.created_on, a.modified_on) self.assertGreater(a.created_on, before_created) self.assertGreater(after_created, a.created_on)
def test(self): app = BankAccountsWithAutomaticSnapshotting() # Check snapshotting is enabled by setting snapshotting_intervals only. self.assertTrue(app.snapshots) # Open an account. account_id = app.open_account("Alice", "*****@*****.**") # Check there are no snapshots. snapshots = list(app.snapshots.get(account_id)) self.assertEqual(len(snapshots), 0) # Trigger twelve more events. for _ in range(12): app.credit_account(account_id, Decimal("10.00")) # Check the account is at version 13. account = app.get_account(account_id) self.assertEqual(account.version, 13) # Check snapshots have been taken at regular intervals. snapshots = list(app.snapshots.get(account_id)) self.assertEqual(len(snapshots), 2) self.assertEqual(snapshots[0].originator_version, 5) self.assertEqual(snapshots[1].originator_version, 10) # Check another type of aggregate is not snapshotted. aggregate = Aggregate() for _ in range(10): aggregate.trigger_event(Aggregate.Event) app.save(aggregate) # Check snapshots have not been taken at regular intervals. snapshots = list(app.snapshots.get(aggregate.id)) self.assertEqual(len(snapshots), 0)
def test_application_with_cached_aggregates(self): app = Application(env={"AGGREGATE_CACHE_MAXSIZE": "10"}) aggregate = Aggregate() app.save(aggregate) self.assertEqual(aggregate, app.repository.cache.get(aggregate.id))
def create_aggregate(self) -> UUID: aggregate = Aggregate() logged_id = self.aggregate_log.trigger_event( aggregate_id=aggregate.id) self.save(aggregate, logged_id) return aggregate.id
def test_cache_maxsize_nonzero(self): transcoder = JSONTranscoder() transcoder.register(UUIDAsHex()) transcoder.register(DecimalAsStr()) transcoder.register(DatetimeAsISO()) transcoder.register(EmailAddressAsStr()) event_recorder = SQLiteAggregateRecorder(SQLiteDatastore(":memory:")) event_recorder.create_table() event_store = EventStore( mapper=Mapper(transcoder=transcoder), recorder=event_recorder, ) repository = Repository(event_store, cache_maxsize=2) self.assertEqual(type(repository.cache), LRUCache) aggregate1 = Aggregate() self.assertFalse(aggregate1.id in repository) event_store.put(aggregate1.collect_events()) self.assertTrue(aggregate1.id in repository) aggregate2 = Aggregate() self.assertFalse(aggregate2.id in repository) event_store.put(aggregate2.collect_events()) self.assertTrue(aggregate2.id in repository) aggregate3 = Aggregate() self.assertFalse(aggregate3.id in repository) event_store.put(aggregate3.collect_events()) self.assertTrue(aggregate3.id in repository) self.assertFalse(aggregate1.id in repository.cache.cache) self.assertEqual(1, repository.get(aggregate1.id).version) self.assertEqual(1, repository.get(aggregate2.id).version) self.assertEqual(1, repository.get(aggregate3.id).version) aggregate1.trigger_event(Aggregate.Event) event_store.put(aggregate1.collect_events()) self.assertEqual(2, repository.get(aggregate1.id).version)