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();
        }
Пример #2
0
        public void FromEnvelope_sets_MessageId_correctly()
        {
            var domainEvent = fixture.Create <FakeUserCreated>();
            var envelope    = new Envelope(domainEvent);

            PendingEventTableEntity actual =
                FromEnvelope <FakeUser>(envelope, serializer);

            actual.MessageId.Should().Be(envelope.MessageId);
        }
Пример #3
0
        public void FromEnvelope_sets_RowKey_correctly()
        {
            var domainEvent = fixture.Create <FakeUserCreated>();
            var envelope    = new Envelope(domainEvent);

            PendingEventTableEntity actual =
                FromEnvelope <FakeUser>(envelope, serializer);

            actual.RowKey.Should().Be(GetRowKey(domainEvent.Version));
        }
Пример #4
0
        public void FromEnvelope_sets_PartitionKey_correctly()
        {
            var domainEvent = fixture.Create <FakeUserCreated>();
            var envelope    = new Envelope(domainEvent);

            PendingEventTableEntity actual =
                FromEnvelope <FakeUser>(envelope, serializer);

            actual.PartitionKey.Should().Be(
                GetPartitionKey(typeof(FakeUser), domainEvent.SourceId));
        }
Пример #5
0
        public void FromEnvelope_sets_CorrelationId_correctly()
        {
            var domainEvent   = fixture.Create <FakeUserCreated>();
            var correlationId = GuidGenerator.Create();
            var envelope      = new Envelope(correlationId, domainEvent);

            PendingEventTableEntity actual =
                FromEnvelope <FakeUser>(envelope, serializer);

            actual.CorrelationId.Should().Be(correlationId);
        }
        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);
        }
Пример #7
0
        public void FromEnvelope_sets_EventJson_correctly()
        {
            var domainEvent = fixture.Create <FakeUserCreated>();
            var envelope    = new Envelope(domainEvent);

            PendingEventTableEntity actual =
                FromEnvelope <FakeUser>(envelope, serializer);

            object message = serializer.Deserialize(actual.EventJson);

            message.Should().BeOfType <FakeUserCreated>();
            message.ShouldBeEquivalentTo(domainEvent);
        }
        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());
        }
Пример #10
0
        private Task InsertPendingEvents <T>(
            List <Envelope> envelopes,
            CancellationToken cancellationToken)
            where T : class, IEventSourced
        {
            var batch = new TableBatchOperation();

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

            return(_eventTable.ExecuteBatchAsync(batch, cancellationToken));
        }
Пример #11
0
        public Task PublishPendingEvents <T>(
            Guid sourceId,
            CancellationToken cancellationToken)
            where T : class, IEventSourced
        {
            if (sourceId == Guid.Empty)
            {
                throw new ArgumentException(
                          $"{sourceId} cannot be empty.", nameof(sourceId));
            }

            string pendingPartition = PendingEventTableEntity.GetPartitionKey(typeof(T), sourceId);

            return(Publish(pendingPartition, cancellationToken));
        }
Пример #12
0
        private async Task SendPendingEvents(
            List <PendingEventTableEntity> pendingEvents,
            CancellationToken cancellationToken)
        {
            PendingEventTableEntity firstEvent = pendingEvents.First();

            string persistentPartition = firstEvent.PersistentPartition;

            List <EventTableEntity> persistentEvents = await
                                                       GetPersistentEvents(persistentPartition, firstEvent.Version, cancellationToken).ConfigureAwait(false);

            var persistentVersions = new HashSet <int>(persistentEvents.Select(e => e.Version));

            var envelopes =
                from e in pendingEvents
                where persistentVersions.Contains(e.Version)
                select new Envelope(e.MessageId, e.CorrelationId, _serializer.Deserialize(e.EventJson));

            await _messageBus.SendBatch(envelopes, cancellationToken).ConfigureAwait(false);
        }
Пример #13
0
        public async Task SaveEvents_inserts_pending_event_entities_correctly()
        {
            // Arrange
            var created         = fixture.Create <FakeUserCreated>();
            var usernameChanged = fixture.Create <FakeUsernameChanged>();
            var events          = new DomainEvent[] { created, usernameChanged };
            var correlationId   = Guid.NewGuid();

            RaiseEvents(userId, events);

            // Act
            await sut.SaveEvents <FakeUser>(events, correlationId);

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

            foreach (var t in pendingEvents.Zip(events, (pending, source) =>
                                                new { Pending = pending, Source = source }))
            {
                var actual = new
                {
                    t.Pending.RowKey,
                    t.Pending.PersistentPartition,
                    t.Pending.Version,
                    t.Pending.CorrelationId,
                    Message = serializer.Deserialize(t.Pending.EventJson)
                };
                actual.ShouldBeEquivalentTo(new
                {
                    RowKey = PendingEventTableEntity.GetRowKey(t.Source.Version),
                    PersistentPartition = EventTableEntity.GetPartitionKey(typeof(FakeUser), userId),
                    t.Source.Version,
                    CorrelationId = correlationId,
                    Message       = t.Source
                },
                                            opts => opts.RespectingRuntimeTypes());
            }
        }
        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();
        }