public async Task PublishPendingEvents_does_not_fails_even_if_all_events_persisted()
        {
            // Arrange
            var userId = Guid.NewGuid();

            var userCreated     = fixture.Create <FakeUserCreated>();
            var usernameChanged = fixture.Create <FakeUsernameChanged>();
            var domainEvents    = new DomainEvent[] { userCreated, usernameChanged };

            RaiseEvents(userId, domainEvents);

            var envelopes = new List <Envelope>(domainEvents.Select(e => new Envelope(e)));

            var batchOperation = new TableBatchOperation();

            envelopes
            .Select(e => PendingEventTableEntity.FromEnvelope <FakeUser>(e, serializer))
            .ForEach(batchOperation.Insert);
            await s_eventTable.ExecuteBatchAsync(batchOperation);

            batchOperation.Clear();
            envelopes
            .Select(e => EventTableEntity.FromEnvelope <FakeUser>(e, serializer))
            .ForEach(batchOperation.Insert);
            await s_eventTable.ExecuteBatchAsync(batchOperation);

            // Act
            Func <Task> action = () => sut.PublishPendingEvents <FakeUser>(userId, CancellationToken.None);

            // Assert
            action.ShouldNotThrow();
        }
        public async Task PublishAllEvents_sends_pending_events()
        {
            // Arrange
            var domainEvents = new List <DomainEvent>();

            List <Guid> users = fixture.CreateMany <Guid>().ToList();

            foreach (Guid userId in users)
            {
                var userCreated     = fixture.Create <FakeUserCreated>();
                var usernameChanged = fixture.Create <FakeUsernameChanged>();
                var events          = new DomainEvent[] { userCreated, usernameChanged };
                RaiseEvents(userId, events);

                var envelopes = new List <Envelope>(events.Select(e => new Envelope(e)));

                var batchOperation = new TableBatchOperation();
                envelopes
                .Select(e => PendingEventTableEntity.FromEnvelope <FakeUser>(e, serializer))
                .ForEach(batchOperation.Insert);
                await s_eventTable.ExecuteBatchAsync(batchOperation);

                batchOperation.Clear();
                envelopes
                .Select(e => EventTableEntity.FromEnvelope <FakeUser>(e, serializer))
                .ForEach(batchOperation.Insert);
                await s_eventTable.ExecuteBatchAsync(batchOperation);

                domainEvents.AddRange(events);
            }

            var messages = new List <IDomainEvent>();

            Mock.Get(messageBus)
            .Setup(
                x =>
                x.SendBatch(
                    It.IsAny <IEnumerable <Envelope> >(),
                    It.IsAny <CancellationToken>()))
            .Callback <IEnumerable <Envelope>, CancellationToken>(
                (batch, cancellationToken) =>
                messages.AddRange(batch
                                  .Select(b => b.Message)
                                  .OfType <IDomainEvent>()
                                  .Where(m => users.Contains(m.SourceId))))
            .Returns(Task.FromResult(true));

            // Act
            await sut.PublishAllEvents(CancellationToken.None);

            // Assert
            messages.Should().OnlyContain(e => e is IDomainEvent);
            messages.ShouldAllBeEquivalentTo(domainEvents);
        }
        public async Task PublishPendingEvents_does_not_delete_pending_events_if_fails_to_send()
        {
            // Arrange
            var userId = Guid.NewGuid();

            var userCreated     = fixture.Create <FakeUserCreated>();
            var usernameChanged = fixture.Create <FakeUsernameChanged>();
            var domainEvents    = new DomainEvent[] { userCreated, usernameChanged };

            RaiseEvents(userId, domainEvents);

            var envelopes = new List <Envelope>(domainEvents.Select(e => new Envelope(e)));

            var batchOperation = new TableBatchOperation();
            var pendingEvents  = new List <PendingEventTableEntity>(
                envelopes.Select(e => PendingEventTableEntity.FromEnvelope <FakeUser>(e, serializer)));

            pendingEvents.ForEach(batchOperation.Insert);
            await s_eventTable.ExecuteBatchAsync(batchOperation);

            batchOperation.Clear();
            envelopes
            .Take(1)
            .Select(e => EventTableEntity.FromEnvelope <FakeUser>(e, serializer))
            .ForEach(batchOperation.Insert);
            await s_eventTable.ExecuteBatchAsync(batchOperation);

            Mock.Get(messageBus)
            .Setup(
                x =>
                x.SendBatch(
                    It.IsAny <IEnumerable <Envelope> >(),
                    It.IsAny <CancellationToken>()))
            .Throws(new InvalidOperationException());

            // Act
            try
            {
                await sut.PublishPendingEvents <FakeUser>(userId, CancellationToken.None);
            }
            catch (InvalidOperationException)
            {
            }

            // Assert
            string partitionKey         = PendingEventTableEntity.GetPartitionKey(typeof(FakeUser), userId);
            var    query                = new TableQuery <PendingEventTableEntity>().Where($"PartitionKey eq '{partitionKey}'");
            IEnumerable <object> actual = s_eventTable.ExecuteQuery(query).Select(e => e.RowKey);

            actual.ShouldAllBeEquivalentTo(pendingEvents.Select(e => e.RowKey));
        }
        public async Task PublishPendingEventss_sends_only_persisted_pending_events()
        {
            // Arrange
            var userId = Guid.NewGuid();

            var userCreated     = fixture.Create <FakeUserCreated>();
            var usernameChanged = fixture.Create <FakeUsernameChanged>();
            var domainEvents    = new DomainEvent[] { userCreated, usernameChanged };

            RaiseEvents(userId, domainEvents);

            var envelopes = new List <Envelope>(domainEvents.Select(e => new Envelope(e)));

            var batchOperation = new TableBatchOperation();

            envelopes
            .Select(e => PendingEventTableEntity.FromEnvelope <FakeUser>(e, serializer))
            .ForEach(batchOperation.Insert);
            await s_eventTable.ExecuteBatchAsync(batchOperation);

            batchOperation.Clear();
            envelopes
            .Take(1)
            .Select(e => EventTableEntity.FromEnvelope <FakeUser>(e, serializer))
            .ForEach(batchOperation.Insert);
            await s_eventTable.ExecuteBatchAsync(batchOperation);

            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 <FakeUser>(userId, CancellationToken.None);

            // Assert
            Mock.Get(messageBus).Verify(
                x =>
                x.SendBatch(
                    It.IsAny <IEnumerable <Envelope> >(),
                    CancellationToken.None),
                Times.Once());
            batch.ShouldAllBeEquivalentTo(envelopes.Take(1), opts => opts.RespectingRuntimeTypes());
        }
Beispiel #5
0
        private async Task InsertEventsAndCorrelation <T>(
            List <Envelope> envelopes,
            Guid?correlationId,
            CancellationToken cancellationToken)
            where T : class, IEventSourced
        {
            var batch = new TableBatchOperation();

            var  firstEvent = (IDomainEvent)envelopes.First().Message;
            Guid sourceId   = firstEvent.SourceId;

            foreach (Envelope envelope in envelopes)
            {
                batch.Insert(EventTableEntity.FromEnvelope <T>(envelope, _serializer));
            }

            if (correlationId.HasValue)
            {
                batch.Insert(CorrelationTableEntity.Create(typeof(T), sourceId, correlationId.Value));
            }

            try
            {
                await _eventTable.ExecuteBatchAsync(batch, cancellationToken).ConfigureAwait(false);
            }
            catch (StorageException exception) when(correlationId.HasValue)
            {
                string filter = CorrelationTableEntity.GetFilter(typeof(T), sourceId, correlationId.Value);
                var    query  = new TableQuery <CorrelationTableEntity>().Where(filter);

                if (await _eventTable.Any(query, cancellationToken))
                {
                    throw new DuplicateCorrelationException(
                              typeof(T),
                              sourceId,
                              correlationId.Value,
                              exception);
                }

                throw;
            }
        }
        public async Task PublishPendingEvents_deletes_all_pending_events()
        {
            // Arrange
            var userId = Guid.NewGuid();

            var userCreated     = fixture.Create <FakeUserCreated>();
            var usernameChanged = fixture.Create <FakeUsernameChanged>();
            var domainEvents    = new DomainEvent[] { userCreated, usernameChanged };

            RaiseEvents(userId, domainEvents);

            var envelopes = new List <Envelope>(domainEvents.Select(e => new Envelope(e)));

            var batchOperation = new TableBatchOperation();

            envelopes
            .Select(e => PendingEventTableEntity.FromEnvelope <FakeUser>(e, serializer))
            .ForEach(batchOperation.Insert);
            await s_eventTable.ExecuteBatchAsync(batchOperation);

            batchOperation.Clear();
            envelopes
            .Take(1)
            .Select(e => EventTableEntity.FromEnvelope <FakeUser>(e, serializer))
            .ForEach(batchOperation.Insert);
            await s_eventTable.ExecuteBatchAsync(batchOperation);

            // Act
            await sut.PublishPendingEvents <FakeUser>(userId, CancellationToken.None);

            // Assert
            string partitionKey = PendingEventTableEntity.GetPartitionKey(typeof(FakeUser), userId);
            var    query        = new TableQuery <PendingEventTableEntity>().Where($"PartitionKey eq '{partitionKey}'");
            List <PendingEventTableEntity> actual = s_eventTable.ExecuteQuery(query).ToList();

            actual.Should().BeEmpty();
        }