Example #1
0
        public void GetRowKey_returns_prefixed_formatted_version()
        {
            int    version = new Fixture().Create <int>();
            string actual  = PendingEvent.GetRowKey(version);

            actual.Should().Be($"Pending-{version:D10}");
        }
Example #2
0
        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();
        }
Example #4
0
        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)));
        }
Example #5
0
        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;
            }
        }
Example #7
0
        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));
        }
Example #8
0
        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));
        }
Example #9
0
        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();
        }
Example #10
0
        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);
        }
Example #11
0
        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);
        }
Example #12
0
        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);
        }
Example #13
0
        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());
        }
Example #15
0
        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();
        }