コード例 #1
0
        public override async Task Scheduled_commands_with_no_due_time_are_delivered_at_Clock_Now_when_delivery_is_deferred()
        {
            // arrange
            var deliveredTime = new DateTimeOffset();

            var target = new NonEventSourcedCommandTarget(Any.CamelCaseName());

            await Save(target);

            Configuration
            .Current
            .UseCommandHandler <NonEventSourcedCommandTarget, TestCommand>(async(_, __) => deliveredTime = Clock.Now());

            // act
            await Schedule(target.Id,
                           new TestCommand
            {
                CanBeDeliveredDuringScheduling = false
            },
                           dueTime : null);

            await AdvanceClock(
                clockName : clockName,
                by : 1.Hours());

            // assert
            deliveredTime
            .Should()
            .Be(Clock.Now());
        }
コード例 #2
0
        public async Task When_the_VirtualClock_is_advanced_past_a_commands_due_time_then_in_EnactCommand_ClockNow_returns_the_commands_due_time()
        {
            var dueTime = DateTimeOffset.Parse("2019-09-01 +00:00");

            VirtualClock.Start(DateTimeOffset.Parse("2019-01-01 +00:00"));

            var target        = new NonEventSourcedCommandTarget(Any.CamelCaseName());
            var configuration = Configuration.Current;
            await configuration.Store <NonEventSourcedCommandTarget>().Put(target);

            var clockNowAtCommandDeliveryTime = default(DateTimeOffset);

            configuration.UseCommandHandler <NonEventSourcedCommandTarget, TestCommand>(
                enactCommand: async(_, __) =>
            {
                clockNowAtCommandDeliveryTime = Clock.Now();
            });

            var scheduler = configuration.CommandScheduler <NonEventSourcedCommandTarget>();

            await scheduler.Schedule(target.Id,
                                     new TestCommand(),
                                     dueTime : dueTime);

            VirtualClock.Current.AdvanceBy(365.Days());

            clockNowAtCommandDeliveryTime.Should().Be(dueTime);
        }
        public override async Task Scheduled_commands_are_delivered_immediately_if_past_due_per_the_domain_clock()
        {
            // arrange
            var target = new NonEventSourcedCommandTarget(Any.CamelCaseName());
            await Save(target);

            // act
            await Schedule(target.Id,
                new TestCommand(),
                Clock.Now().AddMinutes(-2));

            //assert 
            target = await Get<NonEventSourcedCommandTarget>(target.Id);

            target.CommandsEnacted.Should().HaveCount(1);
        }
コード例 #4
0
        public override async Task Scheduled_commands_are_delivered_immediately_if_past_due_per_the_domain_clock()
        {
            // arrange
            var target = new NonEventSourcedCommandTarget(Any.CamelCaseName());

            await Save(target);

            // act
            await Schedule(target.Id,
                           new TestCommand(),
                           Clock.Now().AddMinutes(-2));

            //assert
            target = await Get <NonEventSourcedCommandTarget>(target.Id);

            target.CommandsEnacted.Should().HaveCount(1);
        }
        public override async Task When_a_clock_is_advanced_then_commands_are_not_triggered_that_have_not_become_due()
        {
            // arrange
            var target = new NonEventSourcedCommandTarget(Any.CamelCaseName());
            await Save(target);

            // act
            await Schedule(target.Id,
                new TestCommand(),
                Clock.Now().AddDays(2));

            await AdvanceClock(TimeSpan.FromDays(1.1));

            //assert 
            target = await Get<NonEventSourcedCommandTarget>(target.Id);

            target.CommandsEnacted.Should().HaveCount(0);
        }
        public override async Task When_a_clock_is_advanced_its_associated_commands_are_triggered()
        {
            // arrange
            var target = new NonEventSourcedCommandTarget(Any.CamelCaseName());
            await Save(target);

            await Schedule(target.Id,
                new TestCommand(),
                Clock.Now().AddDays(1));

            // act
            await AdvanceClock(25.Hours());

            //assert 
            target = await Get<NonEventSourcedCommandTarget>(target.Id);

            target.CommandsEnacted.Should().HaveCount(1);
        }
コード例 #7
0
        public override async Task When_a_clock_is_advanced_then_commands_are_not_triggered_that_have_not_become_due()
        {
            // arrange
            var target = new NonEventSourcedCommandTarget(Any.CamelCaseName());

            await Save(target);

            // act
            await Schedule(target.Id,
                           new TestCommand(),
                           Clock.Now().AddDays(2));

            await AdvanceClock(TimeSpan.FromDays(1.1));

            //assert
            target = await Get <NonEventSourcedCommandTarget>(target.Id);

            target.CommandsEnacted.Should().HaveCount(0);
        }
コード例 #8
0
        public override async Task Scheduled_commands_are_delivered_immediately_if_past_due_per_the_scheduler_clock()
        {
            // arrange
            var target = new NonEventSourcedCommandTarget(Any.CamelCaseName());

            await Save(target);

            var schedulerClockTime = DateTimeOffset.Parse("2016-02-13 03:03:48 PM");

            // act
            await Schedule(target.Id,
                           new TestCommand(),
                           schedulerClockTime.AddMinutes(-2));

            //assert
            target = await Get <NonEventSourcedCommandTarget>(target.Id);

            target.CommandsEnacted.Should().HaveCount(1);
        }
コード例 #9
0
        public override async Task When_a_clock_is_advanced_its_associated_commands_are_triggered()
        {
            // arrange
            var target = new NonEventSourcedCommandTarget(Any.CamelCaseName());

            await Save(target);

            await Schedule(target.Id,
                           new TestCommand(),
                           Clock.Now().AddDays(1));

            // act
            await AdvanceClock(25.Hours());

            //assert
            target = await Get <NonEventSourcedCommandTarget>(target.Id);

            target.CommandsEnacted.Should().HaveCount(1);
        }
コード例 #10
0
        public override async Task When_a_command_is_scheduled_but_an_exception_is_thrown_in_a_handler_then_an_error_is_recorded()
        {
            // arrange
            var target = new NonEventSourcedCommandTarget(Any.CamelCaseName());

            await Save(target);

            // act
            await Schedule(target.Id,
                           new TestCommand(isValid : false));

            //assert
            using (var db = CommandSchedulerDbContext())
            {
                var aggregateId = target.Id.ToGuidV3();
                var error       = db.Errors.Single(e => e.ScheduledCommand.AggregateId == aggregateId);

                error.Error.Should().Contain("CommandValidationException");
            }
        }
コード例 #11
0
        public override async Task When_command_is_durable_but_immediate_delivery_succeeds_then_it_is_not_redelivered()
        {
            // arrange
            var target = new NonEventSourcedCommandTarget(Any.CamelCaseName());

            await Save(target);

            // act
            await Schedule(target.Id,
                           new TestCommand
            {
                RequiresDurableScheduling = true
            });
            await AdvanceClock(2.Days());

            //assert
            target = await Get <NonEventSourcedCommandTarget>(target.Id);

            target.CommandsEnacted.Should().HaveCount(1);
        }
コード例 #12
0
        public async Task When_a_command_is_delivered_and_throws_during_clock_advance_then_other_commands_are_still_delivered()
        {
            // arrange
            var target = new NonEventSourcedCommandTarget(Any.CamelCaseName())
            {
                OnEnactCommand = async(commandTarget, command) =>
                {
                    await Task.Yield();

                    if (command.ETag == "first")
                    {
                        throw new Exception("oops!");
                    }
                }
            };
            var store = Configuration.Current.Store <NonEventSourcedCommandTarget>();
            await store.Put(target);

            VirtualClock.Start();

            // act
            var scheduler = Configuration.Current.CommandScheduler <NonEventSourcedCommandTarget>();

            await scheduler.Schedule(target.Id,
                                     new TestCommand(etag : "first"),
                                     Clock.Now().AddMinutes(1));

            await scheduler.Schedule(target.Id,
                                     new TestCommand(etag : "second"),
                                     Clock.Now().AddMinutes(2));

            VirtualClock.Current.AdvanceBy(1.Hours());

            // assert
            target = await store.Get(target.Id);

            target.CommandsEnacted
            .Select(c => c.ETag)
            .Should()
            .Contain(etag => etag == "second");
        }
コード例 #13
0
        public override async Task A_command_handler_can_cancel_a_scheduled_command_after_it_fails()
        {
            // arrange
            var target = new NonEventSourcedCommandTarget(Any.CamelCaseName())
            {
                OnHandleScheduledCommandError = async(commandTarget, failed) => failed.Cancel()
            };

            await Save(target);

            // act
            await Schedule(target.Id,
                           new TestCommand(isValid : false),
                           Clock.Now().AddMinutes(2));

            await AdvanceClock(5.Minutes());

            //assert
            target = await Get <NonEventSourcedCommandTarget>(target.Id);

            target.CommandsFailed.Should().HaveCount(1);
        }
コード例 #14
0
        public override async Task Immediately_scheduled_commands_triggered_by_a_scheduled_command_have_their_due_time_set_to_the_causative_command_clock()
        {
            // arrange
            var deliveredTime = new DateTimeOffset();
            var target        = new NonEventSourcedCommandTarget(Any.CamelCaseName());

            await Save(target);

            Configuration.Current.UseCommandHandler <NonEventSourcedCommandTarget, TestCommand>(async(_, cmd) =>
            {
                if (cmd.ETag == "first")
                {
                    await Schedule(target.Id,
                                   new TestCommand
                    {
                        CanBeDeliveredDuringScheduling = true
                    });
                }
                else
                {
                    deliveredTime = Clock.Now();
                }
            });

            // act
            await Schedule(target.Id,
                           new TestCommand
            {
                CanBeDeliveredDuringScheduling = true,
                ETag = "first"
            },
                           dueTime : DateTimeOffset.Parse("2016-02-13 01:05:00 AM"));

            await AdvanceClock(clockName : clockName, by : 1.Hours());

            // assert
            deliveredTime.Should().Be(DateTimeOffset.Parse("2016-02-13 01:05:00 AM"));
        }
コード例 #15
0
        public async Task When_a_scheduled_command_fails_and_the_clock_is_advanced_again_then_it_can_be_retried()
        {
            // arrange
            var target = new NonEventSourcedCommandTarget {
                IsValid = false
            };

            await Save(target);

            await Schedule(
                target.Id,
                new TestCommand(),
                Clock.Now().AddDays(10));

            // act
            await AdvanceClock(TimeSpan.FromDays(10.1));

            target.CommandsFailed
            .Should()
            .HaveCount(1);
            target
            .CommandsEnacted
            .Should()
            .HaveCount(0);

            target.IsValid = true;

            await AdvanceClock(TimeSpan.FromHours(1));

            target
            .CommandsFailed
            .Should()
            .HaveCount(1);
            target
            .CommandsEnacted
            .Should()
            .HaveCount(1);
        }
コード例 #16
0
        public override async Task A_command_handler_can_request_retry_of_a_failed_command_as_late_as_it_wants()
        {
            // arrange
            var target = new NonEventSourcedCommandTarget(Any.CamelCaseName())
            {
                OnHandleScheduledCommandError = async(commandTarget, failed) =>
                                                failed.Retry(after: 1.Hours())
            };

            await Save(target);

            // act
            await Schedule(target.Id,
                           new TestCommand(isValid : false),
                           Clock.Now().Add(2.Minutes()));
            await AdvanceClock(5.Minutes());
            await AdvanceClock(5.Minutes()); // should not trigger a retry

            //assert
            target = await Get <NonEventSourcedCommandTarget>(target.Id);

            target.CommandsFailed.Should().HaveCount(1);
        }
コード例 #17
0
        public async Task When_a_command_fails_and_is_scheduled_for_retry_then_advancing_the_virtual_clock_triggers_redelivery()
        {
            VirtualClock.Start();

            var target = new NonEventSourcedCommandTarget(Any.CamelCaseName())
            {
                IsValid = false
            };
            var retries = 0;

            var configuration = Configuration.Current;

            await configuration.Store <NonEventSourcedCommandTarget>().Put(target);

            configuration.UseCommandHandler <NonEventSourcedCommandTarget, TestCommand>(
                enactCommand: async(_, __) => { },
                handleScheduledCommandException: async(_, command) =>
            {
                if (command.NumberOfPreviousAttempts >= 12)
                {
                    command.Cancel();
                    return;
                }
                retries++;
                command.Retry(1.Hours());
            });

            var scheduler = configuration.CommandScheduler <NonEventSourcedCommandTarget>();

            await scheduler.Schedule(target.Id,
                                     new TestCommand(),
                                     dueTime : Clock.Now().AddHours(1));

            VirtualClock.Current.AdvanceBy(1.Days());

            retries.Should().Be(12);
        }
コード例 #18
0
        public override async Task Immediately_scheduled_commands_triggered_by_a_scheduled_command_have_their_due_time_set_to_the_causative_command_clock()
        {
            // arrange
            var deliveredTime = new DateTimeOffset();
            var target = new NonEventSourcedCommandTarget(Any.CamelCaseName());
            await Save(target);
            Configuration.Current.UseCommandHandler<NonEventSourcedCommandTarget, TestCommand>(async (_, cmd) =>
            {
                if (cmd.ETag == "first")
                {
                    await Schedule(target.Id,
                        new TestCommand
                        {
                            CanBeDeliveredDuringScheduling = true
                        });
                }
                else
                {
                    deliveredTime = Clock.Now();
                }
            });

            // act
            await Schedule(target.Id,
                new TestCommand
                {
                    CanBeDeliveredDuringScheduling = true,
                    ETag = "first"
                },
                dueTime: DateTimeOffset.Parse("2016-02-13 01:05:00 AM"));

            await AdvanceClock(clockName: clockName, by: 1.Hours());

            // assert 
            deliveredTime.Should().Be(DateTimeOffset.Parse("2016-02-13 01:05:00 AM"));
        }
コード例 #19
0
        public override async Task A_command_handler_can_request_retry_of_a_failed_command_as_late_as_it_wants()
        {
            // arrange
            var target = new NonEventSourcedCommandTarget(Any.CamelCaseName())
            {
                OnHandleScheduledCommandError = async (commandTarget, failed) =>
                                                failed.Retry(after: 1.Hours())
            };
            await Save(target);

            // act
            await Schedule(target.Id,
                new TestCommand(isValid: false),
                Clock.Now().Add(2.Minutes()));
            await AdvanceClock(5.Minutes());
            await AdvanceClock(5.Minutes()); // should not trigger a retry

            //assert 
            target = await Get<NonEventSourcedCommandTarget>(target.Id);

            target.CommandsFailed.Should().HaveCount(1);
        }
コード例 #20
0
 public async Task when_a_command_is_applied_directly_the_command_is_executed()
 {
     var target = new NonEventSourcedCommandTarget();
     await target.ApplyAsync(new TestCommand());
     target.CommandsEnacted.Should().HaveCount(1);
 }
コード例 #21
0
 private static NonEventSourcedCommandTarget CreateCommandTarget()
 {
     var target = new NonEventSourcedCommandTarget(Any.Word());
     Save(target).Wait();
     return target;
 }
コード例 #22
0
        public async Task When_a_scheduled_command_fails_and_the_clock_is_advanced_again_then_it_can_be_retried()
        {
            // arrange
            var target = new NonEventSourcedCommandTarget { IsValid = false };

            await Save(target);

            await Schedule(
                target.Id,
                new TestCommand(),
                Clock.Now().AddDays(10));

            // act
            await AdvanceClock(TimeSpan.FromDays(10.1));

            target.CommandsFailed
                .Should()
                .HaveCount(1);
            target
                .CommandsEnacted
                .Should()
                .HaveCount(0);

            target.IsValid = true;

            await AdvanceClock(TimeSpan.FromHours(1));

            target
                .CommandsFailed
                .Should()
                .HaveCount(1);
            target
                .CommandsEnacted
                .Should()
                .HaveCount(1);
        }
コード例 #23
0
        public override async Task A_command_handler_can_cancel_a_scheduled_command_after_it_fails()
        {
            // arrange
            var target = new NonEventSourcedCommandTarget(Any.CamelCaseName())
            {
                OnHandleScheduledCommandError = async (commandTarget, failed) => failed.Cancel()
            };
            await Save(target);

            // act
            await Schedule(target.Id,
                new TestCommand(isValid: false),
                Clock.Now().AddMinutes(2));

            await AdvanceClock(5.Minutes());

            //assert 
            target = await Get<NonEventSourcedCommandTarget>(target.Id);

            target.CommandsFailed.Should().HaveCount(1);
        }
コード例 #24
0
        public override async Task When_a_command_is_scheduled_but_an_exception_is_thrown_in_a_handler_then_an_error_is_recorded()
        {
            // arrange
            var target = new NonEventSourcedCommandTarget(Any.CamelCaseName());
            await Save(target);

            // act
            await Schedule(target.Id,
                new TestCommand(isValid: false));

            //assert 
            using (var db = CommandSchedulerDbContext())
            {
                var aggregateId = target.Id.ToGuidV3();
                var error = db.Errors.Single(e => e.ScheduledCommand.AggregateId == aggregateId);

                error.Error.Should().Contain("CommandValidationException");
            }
        }
コード例 #25
0
        public override async Task When_command_is_durable_but_immediate_delivery_succeeds_then_it_is_not_redelivered()
        {
            // arrange
            var target = new NonEventSourcedCommandTarget(Any.CamelCaseName());
            await Save(target);

            // act
            await Schedule(target.Id,
                new TestCommand
                {
                    RequiresDurableScheduling = true
                });
            await AdvanceClock(2.Days());

            //assert 
            target = await Get<NonEventSourcedCommandTarget>(target.Id);

            target.CommandsEnacted.Should().HaveCount(1);
        }
コード例 #26
0
        public override async Task Scheduled_commands_are_delivered_immediately_if_past_due_per_the_scheduler_clock()
        {
            // arrange
            var target = new NonEventSourcedCommandTarget(Any.CamelCaseName());
            await Save(target);

            var schedulerClockTime = DateTimeOffset.Parse("2016-02-13 03:03:48 PM");

            // act
            await Schedule(target.Id,
                new TestCommand(),
                schedulerClockTime.AddMinutes(-2));

            //assert 
            target = await Get<NonEventSourcedCommandTarget>(target.Id);

            target.CommandsEnacted.Should().HaveCount(1);
        }
コード例 #27
0
        public override async Task Scheduled_commands_with_no_due_time_are_delivered_at_Clock_Now_when_delivery_is_deferred()
        {
            // arrange
            var deliveredTime = new DateTimeOffset();

            var target = new NonEventSourcedCommandTarget(Any.CamelCaseName());
            await Save(target);

            Configuration
                .Current
                .UseCommandHandler<NonEventSourcedCommandTarget, TestCommand>(async (_, __) => deliveredTime = Clock.Now());

            // act
            await Schedule(target.Id,
                new TestCommand
                {
                    CanBeDeliveredDuringScheduling = false
                },
                dueTime: null);

            await AdvanceClock(
                clockName: clockName,
                by: 1.Hours());

            // assert 
            deliveredTime
                .Should()
                .Be(Clock.Now());
        }