public void GetRowKey_returns_prefixed_formatted_version() { int version = new Fixture().Create <int>(); string actual = PendingEvent.GetRowKey(version); actual.Should().Be($"Pending-{version:D10}"); }
public async Task FlushPendingEvents_sends_all_pending_events_correctly() { // Arrange var messageBus = new MessageLogger(); var sut = new AzureEventPublisher(s_eventTable, s_serializer, messageBus); var fixture = new Fixture(); var user = new FakeUser(Guid.NewGuid(), fixture.Create <string>()); user.ChangeUsername(fixture.Create <string>()); string operationId = fixture.Create <string>(); var correlationId = Guid.NewGuid(); string contributor = fixture.Create <string>(); var envelopes = new List <Envelope <IDomainEvent> >( from domainEvent in user.FlushPendingEvents() let messageId = Guid.NewGuid() select new Envelope <IDomainEvent>(messageId, domainEvent, operationId, correlationId, contributor)); var batch = new TableBatchOperation(); foreach (Envelope <IDomainEvent> envelope in envelopes) { batch.Insert(PendingEvent.Create(typeof(FakeUser), envelope, s_serializer)); } await s_eventTable.ExecuteBatchAsync(batch); // Act await sut.FlushPendingEvents <FakeUser>(user.Id); // Assert messageBus.Log.ShouldAllBeEquivalentTo(envelopes); }
public async Task SaveEvents_does_not_insert_pending_event_entities_if_fails_to_insert_correlation_entities() { // Arrange var fixture = new Fixture(); var user = new FakeUser(Guid.NewGuid(), fixture.Create <string>()); user.ChangeUsername(fixture.Create <string>()); IList <IDomainEvent> domainEvents = user.FlushPendingEvents().ToList(); var correlationId = Guid.NewGuid(); var batch = new TableBatchOperation(); batch.Insert(new TableEntity { PartitionKey = AggregateEntity.GetPartitionKey(typeof(FakeUser), user.Id), RowKey = Correlation.GetRowKey(correlationId), }); await s_eventTable.ExecuteBatchAsync(batch); // Act Func <Task> action = () => _sut.SaveEvents <FakeUser>(domainEvents, correlationId: correlationId); // Assert action.ShouldThrow <DuplicateCorrelationException>(); string filter = PendingEvent.GetFilter(typeof(FakeUser), user.Id); var query = new TableQuery <PendingEvent> { FilterString = filter }; IEnumerable <PendingEvent> actual = await s_eventTable.ExecuteQuerySegmentedAsync(query, default); actual.Should().BeEmpty(); }
private async Task <List <PendingEvent> > GetPendingEvents(string partition, CancellationToken cancellationToken) { string filter = PendingEvent.GetFilter(partition); var query = new TableQuery <PendingEvent> { FilterString = filter }; return(new List <PendingEvent>(await _eventTable .ExecuteQuery(query, cancellationToken) .ConfigureAwait(false))); }
public void Create_returns_PersistentEvent_instance() { IFixture fixture = new Fixture(); fixture.Register <IDomainEvent>(() => fixture.Create <SomeDomainEvent>()); var actual = PendingEvent.Create( fixture.Create <Type>(), fixture.Create <Envelope <IDomainEvent> >(), new JsonMessageSerializer()); actual.Should().NotBeNull(); }
private async Task Save <T>( List <IDomainEvent> domainEvents, string operationId, Guid?correlationId, string contributor, CancellationToken cancellationToken) where T : class, IEventSourced { var envelopes = new List <Envelope <IDomainEvent> >( from domainEvent in domainEvents let messageId = Guid.NewGuid() select new Envelope <IDomainEvent>(messageId, domainEvent, operationId, correlationId, contributor)); var batch = new TableBatchOperation(); foreach (Envelope <IDomainEvent> envelope in envelopes) { batch.Insert(PersistentEvent.Create(typeof(T), envelope, _serializer)); batch.Insert(PendingEvent.Create(typeof(T), envelope, _serializer)); } Guid sourceId = domainEvents.First().SourceId; if (correlationId.HasValue) { batch.Insert(Correlation.Create(typeof(T), sourceId, correlationId.Value)); } try { await _eventTable.ExecuteBatch(batch, cancellationToken).ConfigureAwait(false); } catch (StorageException exception) when(correlationId.HasValue) { string filter = Correlation.GetFilter(typeof(T), sourceId, correlationId.Value); var query = new TableQuery <Correlation> { FilterString = filter }; if (await _eventTable.Any(query, cancellationToken).ConfigureAwait(false)) { throw new DuplicateCorrelationException( typeof(T), sourceId, correlationId.Value, exception); } throw; } }
public void Create_sets_RowKey_correctly() { IFixture fixture = new Fixture(); SomeDomainEvent domainEvent = fixture.Create <SomeDomainEvent>(); TestContext.WriteLine($"Version: {domainEvent.Version}"); fixture.Inject <IDomainEvent>(domainEvent); var actual = PendingEvent.Create( fixture.Create <Type>(), fixture.Create <Envelope <IDomainEvent> >(), new JsonMessageSerializer()); actual.RowKey.Should().Be(PendingEvent.GetRowKey(domainEvent.Version)); }
public void Create_sets_PartitionKey_correctly() { IFixture fixture = new Fixture(); Type sourceType = fixture.Create <Type>(); SomeDomainEvent domainEvent = fixture.Create <SomeDomainEvent>(); TestContext.WriteLine($"SourceId: {domainEvent.SourceId}"); fixture.Inject <IDomainEvent>(domainEvent); var actual = PendingEvent.Create( sourceType, fixture.Create <Envelope <IDomainEvent> >(), new JsonMessageSerializer()); actual.PartitionKey.Should().Be(AggregateEntity.GetPartitionKey(sourceType, domainEvent.SourceId)); }
public async Task FlushPendingEvents_absorbs_exception_caused_by_that_some_pending_event_already_deleted_since_loaded() { // Arrange var messageBus = new CompletableMessageBus(); var sut = new AzureEventPublisher(s_eventTable, s_serializer, messageBus); var fixture = new Fixture(); var user = new FakeUser(Guid.NewGuid(), fixture.Create <string>()); user.ChangeUsername(fixture.Create <string>()); var pendingEvents = new List <PendingEvent>( from message in user.FlushPendingEvents() let messageId = Guid.NewGuid() let envelope = new Envelope <IDomainEvent>(messageId, message) select PendingEvent.Create(typeof(FakeUser), envelope, s_serializer)); var batch = new TableBatchOperation(); foreach (PendingEvent pendingEvent in pendingEvents) { batch.Insert(pendingEvent); } await s_eventTable.ExecuteBatchAsync(batch); // Act Func <Task> action = async() => { Task flushTask = sut.FlushPendingEvents <FakeUser>(user.Id, CancellationToken.None); await s_eventTable.ExecuteAsync(TableOperation.Delete(pendingEvents.OrderBy(e => e.GetHashCode()).First())); messageBus.Complete(); await flushTask; }; // Assert action.ShouldNotThrow(); string filter = PendingEvent.GetFilter(typeof(FakeUser), user.Id); var query = new TableQuery { FilterString = filter }; TableQuerySegment actual = await s_eventTable.ExecuteQuerySegmentedAsync(query, default); actual.Should().BeEmpty(); }
public async Task FlushPendingEvents_does_not_delete_pending_events_if_fails_to_send() { // Arrange var exception = new InvalidOperationException(); IMessageBus messageBus = Mock.Of <IMessageBus>( x => x.Send(It.IsAny <IEnumerable <Envelope> >(), default) == Task.FromException(exception)); var sut = new AzureEventPublisher(s_eventTable, s_serializer, messageBus); var fixture = new Fixture(); var user = new FakeUser(Guid.NewGuid(), fixture.Create <string>()); user.ChangeUsername(fixture.Create <string>()); string operationId = fixture.Create <string>(); var correlationId = Guid.NewGuid(); string contributor = fixture.Create <string>(); var pendingEvents = new List <PendingEvent>( from message in user.FlushPendingEvents() let messageId = Guid.NewGuid() let envelope = new Envelope <IDomainEvent>(messageId, message, operationId, correlationId, contributor) select PendingEvent.Create(typeof(FakeUser), envelope, s_serializer)); var batch = new TableBatchOperation(); foreach (PendingEvent pendingEvent in pendingEvents) { batch.Insert(pendingEvent); } await s_eventTable.ExecuteBatchAsync(batch); // Act Func <Task> action = () => sut.FlushPendingEvents <FakeUser>(user.Id); // Assert action.ShouldThrow <InvalidOperationException>(); string filter = PendingEvent.GetFilter(typeof(FakeUser), user.Id); var query = new TableQuery <PendingEvent> { FilterString = filter }; TableQuerySegment <PendingEvent> actual = await s_eventTable.ExecuteQuerySegmentedAsync(query, default); actual.ShouldAllBeEquivalentTo(pendingEvents); }
public void Create_sets_Contributor_correctly() { IFixture fixture = new Fixture(); SomeDomainEvent domainEvent = fixture.Create <SomeDomainEvent>(); fixture.Inject <IDomainEvent>(domainEvent); Envelope <IDomainEvent> envelope = fixture.Create <Envelope <IDomainEvent> >(); TestContext.WriteLine($"Contributor: {envelope.Contributor}"); var actual = PendingEvent.Create( fixture.Create <Type>(), envelope, new JsonMessageSerializer()); actual.Contributor.Should().Be(envelope.Contributor); }
public async Task FlushAllPendingEvents_sends_all_pending_events() { // Arrange await s_eventTable.DeleteIfExistsAsync(); await s_eventTable.CreateAsync(); var messageBus = new MessageLogger(); var sut = new AzureEventPublisher(s_eventTable, s_serializer, messageBus); var expected = new List <Envelope <IDomainEvent> >(); var fixture = new Fixture(); var userIds = fixture.CreateMany <Guid>().ToList(); foreach (Guid userId in userIds) { var user = new FakeUser(userId, fixture.Create <string>()); user.ChangeUsername(fixture.Create <string>()); string operationId = fixture.Create <string>(); var correlationId = Guid.NewGuid(); string contributor = fixture.Create <string>(); var envelopes = new List <Envelope <IDomainEvent> >( from message in user.FlushPendingEvents() let messageId = Guid.NewGuid() select new Envelope <IDomainEvent>(messageId, message, operationId, correlationId, contributor)); expected.AddRange(envelopes); var batch = new TableBatchOperation(); foreach (Envelope <IDomainEvent> envelope in envelopes) { batch.Insert(PendingEvent.Create(typeof(FakeUser), envelope, s_serializer)); } await s_eventTable.ExecuteBatchAsync(batch); } // Act await sut.FlushAllPendingEvents(CancellationToken.None); // Assert messageBus.Log.ShouldAllBeEquivalentTo(expected); }
public void Create_sets_EventJson_correctly() { IFixture fixture = new Fixture(); SomeDomainEvent domainEvent = fixture.Create <SomeDomainEvent>(); fixture.Inject <IDomainEvent>(domainEvent); var serializer = new JsonMessageSerializer(); var actual = PendingEvent.Create( fixture.Create <Type>(), fixture.Create <Envelope <IDomainEvent> >(), serializer); object restored = serializer.Deserialize(actual.EventJson); restored.Should().BeOfType <SomeDomainEvent>(); restored.ShouldBeEquivalentTo(domainEvent); }
public async Task SaveEvents_inserts_pending_event_entities_correctly() { // Arrange var fixture = new Fixture(); var user = new FakeUser(Guid.NewGuid(), fixture.Create <string>()); user.ChangeUsername(fixture.Create <string>()); IList <IDomainEvent> domainEvents = user.FlushPendingEvents().ToList(); string operationId = fixture.Create <string>(); var correlationId = Guid.NewGuid(); string contributor = fixture.Create <string>(); // Act await _sut.SaveEvents <FakeUser>(domainEvents, operationId, correlationId, contributor); // Assert string filter = PendingEvent.GetFilter(typeof(FakeUser), user.Id); var query = new TableQuery <PendingEvent> { FilterString = filter }; IEnumerable <PendingEvent> actual = await s_eventTable.ExecuteQuerySegmentedAsync(query, default); actual.ShouldAllBeEquivalentTo( from domainEvent in domainEvents let envelope = new Envelope <IDomainEvent>( Guid.NewGuid(), domainEvent, operationId, correlationId, contributor) select PendingEvent.Create(typeof(FakeUser), envelope, _serializer), opts => opts .Excluding(e => e.MessageId) .Excluding(e => e.Timestamp) .Excluding(e => e.ETag) .WithStrictOrdering()); }
public async Task FlushPendingEvents_deletes_all_pending_events() { // Arrange var sut = new AzureEventPublisher(s_eventTable, s_serializer, Mock.Of <IMessageBus>()); var fixture = new Fixture(); var user = new FakeUser(Guid.NewGuid(), fixture.Create <string>()); user.ChangeUsername(fixture.Create <string>()); var envelopes = new List <Envelope <IDomainEvent> >( from domainEvent in user.FlushPendingEvents() let messageId = Guid.NewGuid() select new Envelope <IDomainEvent>(messageId, domainEvent)); var batch = new TableBatchOperation(); foreach (Envelope <IDomainEvent> envelope in envelopes) { batch.Insert(PendingEvent.Create(typeof(FakeUser), envelope, s_serializer)); } await s_eventTable.ExecuteBatchAsync(batch); // Act await sut.FlushPendingEvents <FakeUser>(user.Id); // Assert string filter = PendingEvent.GetFilter(typeof(FakeUser), user.Id); var query = new TableQuery { FilterString = filter }; TableQuerySegment actual = await s_eventTable.ExecuteQuerySegmentedAsync(query, default); actual.Results.Should().BeEmpty(); }