Exemplo n.º 1
0
        public async Task SaveProcessManagerAndPublishCommands_inserts_new_process_manager()
        {
            // Arrange
            var processManager = new FooProcessManager {
                AggregateId = Guid.NewGuid()
            };
            var sut = new SqlProcessManagerDataContext <FooProcessManager>(
                new FooProcessManagerDbContext(),
                new JsonMessageSerializer(),
                Mock.Of <ICommandPublisher>());

            using (sut)
            {
                // Act
                await sut.SaveProcessManagerAndPublishCommands(processManager);
            }

            // Assert
            using (var db = new FooProcessManagerDbContext())
            {
                FooProcessManager actual = await
                                           db.FooProcessManagers.SingleOrDefaultAsync(x => x.Id == processManager.Id);

                actual.Should().NotBeNull();
                actual.AggregateId.Should().Be(processManager.AggregateId);
            }
        }
        public async Task given_scheduled_message_bus_fails_FlushCommands_deletes_no_scheduled_command()
        {
            // Arrange
            var serializer        = new JsonMessageSerializer();
            var processManager    = new FooProcessManager();
            var fixture           = new Fixture();
            var scheduledCommands = new List <PendingScheduledCommand>(
                from command in fixture.CreateMany <FooCommand>()
                let envelope = new Envelope(command)
                               let scheduledEnvelope = new ScheduledEnvelope(envelope, fixture.Create <DateTimeOffset>())
                                                       select PendingScheduledCommand.FromScheduledEnvelope(processManager, scheduledEnvelope, serializer));

            using (var db = new FooProcessManagerDbContext())
            {
                db.PendingScheduledCommands.AddRange(scheduledCommands);
                await db.SaveChangesAsync();
            }

            Guid poisonedMessageId = (from c in scheduledCommands
                                      orderby c.GetHashCode()
                                      select c.MessageId).First();

            IScheduledMessageBus scheduledMessageBus = Mock.Of <IScheduledMessageBus>();
            var exception = new InvalidOperationException();

            Mock.Get(scheduledMessageBus)
            .Setup(x => x.Send(It.Is <ScheduledEnvelope>(p => p.Envelope.MessageId == poisonedMessageId), CancellationToken.None))
            .ThrowsAsync(exception);

            var sut = new SqlCommandPublisher(
                () => new FooProcessManagerDbContext(),
                serializer,
                Mock.Of <IMessageBus>(),
                scheduledMessageBus);

            // Act
            Func <Task> action = () => sut.FlushCommands(processManager.Id, CancellationToken.None);

            // Assert
            action.ShouldThrow <InvalidOperationException>().Which.Should().BeSameAs(exception);
            using (var db = new FooProcessManagerDbContext())
            {
                IQueryable <PendingScheduledCommand> query = from c in db.PendingScheduledCommands
                                                             where c.ProcessManagerId == processManager.Id
                                                             select c;
                List <PendingScheduledCommand> actual = await query.ToListAsync();

                actual.ShouldAllBeEquivalentTo(scheduledCommands, opts => opts.RespectingRuntimeTypes());
            }
        }
Exemplo n.º 3
0
        public async Task SaveProcessManagerAndPublishCommands_commits_once()
        {
            // Arrange
            var context = new FooProcessManagerDbContext();
            var sut     = new SqlProcessManagerDataContext <FooProcessManager>(
                context,
                new JsonMessageSerializer(),
                Mock.Of <ICommandPublisher>());
            var processManager = new FooProcessManager();

            // Act
            await sut.SaveProcessManagerAndPublishCommands(processManager);

            // Assert
            context.CommitCount.Should().Be(1);
        }
Exemplo n.º 4
0
        public async Task SaveProcessManagerAndPublishCommands_inserts_pending_scheduled_commands_sequentially()
        {
            // Arrange
            var fixture = new Fixture();
            IEnumerable <(FooCommand command, DateTimeOffset scheduledTime)> scheduledCommands = fixture.CreateMany <(FooCommand, DateTimeOffset)>();
            var processManager = new FooProcessManager(
                from e in scheduledCommands
                select new ScheduledCommand(e.command, e.scheduledTime));
            var    operationId   = Guid.NewGuid();
            var    correlationId = Guid.NewGuid();
            string contributor   = fixture.Create <string>();
            var    serializer    = new JsonMessageSerializer();

            // Act
            using (var sut = new SqlProcessManagerDataContext <FooProcessManager>(
                       new FooProcessManagerDbContext(),
                       serializer,
                       Mock.Of <ICommandPublisher>()))
            {
                await sut.SaveProcessManagerAndPublishCommands(processManager, operationId, correlationId, contributor);
            }

            // Assert
            using (var db = new FooProcessManagerDbContext())
            {
                IQueryable <PendingScheduledCommand> query =
                    from c in db.PendingScheduledCommands
                    where c.ProcessManagerId == processManager.Id
                    orderby c.Id
                    select c;

                var pendingScheduledCommands = query.ToList();
                pendingScheduledCommands.Should().HaveCount(scheduledCommands.Count());
                foreach (((FooCommand command, DateTimeOffset scheduledTime)expected, PendingScheduledCommand actual)t in
                         scheduledCommands.Zip(pendingScheduledCommands, (expected, actual) => (expected, actual)))
                {
                    t.actual.ProcessManagerType.Should().Be(typeof(FooProcessManager).FullName);
                    t.actual.ProcessManagerId.Should().Be(processManager.Id);
                    t.actual.MessageId.Should().NotBeEmpty();
                    t.actual.OperationId.Should().Be(operationId);
                    t.actual.CorrelationId.Should().Be(correlationId);
                    t.actual.Contributor.Should().Be(contributor);
                    serializer.Deserialize(t.actual.CommandJson).ShouldBeEquivalentTo(t.expected.command, opts => opts.RespectingRuntimeTypes());
                    t.actual.ScheduledTime.Should().Be(t.expected.scheduledTime);
                }
            }
        }
        public async Task FlushCommands_absorbs_exception_caused_by_that_some_pending_scheduled_command_already_deleted_since_loaded()
        {
            // Arrange
            var scheduledMessageBus = new CompletableScheduledMessageBus();
            var serializer          = new JsonMessageSerializer();
            var sut = new SqlCommandPublisher(
                () => new FooProcessManagerDbContext(),
                serializer,
                Mock.Of <IMessageBus>(),
                scheduledMessageBus);

            var processManager = new FooProcessManager();

            using (var db = new FooProcessManagerDbContext())
            {
                db.PendingScheduledCommands.AddRange(
                    from command in new Fixture().CreateMany <FooCommand>()
                    let envelope = new Envelope(command)
                                   let scheduledEnvelope = new ScheduledEnvelope(envelope, DateTimeOffset.Now)
                                                           select PendingScheduledCommand.FromScheduledEnvelope(processManager, scheduledEnvelope, serializer));
                await db.SaveChangesAsync();
            }

            // Act
            Func <Task> action = async() =>
            {
                Task flushTask = sut.FlushCommands(processManager.Id, CancellationToken.None);
                using (var db = new FooProcessManagerDbContext())
                {
                    List <PendingScheduledCommand> pendingScheduledCommands = await db
                                                                              .PendingScheduledCommands
                                                                              .Where(c => c.ProcessManagerId == processManager.Id)
                                                                              .OrderByDescending(c => c.Id)
                                                                              .Take(1)
                                                                              .ToListAsync();

                    db.PendingScheduledCommands.RemoveRange(pendingScheduledCommands);
                    await db.SaveChangesAsync();
                }

                scheduledMessageBus.Complete();
                await flushTask;
            };

            // Assert
            action.ShouldNotThrow();
        }
        public async Task FlushCommands_deletes_all_commands_associated_with_specified_process_manager()
        {
            // Arrange
            var serializer = new JsonMessageSerializer();

            var processManager      = new FooProcessManager();
            var noiseProcessManager = new FooProcessManager();

            const int noiseCommandCount = 3;

            using (var db = new FooProcessManagerDbContext())
            {
                var commands = new List <PendingCommand>(
                    from command in Enumerable.Repeat(new FooCommand(), 3)
                    let envelope = new Envelope(command)
                                   select PendingCommand.FromEnvelope(processManager, envelope, serializer));

                commands.AddRange(
                    from command in Enumerable.Repeat(new FooCommand(), noiseCommandCount)
                    let envelope = new Envelope(command)
                                   select PendingCommand.FromEnvelope(noiseProcessManager, envelope, serializer));

                var random = new Random();
                db.PendingCommands.AddRange(
                    from command in commands
                    orderby random.Next()
                    select command);

                await db.SaveChangesAsync();
            }

            var sut = new SqlCommandPublisher(
                () => new FooProcessManagerDbContext(),
                serializer,
                Mock.Of <IMessageBus>(),
                Mock.Of <IScheduledMessageBus>());

            // Act
            await sut.FlushCommands(processManager.Id, CancellationToken.None);

            // Assert
            using (var db = new FooProcessManagerDbContext())
            {
                (await db.PendingCommands.AnyAsync(c => c.ProcessManagerId == processManager.Id)).Should().BeFalse();
                (await db.PendingCommands.CountAsync(c => c.ProcessManagerId == noiseProcessManager.Id)).Should().Be(noiseCommandCount);
            }
        }
        public async Task given_message_bus_fails_FlushCommands_deletes_no_command()
        {
            // Arrange
            var serializer     = new JsonMessageSerializer();
            var processManager = new FooProcessManager();
            var fixture        = new Fixture();
            var commands       = new List <PendingCommand>(
                from command in fixture.CreateMany <FooCommand>()
                let envelope = new Envelope(command)
                               select PendingCommand.FromEnvelope(processManager, envelope, serializer));

            using (var db = new FooProcessManagerDbContext())
            {
                db.PendingCommands.AddRange(commands);
                await db.SaveChangesAsync();
            }

            IMessageBus messageBus = Mock.Of <IMessageBus>();
            var         exception  = new InvalidOperationException();

            Mock.Get(messageBus)
            .Setup(x => x.Send(It.IsAny <IEnumerable <Envelope> >(), It.IsAny <CancellationToken>()))
            .ThrowsAsync(exception);

            var sut = new SqlCommandPublisher(
                () => new FooProcessManagerDbContext(),
                serializer,
                messageBus,
                Mock.Of <IScheduledMessageBus>());

            // Act
            Func <Task> action = () => sut.FlushCommands(processManager.Id, CancellationToken.None);

            // Assert
            action.ShouldThrow <InvalidOperationException>().Which.Should().BeSameAs(exception);
            using (var db = new FooProcessManagerDbContext())
            {
                IQueryable <PendingCommand> query = from c in db.PendingCommands
                                                    where c.ProcessManagerId == processManager.Id
                                                    select c;
                List <PendingCommand> actual = await query.ToListAsync();

                actual.ShouldAllBeEquivalentTo(commands, opts => opts.RespectingRuntimeTypes());
            }
        }
Exemplo n.º 8
0
        public async Task FindProcessManager_returns_process_manager_that_satisfies_predicate()
        {
            // Arrange
            var processManagers = Enumerable
                                  .Repeat <Func <FooProcessManager> >(() => new FooProcessManager {
                AggregateId = Guid.NewGuid()
            }, 10)
                                  .Select(f => f.Invoke())
                                  .ToList();

            FooProcessManager expected = processManagers.First();

            using (var db = new FooProcessManagerDbContext())
            {
                var random = new Random();
                foreach (FooProcessManager processManager in from p in processManagers
                         orderby random.Next()
                         select p)
                {
                    db.FooProcessManagers.Add(processManager);
                }

                await db.SaveChangesAsync();
            }

            var sut = new SqlProcessManagerDataContext <FooProcessManager>(
                new FooProcessManagerDbContext(),
                new JsonMessageSerializer(),
                Mock.Of <ICommandPublisher>());

            using (sut)
            {
                Expression <Func <FooProcessManager, bool> > predicate = x => x.AggregateId == expected.AggregateId;

                // Act
                FooProcessManager actual = await sut.FindProcessManager(predicate, CancellationToken.None);

                // Assert
                actual.Should().NotBeNull();
                actual.Id.Should().Be(expected.Id);
            }
        }
        public async Task EnqueueAll_publishes_all_pending_scheduled_commands_asynchronously()
        {
            // Arrange
            var serializer = new JsonMessageSerializer();

            var fixture = new Fixture();

            using (var db = new FooProcessManagerDbContext())
            {
                for (int i = 0; i < 3; i++)
                {
                    var processManager = new FooProcessManager();
                    db.PendingScheduledCommands.AddRange(from command in Enumerable.Repeat(new FooCommand(), 3)
                                                         let envelope = new Envelope(command)
                                                                        let scheduledEnvelope = new ScheduledEnvelope(envelope, DateTimeOffset.Now)
                                                                                                select PendingScheduledCommand.FromScheduledEnvelope(processManager, scheduledEnvelope, serializer));
                }

                await db.SaveChangesAsync();
            }

            var sut = new SqlCommandPublisher(
                () => new FooProcessManagerDbContext(),
                serializer,
                Mock.Of <IMessageBus>(),
                Mock.Of <IScheduledMessageBus>());

            // Act
            sut.EnqueueAll(CancellationToken.None);

            // Assert
            using (var db = new FooProcessManagerDbContext())
            {
                int maximumRetryCount = 5;
                var retryPolicy       = new RetryPolicy <bool>(
                    maximumRetryCount,
                    new DelegatingTransientFaultDetectionStrategy <bool>(any => any == true),
                    new ConstantRetryIntervalStrategy(TimeSpan.FromSeconds(1.0)));
                (await retryPolicy.Run(db.PendingScheduledCommands.AnyAsync, CancellationToken.None)).Should().BeFalse();
            }
        }
        public async Task FlushCommands_sends_all_scheduled_commands_associated_with_specified_process_manager_sequentially()
        {
            // Arrange
            var serializer          = new JsonMessageSerializer();
            var processManager      = new FooProcessManager();
            var noiseProcessManager = new FooProcessManager();

            var fixture = new Fixture();

            var scheduledEnvelopes = new List <ScheduledEnvelope>(
                from command in fixture.CreateMany <FooCommand>()
                let envelope = new Envelope(Guid.NewGuid(), command, null, Guid.NewGuid(), null)
                               select new ScheduledEnvelope(envelope, fixture.Create <DateTimeOffset>()));

            using (var db = new FooProcessManagerDbContext())
            {
                db.PendingScheduledCommands.AddRange(
                    from scheduledEnvelope in scheduledEnvelopes
                    select PendingScheduledCommand.FromScheduledEnvelope(processManager, scheduledEnvelope, serializer));

                db.PendingScheduledCommands.AddRange(
                    from scheduledEnvelope in fixture.CreateMany <ScheduledEnvelope>()
                    select PendingScheduledCommand.FromScheduledEnvelope(noiseProcessManager, scheduledEnvelope, serializer));

                await db.SaveChangesAsync();
            }

            var scheduledMessageBus = new ScheduledMessageBus();

            var sut = new SqlCommandPublisher(
                () => new FooProcessManagerDbContext(),
                serializer,
                Mock.Of <IMessageBus>(),
                scheduledMessageBus);

            // Act
            await sut.FlushCommands(processManager.Id, CancellationToken.None);

            // Assert
            scheduledMessageBus.Sent.ShouldAllBeEquivalentTo(scheduledEnvelopes, opts => opts.WithStrictOrdering().RespectingRuntimeTypes());
        }
Exemplo n.º 11
0
        public async Task FindProcessManager_flushes_pending_commands()
        {
            // Arrange
            ICommandPublisher publisher = Mock.Of <ICommandPublisher>();
            var processManager          = new FooProcessManager();
            var sut = new SqlProcessManagerDataContext <FooProcessManager>(
                new FooProcessManagerDbContext(),
                new JsonMessageSerializer(),
                publisher);

            using (var db = new FooProcessManagerDbContext())
            {
                db.FooProcessManagers.Add(processManager);
                await db.SaveChangesAsync();
            }

            // Act
            await sut.FindProcessManager(p => p.Id == processManager.Id, CancellationToken.None);

            // Assert
            Mock.Get(publisher).Verify(x => x.FlushCommands(processManager.Id, CancellationToken.None), Times.Once());
        }
Exemplo n.º 12
0
        public async Task SaveProcessManagerAndPublishCommands_updates_existing_process_manager()
        {
            // Arrange
            var fixture = new Fixture();
            FooProcessManager processManager = fixture.Create <FooProcessManager>();

            using (var db = new FooProcessManagerDbContext())
            {
                db.FooProcessManagers.Add(processManager);
                await db.SaveChangesAsync();
            }

            string statusValue = fixture.Create <string>();

            var sut = new SqlProcessManagerDataContext <FooProcessManager>(
                new FooProcessManagerDbContext(),
                new JsonMessageSerializer(),
                Mock.Of <ICommandPublisher>());

            using (sut)
            {
                processManager = await sut.FindProcessManager(x => x.Id == processManager.Id);

                processManager.StatusValue = statusValue;

                // Act
                await sut.SaveProcessManagerAndPublishCommands(processManager);
            }

            // Assert
            using (var db = new FooProcessManagerDbContext())
            {
                FooProcessManager actual = await
                                           db.FooProcessManagers.SingleOrDefaultAsync(x => x.Id == processManager.Id);

                actual.StatusValue.Should().Be(statusValue);
            }
        }