public void SaveEvents_fails_if_events_not_have_same_source_id() { // Arrange var userId = Guid.NewGuid(); var created = new FakeUserCreated { SourceId = userId, Version = 1, RaisedAt = DateTime.UtcNow, }; var usernameChanged = new FakeUsernameChanged { SourceId = Guid.NewGuid(), Version = 2, RaisedAt = DateTime.UtcNow, }; var sut = new SqlEventStore( () => new FakeEventStoreDbContext(_dbContextOptions), new JsonMessageSerializer()); // Act Func <Task> action = () => sut.SaveEvents <FakeUser>(new DomainEvent[] { created, usernameChanged }); // Assert action.ShouldThrow <ArgumentException>().Where(x => x.ParamName == "events"); }
public async Task SaveEvents_inserts_Aggregate_correctly_for_new_aggregate_id() { // Arrange var userId = Guid.NewGuid(); var created = new FakeUserCreated(); var events = new DomainEvent[] { created }; events.Raise(userId); var sut = new SqlEventStore( () => new FakeEventStoreDbContext(_dbContextOptions), new JsonMessageSerializer()); // Act await sut.SaveEvents <FakeUser>(events); // Assert using (var db = new FakeEventStoreDbContext(_dbContextOptions)) { Aggregate actual = await db .Aggregates .Where(a => a.AggregateId == userId) .SingleOrDefaultAsync(); actual.Should().NotBeNull(); actual.AggregateType.Should().Be(typeof(FakeUser).FullName); actual.Version.Should().Be(created.Version); } }
public async Task PublishPendingEvents_deletes_pending_events( FakeUserCreated created, FakeUsernameChanged usernameChanged) { // Arrange var sourceId = Guid.NewGuid(); var events = new DomainEvent[] { created, usernameChanged }; RaiseEvents(sourceId, events); using (var db = new DataContext()) { foreach (DomainEvent e in events) { var envelope = new Envelope(e); db.PendingEvents.Add(PendingEvent.FromEnvelope(envelope, serializer)); } await db.SaveChangesAsync(); } // Act await sut.PublishPendingEvents(sourceId, CancellationToken.None); // Assert using (var db = new DataContext()) { bool actual = await db .PendingEvents .Where(e => e.AggregateId == sourceId) .AnyAsync(); actual.Should().BeFalse(); } }
public async Task SaveEvents_sets_message_properties_correctly( FakeUserCreated created, FakeUsernameChanged usernameChanged, Guid correlationId) { // Arrange var events = new DomainEvent[] { created, usernameChanged }; RaiseEvents(userId, events); // Act await sut.SaveEvents <FakeUser>(events, correlationId); // Asseert using (var db = new DataContext()) { IEnumerable <object> expected = db .PendingEvents .Where(e => e.AggregateId == userId) .OrderBy(e => e.Version) .AsEnumerable() .Select(e => new { e.MessageId, e.CorrelationId }) .ToList(); IEnumerable <object> actual = db .PersistentEvents .Where(e => e.AggregateId == userId) .OrderBy(e => e.Version) .AsEnumerable() .Select(e => new { e.MessageId, e.CorrelationId }) .ToList(); actual.ShouldAllBeEquivalentTo(expected); } }
public async Task SaveEvents_removes_existing_UniqueIndexedProperty_if_property_value_is_null( FakeUserCreated created, FakeUsernameChanged usernameChanged) { // Arrange RaiseEvents(userId, created); await sut.SaveEvents <FakeUser>(new[] { created }); usernameChanged.Username = null; RaiseEvents(userId, 1, usernameChanged); // Act await sut.SaveEvents <FakeUser>(new[] { usernameChanged }); // Assert using (var db = new DataContext()) { UniqueIndexedProperty actual = await db .UniqueIndexedProperties .Where( p => p.AggregateType == typeof(FakeUser).FullName && p.PropertyName == nameof(FakeUserCreated.Username) && p.PropertyValue == created.Username) .SingleOrDefaultAsync(); actual.Should().BeNull(); } }
public async Task SaveEvents_inserts_UniqueIndexedProperty_for_new_property( FakeUserCreated created) { var events = new DomainEvent[] { created }; RaiseEvents(userId, events); await sut.SaveEvents <FakeUser>(events); using (var db = new DataContext()) { UniqueIndexedProperty actual = await db .UniqueIndexedProperties .Where( p => p.AggregateType == typeof(FakeUser).FullName && p.PropertyName == nameof(FakeUserCreated.Username) && p.PropertyValue == created.Username) .SingleOrDefaultAsync(); actual.Should().NotBeNull(); actual.AggregateId.Should().Be(userId); actual.Version.Should().Be(created.Version); } }
public async Task SaveEvents_fails_if_unique_indexed_property_duplicate( Guid macId, Guid toshId, string duplicateUserName) { // Arrange var macCreated = new FakeUserCreated { Username = duplicateUserName }; RaiseEvents(macId, macCreated); await sut.SaveEvents <FakeUser>(new[] { macCreated }); // Act var toshCreated = new FakeUserCreated { Username = duplicateUserName }; RaiseEvents(toshId, toshCreated); Func <Task> action = () => sut.SaveEvents <FakeUser>(new[] { toshCreated }); // Assert action.ShouldThrow <Exception>(); using (var db = new DataContext()) { IQueryable <PersistentEvent> query = from e in db.PersistentEvents where e.AggregateId == toshId select e; (await query.AnyAsync()).Should().BeFalse(); } }
public async Task SaveEvents_updates_existing_UniqueIndexedProperty_correctly( FakeUserCreated created, FakeUsernameChanged usernameChanged) { // Arrange RaiseEvents(userId, created); await sut.SaveEvents <FakeUser>(new[] { created }); RaiseEvents(userId, 1, usernameChanged); // Act await sut.SaveEvents <FakeUser>(new[] { usernameChanged }); // Assert using (var db = new DataContext()) { UniqueIndexedProperty actual = await db .UniqueIndexedProperties .Where( p => p.AggregateId == userId && p.PropertyName == nameof(FakeUserCreated.Username)) .SingleOrDefaultAsync(); actual.Should().NotBeNull(); actual.PropertyValue.Should().Be(usernameChanged.Username); actual.Version.Should().Be(usernameChanged.Version); } }
public async Task PublishPendingEvents_commits_once( FakeUserCreated created, FakeUsernameChanged usernameChanged) { // Arrange var sourceId = Guid.NewGuid(); var events = new DomainEvent[] { created, usernameChanged }; RaiseEvents(sourceId, events); Mock.Get(mockDbContext.PendingEvents) .SetupData(events .Select(e => new Envelope(e)) .Select(e => PendingEvent.FromEnvelope(e, serializer)) .ToList()); var sut = new SqlEventPublisher( () => mockDbContext, serializer, messageBus); // Act await sut.PublishPendingEvents(sourceId, CancellationToken.None); // Assert Mock.Get(mockDbContext).Verify( x => x.SaveChangesAsync(CancellationToken.None), Times.Once()); }
public async Task SaveEvents_throws_DuplicateCorrelationException_if_correlation_duplicate() { // Arrange var userId = Guid.NewGuid(); var created = new FakeUserCreated(); var usernameChanged = new FakeUsernameChanged(); new DomainEvent[] { created, usernameChanged }.Raise(userId); var sut = new SqlEventStore( () => new FakeEventStoreDbContext(_dbContextOptions), new JsonMessageSerializer()); var correlationId = Guid.NewGuid(); await sut.SaveEvents <FakeUser>(new[] { created }, correlationId : correlationId); // Act Func <Task> action = () => sut.SaveEvents <FakeUser>(new[] { usernameChanged }, correlationId: correlationId); // Assert action.ShouldThrow <DuplicateCorrelationException>().Where( x => x.SourceType == typeof(FakeUser) && x.SourceId == userId && x.CorrelationId == correlationId && x.InnerException is DbUpdateException); }
public async Task SaveEvents_inserts_Correlation_entity_correctly() { // Arrange var userId = Guid.NewGuid(); var created = new FakeUserCreated(); var correlationId = Guid.NewGuid(); created.Raise(userId); DateTime now = DateTime.UtcNow; var sut = new SqlEventStore( () => new FakeEventStoreDbContext(_dbContextOptions), new JsonMessageSerializer()); // Act await sut.SaveEvents <FakeUser>(new[] { created }, correlationId : correlationId); // Assert using (var db = new FakeEventStoreDbContext(_dbContextOptions)) { Correlation correlation = await db .Correlations .Where( c => c.AggregateType == typeof(FakeUser).FullName && c.AggregateId == userId && c.CorrelationId == correlationId) .SingleOrDefaultAsync(); correlation.Should().NotBeNull(); correlation.HandledAt.Should().BeCloseTo(now, precision: 100); } }
public async Task SaveEvents_does_not_insert_UniqueIndexedProperty_if_property_value_is_null() { // Arrange var userId = Guid.NewGuid(); var created = new FakeUserCreated { Username = null }; created.Raise(userId); var sut = new SqlEventStore( () => new FakeEventStoreDbContext(_dbContextOptions), new JsonMessageSerializer()); // Act await sut.SaveEvents <FakeUser>(new DomainEvent[] { created }); // Assert using (var db = new FakeEventStoreDbContext(_dbContextOptions)) { UniqueIndexedProperty actual = await db .UniqueIndexedProperties .Where( p => p.AggregateType == typeof(FakeUser).FullName && p.PropertyName == nameof(FakeUserCreated.Username) && p.PropertyValue == created.Username) .SingleOrDefaultAsync(); actual.Should().BeNull(); } }
public async Task SaveEvents_inserts_UniqueIndexedProperty_with_value_of_latest_indexed_event() { // Arrange var userId = Guid.NewGuid(); var created = new FakeUserCreated(); var usernameChanged = new FakeUsernameChanged(); var events = new DomainEvent[] { created, usernameChanged }; events.Raise(userId); var sut = new SqlEventStore( () => new FakeEventStoreDbContext(_dbContextOptions), new JsonMessageSerializer()); // Act await sut.SaveEvents <FakeUser>(events); // Assert using (var db = new FakeEventStoreDbContext(_dbContextOptions)) { UniqueIndexedProperty actual = await db .UniqueIndexedProperties .Where( p => p.AggregateId == userId && p.PropertyName == nameof(FakeUserCreated.Username)) .SingleOrDefaultAsync(); actual.PropertyValue.Should().Be(usernameChanged.Username); actual.Version.Should().Be(usernameChanged.Version); } }
public async Task SaveEvents_does_not_insert_UniqueIndexedProperty_if_property_value_is_null() { var created = new FakeUserCreated { Username = null }; var events = new DomainEvent[] { created }; RaiseEvents(userId, events); await sut.SaveEvents <FakeUser>(events); using (var db = new DataContext()) { UniqueIndexedProperty actual = await db .UniqueIndexedProperties .Where( p => p.AggregateType == typeof(FakeUser).FullName && p.PropertyName == nameof(FakeUserCreated.Username) && p.PropertyValue == created.Username) .SingleOrDefaultAsync(); actual.Should().BeNull(); } }
public void FromEnvelope_sets_MessageId_correctly() { FakeUserCreated domainEvent = _fixture.Create <FakeUserCreated>(); var envelope = new Envelope(domainEvent); var actual = PendingEvent.FromEnvelope(envelope, _serializer); actual.MessageId.Should().Be(envelope.MessageId); }
public void FromEnvelope_sets_Contributor_correctly() { FakeUserCreated domainEvent = _fixture.Create <FakeUserCreated>(); string contributor = _fixture.Create <string>(); var envelope = new Envelope(Guid.NewGuid(), domainEvent, contributor: contributor); var actual = PendingEvent.FromEnvelope(envelope, _serializer); actual.Contributor.Should().Be(contributor); }
public void FromEnvelope_sets_CorrelationId_correctly() { FakeUserCreated domainEvent = _fixture.Create <FakeUserCreated>(); var correlationId = Guid.NewGuid(); var envelope = new Envelope(Guid.NewGuid(), domainEvent, correlationId: correlationId); var actual = PendingEvent.FromEnvelope(envelope, _serializer); actual.CorrelationId.Should().Be(correlationId); }
public void FromEnvelope_sets_OperationId_correctly() { FakeUserCreated domainEvent = _fixture.Create <FakeUserCreated>(); string operationId = $"{Guid.NewGuid()}"; var envelope = new Envelope(Guid.NewGuid(), domainEvent, operationId); var actual = PendingEvent.FromEnvelope(envelope, _serializer); actual.OperationId.Should().Be(operationId); }
public async Task SaveEvents_saves_pending_events_correctly() { // Arrange var userId = Guid.NewGuid(); var created = new FakeUserCreated(); var usernameChanged = new FakeUsernameChanged(); var events = new DomainEvent[] { created, usernameChanged }; events.Raise(userId); var serializer = new JsonMessageSerializer(); var sut = new SqlEventStore( () => new FakeEventStoreDbContext(_dbContextOptions), serializer); string operationId = Guid.NewGuid().ToString(); var correlationId = Guid.NewGuid(); string contributor = Guid.NewGuid().ToString(); // Act await sut.SaveEvents <FakeUser>(events, operationId, correlationId, contributor); // Asseert using (var db = new FakeEventStoreDbContext(_dbContextOptions)) { var pendingEvents = db .PendingEvents .Where(e => e.AggregateId == userId) .OrderBy(e => e.Version) .ToList(); foreach (var t in pendingEvents.Zip(events, (pending, source) => new { Pending = pending, Source = source })) { var actual = new { t.Pending.Version, t.Pending.CorrelationId, t.Pending.Contributor, Message = serializer.Deserialize(t.Pending.EventJson), }; actual.ShouldBeEquivalentTo(new { t.Source.Version, OperationId = operationId, CorrelationId = correlationId, Contributor = contributor, Message = t.Source, }, opts => opts.RespectingRuntimeTypes()); } } }
public async Task FindIdByUniqueIndexedProperty_returns_aggregate_id_if_property_found( FakeUserCreated created) { RaiseEvents(userId, created); await sut.SaveEvents <FakeUser>(new[] { created }); Guid?actual = await sut.FindIdByUniqueIndexedProperty <FakeUser>("Username", created.Username); actual.Should().Be(userId); }
public void SaveEvents_fails_if_events_contains_null( FakeUserCreated created) { var events = new DomainEvent[] { created, null }; RaiseEvents(userId, created); Func <Task> action = () => sut.SaveEvents <FakeUser>(events); action.ShouldThrow <ArgumentException>() .Where(x => x.ParamName == "events"); }
public void FromEnvelope_sets_EventJson_correctly() { FakeUserCreated domainEvent = _fixture.Create <FakeUserCreated>(); var envelope = new Envelope(domainEvent); var actual = PendingEvent.FromEnvelope(envelope, _serializer); object message = _serializer.Deserialize(actual.EventJson); message.Should().BeOfType <FakeUserCreated>(); message.ShouldBeEquivalentTo(domainEvent); }
public async Task FlushPendingEvents_sends_events_correctly() { // Arrange FakeUserCreated created = _fixture.Create <FakeUserCreated>(); FakeUsernameChanged usernameChanged = _fixture.Create <FakeUsernameChanged>(); var sourceId = Guid.NewGuid(); string operationId = _fixture.Create <string>(); var correlationId = Guid.NewGuid(); string contributor = _fixture.Create <string>(); var domainEvents = new DomainEvent[] { created, usernameChanged }; RaiseEvents(sourceId, domainEvents); var envelopes = new List <Envelope>(); using (var db = new DataContext()) { foreach (DomainEvent domainEvent in domainEvents) { var envelope = new Envelope(Guid.NewGuid(), domainEvent, operationId, correlationId, contributor); envelopes.Add(envelope); db.PendingEvents.Add(PendingEvent.FromEnvelope(envelope, _serializer)); } await db.SaveChangesAsync(); } List <Envelope> batch = null; Mock.Get(_messageBus) .Setup( x => x.Send( It.IsAny <IEnumerable <Envelope> >(), It.IsAny <CancellationToken>())) .Callback <IEnumerable <Envelope>, CancellationToken>((b, t) => batch = b.ToList()) .Returns(Task.FromResult(true)); // Act await _sut.FlushPendingEvents(sourceId, CancellationToken.None); // Assert Mock.Get(_messageBus).Verify( x => x.Send( It.IsAny <IEnumerable <Envelope> >(), CancellationToken.None), Times.Once()); batch.ShouldAllBeEquivalentTo(envelopes, opts => opts.RespectingRuntimeTypes()); }
public async Task SaveEvents_saves_events_correctly() { // Arrange var userId = Guid.NewGuid(); var created = new FakeUserCreated(); var usernameChanged = new FakeUsernameChanged(); var events = new DomainEvent[] { created, usernameChanged }; events.Raise(userId); var serializer = new JsonMessageSerializer(); var sut = new SqlEventStore( () => new FakeEventStoreDbContext(_dbContextOptions), serializer); // Act await sut.SaveEvents <FakeUser>(events); // Asseert using (var db = new FakeEventStoreDbContext(_dbContextOptions)) { IEnumerable <object> actual = db .PersistentEvents .Where(e => e.AggregateId == userId) .OrderBy(e => e.Version) .AsEnumerable() .Select(e => new { e.AggregateType, e.Version, e.EventType, Payload = serializer.Deserialize(e.EventJson), }) .ToList(); actual.Should().HaveCount(events.Length); IEnumerable <object> expected = events.Select(e => new { AggregateType = typeof(FakeUser).FullName, e.Version, EventType = e.GetType().FullName, Payload = e, }); actual.ShouldAllBeEquivalentTo(expected); } }
public async Task SaveEvents_saves_events_correctly() { // Arrange FakeUserCreated created = _fixture.Create <FakeUserCreated>(); FakeUsernameChanged usernameChanged = _fixture.Create <FakeUsernameChanged>(); var events = new DomainEvent[] { created, usernameChanged }; RaiseEvents(_userId, events); string operationId = _fixture.Create <string>(); var correlationId = Guid.NewGuid(); string contributor = _fixture.Create <string>(); // Act await _sut.SaveEvents <FakeUser>(events, operationId, correlationId, contributor); // Asseert using (var db = new DataContext()) { IEnumerable <object> actual = db .PersistentEvents .Where(e => e.AggregateId == _userId) .OrderBy(e => e.Version) .AsEnumerable() .Select(e => new { e.Version, e.EventType, e.OperationId, e.CorrelationId, e.Contributor, Payload = _serializer.Deserialize(e.EventJson), }) .ToList(); actual.Should().HaveCount(events.Length); IEnumerable <object> expected = events.Select(e => new { e.Version, EventType = e.GetType().FullName, OperationId = operationId, CorrelationId = correlationId, Contributor = contributor, Payload = e, }); actual.ShouldAllBeEquivalentTo(expected); } }
public async Task FindIdByUniqueIndexedProperty_returns_aggregate_id_if_property_found() { var userId = Guid.NewGuid(); var created = new FakeUserCreated(); created.Raise(userId); var sut = new SqlEventStore( () => new FakeEventStoreDbContext(_dbContextOptions), new JsonMessageSerializer()); await sut.SaveEvents <FakeUser>(new[] { created }); Guid?actual = await sut.FindIdByUniqueIndexedProperty <FakeUser>("Username", created.Username); actual.Should().Be(userId); }
public static FakeUser CreateNew(Guid userGuid, IEventStore eventStore, IEventBus eventBus, IDateTimeProvider dateTimeProvider, DateTime createdDate, string username) { // Instantiate the new FakeUser FakeUser fakeUser = new FakeUser(userGuid, eventStore, eventBus, dateTimeProvider); // Create the event FakeUserCreated @event = new FakeUserCreated(createdDate, userGuid, username); // Apply the event fakeUser.Apply(@event, true); // Save the events and publish them fakeUser.SaveAndPublishEvents(); return(fakeUser); }
public async Task LoadEvents_restores_all_events_correctly( FakeUserCreated created, FakeUsernameChanged usernameChanged) { // Arrange var events = new DomainEvent[] { created, usernameChanged }; RaiseEvents(userId, events); await sut.SaveEvents <FakeUser>(events); // Act IEnumerable <IDomainEvent> actual = await sut.LoadEvents <FakeUser>(userId); // Assert actual.ShouldAllBeEquivalentTo(events); }
public async Task SaveEvents_commits_once( FakeUserCreated created, FakeUsernameChanged usernameChanged) { var events = new DomainEvent[] { created, usernameChanged }; RaiseEvents(userId, events); var sut = new SqlEventStore( () => mockDbContext, new JsonMessageSerializer()); await sut.SaveEvents <FakeUser>(events); Mock.Get(mockDbContext).Verify( x => x.SaveChangesAsync(CancellationToken.None), Times.Once()); }
public async Task PublishPendingEvents_sends_events( FakeUserCreated created, FakeUsernameChanged usernameChanged) { // Arrange var sourceId = Guid.NewGuid(); var events = new DomainEvent[] { created, usernameChanged }; RaiseEvents(sourceId, events); var envelopes = new List <Envelope>(); using (var db = new DataContext()) { foreach (DomainEvent e in events) { var envelope = new Envelope(e); envelopes.Add(envelope); db.PendingEvents.Add(PendingEvent.FromEnvelope(envelope, serializer)); } await db.SaveChangesAsync(); } List <Envelope> batch = null; Mock.Get(messageBus) .Setup( x => x.SendBatch( It.IsAny <IEnumerable <Envelope> >(), It.IsAny <CancellationToken>())) .Callback <IEnumerable <Envelope>, CancellationToken>((b, t) => batch = b.ToList()) .Returns(Task.FromResult(true)); // Act await sut.PublishPendingEvents(sourceId, CancellationToken.None); // Assert Mock.Get(messageBus).Verify( x => x.SendBatch( It.IsAny <IEnumerable <Envelope> >(), CancellationToken.None), Times.Once()); batch.ShouldAllBeEquivalentTo(envelopes, opts => opts.RespectingRuntimeTypes()); }