示例#1
0
        public void ReadModelCatchup_queries_scheduled_commands_if_IScheduledCommand_is_subscribed()
        {
            var scheduledCommandsWritten = 0;
            var scheduledCommandsQueried = 0;

            Events.Write(50, _ =>
            {
                if (Any.Bool())
                {
                    return(Events.Any());
                }

                scheduledCommandsWritten++;
                return(new CommandScheduled <Order>
                {
                    Command = new Ship(),
                    DueTime = DateTimeOffset.UtcNow
                });
            });

            var projector     = Projector.Create <IScheduledCommand>(e => { }).Named(MethodBase.GetCurrentMethod().Name);
            var eventsQueried = 0;

            using (var catchup = CreateReadModelCatchup(projector))
                using (var eventStore = new EventStoreDbContext())
                {
                    catchup.Progress
                    .Where(s => !s.IsStartOfBatch)
                    .ForEachAsync(s =>
                    {
                        var eventId = s.CurrentEventId;
                        var @event  = eventStore.Events.Single(e => e.Id == eventId);
                        if (@event.Type.StartsWith("Scheduled:"))
                        {
                            scheduledCommandsQueried++;
                        }
                        eventsQueried++;
                    });
                    catchup.DisposeAfter(r => r.Run());
                    Console.WriteLine(new { eventsQueried });
                }

            scheduledCommandsQueried.Should().Be(scheduledCommandsWritten);
        }
        public async Task ReadModelCatchup_StartAtEventId_can_be_used_to_avoid_requery_of_previous_events()
        {
            var lastEventId = Events.Write(50, _ => Events.Any());

            var eventsProjected = 0;

            var projector = Projector.Create <Event>(e => { eventsProjected++; })
                            .Named(MethodBase.GetCurrentMethod().Name);

            using (var catchup = new ReadModelCatchup(projector)
            {
                StartAtEventId = lastEventId - 20
            })
            {
                await catchup.Run();
            }

            eventsProjected.Should().Be(21);
        }
示例#3
0
        public async Task The_current_batch_in_progress_can_be_awaited_using_SingleBatchAsync()
        {
            Events.Write(10);

            using (var catchup = CreateReadModelCatchup(Projector.Create <IEvent>(e =>
            {
                // slow this down just enough for the batch to still be running when we await below
                Thread.Sleep(1000);
            })))
            {
                Task.Run(() => catchup.Run());
                Thread.Sleep(1000);
                var status = await catchup.SingleBatchAsync();

                status.IsEndOfBatch.Should().BeTrue();
                status.BatchCount.Should().Be(10);
                status.CurrentEventId.Should().Be(HighestEventId + 10);
            }
        }
示例#4
0
        public async Task ReadModelCatchup_queries_can_be_filtered()
        {
            // arrange
            var shouldQueryAggregateId    = Any.Guid();
            var shouldNotQueryAggregateId = Any.Guid();

            Events.Write(100, i =>
            {
                var @event         = Events.Any() as Event;
                @event.AggregateId = i % 2 == 0
                                         ? shouldQueryAggregateId
                                         : shouldNotQueryAggregateId;
                return(@event);
            });

            var countOfEventsWeWant     = 0;
            var countOfEventsWeDontWant = 0;

            var projector = Projector.Create <IEvent>(e =>
            {
                if (e.AggregateId == shouldQueryAggregateId)
                {
                    countOfEventsWeWant++;
                }
                if (e.AggregateId == shouldNotQueryAggregateId)
                {
                    countOfEventsWeDontWant++;
                }
            }).Named(MethodBase.GetCurrentMethod().Name);

            // act
            using (var catchup = CreateReadModelCatchup(
                       filter: e => e.AggregateId == shouldQueryAggregateId,
                       projectors: new[] { projector }))
            {
                await catchup.Run();
            }

            // assert
            countOfEventsWeWant.Should().Be(50);
            countOfEventsWeDontWant.Should().Be(0);
        }
示例#5
0
        public async Task ReadModelCatchup_queries_all_events_if_IEvent_is_subscribed()
        {
            Events.Write(100, _ => Events.Any());

            var projector     = Projector.Create <IEvent>(e => { }).Named(MethodBase.GetCurrentMethod().Name);
            var eventsQueried = 0;

            using (var catchup = CreateReadModelCatchup(projector))
            {
                catchup.Progress
                .Where(s => !s.IsStartOfBatch)
                .ForEachAsync(s => { eventsQueried++; });
                await catchup.Run()
                .ContinueWith(r => catchup.Dispose());

                Console.WriteLine(new { eventsQueried });
            }

            eventsQueried.Should().Be(100);
        }
示例#6
0
        public async Task When_a_Progress_subscriber_throws_then_catchup_continues()
        {
            Events.Write(10);
            var projectedEventCount = 0;

            using (var catchup = CreateReadModelCatchup(Projector.Create <IEvent>(e =>
            {
                projectedEventCount++;
            })))
            {
                catchup.Progress.Subscribe(e =>
                {
                    throw new Exception("oops!");
                });

                await catchup.Run();
            }

            projectedEventCount.Should().Be(10);
        }
        public async Task ReadModelCatchup_does_not_query_events_that_no_subscribed_projector_is_interested_in()
        {
            Events.Write(100, _ => Events.Any());
            Events.Write(1, _ => new Order.Created());

            var projector2 = Projector.Create <CustomerAccount.Created>(e => { });

            StorableEvent extraneousEvent = null;

            using (var catchup = CreateReadModelCatchup(projector2))
                using (var eventStore = EventStoreDbContext())
                {
                    var eventsQueried = 0;
                    catchup.Progress
                    .Where(s => !s.IsStartOfBatch)
                    .ForEachAsync(s =>
                    {
                        var eventId = s.CurrentEventId;
                        var @event  = eventStore.Events.Single(e => e.Id == eventId);
                        if (@event.StreamName != "CustomerAccount" || @event.Type != "Created")
                        {
                            extraneousEvent = @event;
                            catchup.Dispose();
                        }
                        eventsQueried++;
                    });
                    await catchup.Run()
                    .ContinueWith(r => catchup.Dispose());

                    Console.WriteLine(new { eventsQueried });
                }

            if (extraneousEvent != null)
            {
                Assert.Fail(string.Format("Found an event that should not have been queried from the event store: {0}:{1} (#{2})",
                                          extraneousEvent.StreamName,
                                          extraneousEvent.Type,
                                          extraneousEvent.Id));
            }
        }
示例#8
0
        public async Task Two_different_projectors_can_catch_up_to_two_different_event_stores_using_separate_catchups()
        {
            // arrange
            var projector1CallCount = 0;
            var projector2CallCount = 0;
            var projector1          = Projector.Create <Order.ItemAdded>(e => projector1CallCount++).Named(MethodBase.GetCurrentMethod().Name + "1");
            var projector2          = Projector.Create <Order.ItemAdded>(e => projector2CallCount++).Named(MethodBase.GetCurrentMethod().Name + "2");
            var startProjector2AtId = new OtherEventStoreDbContext().DisposeAfter(db => db.HighestEventId()) + 1;

            Events.Write(5, createEventStore: () => EventStoreDbContext());
            Events.Write(5, createEventStore: () => new OtherEventStoreDbContext());

            using (var eventStoreCatchup = new ReadModelCatchup(
                       readModelDbContext: () => ReadModelDbContext(),
                       eventStoreDbContext: () => EventStoreDbContext(),
                       startAtEventId: HighestEventId + 1,
                       projectors: projector1)
            {
                Name = "eventStoreCatchup"
            })
                using (var otherEventStoreCatchup = new ReadModelCatchup(
                           readModelDbContext: () => ReadModelDbContext(),
                           eventStoreDbContext: () => new OtherEventStoreDbContext(),
                           startAtEventId: startProjector2AtId,
                           projectors: projector2)
                {
                    Name = "otherEventStoreCatchup"
                })
                {
                    // act
                    await eventStoreCatchup.SingleBatchAsync();

                    await otherEventStoreCatchup.SingleBatchAsync();
                }

            // assert
            projector1CallCount.Should().Be(5, "projector1 should get all events from event stream");
            projector2CallCount.Should().Be(5, "projector2 should get all events from event stream");
        }
示例#9
0
        public async Task SingleBatchAsync_can_be_used_to_observe_the_status_during_a_single_catchup_batch()
        {
            Events.Write(5);

            using (var catchup = CreateReadModelCatchup(Projector.Create <IEvent>(e => { })))
            {
                var statuses = await catchup.SingleBatchAsync().ToArray();

                var ids = statuses.Select(s => s.CurrentEventId).ToArray();

                Console.WriteLine(new { ids }.ToLogString());

                ids.ShouldBeEquivalentTo(new[]
                {
                    HighestEventId + 1,
                    HighestEventId + 1,
                    HighestEventId + 2,
                    HighestEventId + 3,
                    HighestEventId + 4,
                    HighestEventId + 5
                });
            }
        }
示例#10
0
        public async Task When_Progress_is_awaited_then_it_completes_when_the_catchup_is_disposed()
        {
            Events.Write(5);
            long lastEventId = 0;

            using (var catchup = CreateReadModelCatchup(Projector.Create <IEvent>(e => { })))
            {
                catchup.Progress.Subscribe(s =>
                {
                    Console.WriteLine(s);
                    lastEventId = s.CurrentEventId;
                });

#pragma warning disable 4014
                // don't await
                Task.Run(() => catchup.Run())
                .ContinueWith(r => catchup.Dispose());
#pragma warning restore 4014

                await catchup.Progress;
            }

            lastEventId.Should().Be(HighestEventId + 5);
        }
示例#11
0
        public async Task When_Progress_is_awaited_then_it_completes_when_the_catchup_is_disposed()
        {
            Events.Write(5);
            long lastEventId = 0;

            using (var catchup = CreateReadModelCatchup(Projector.Create <IEvent>(e => { })))
            {
                catchup.Progress.Subscribe(s =>
                {
                    Console.WriteLine(s);
                    lastEventId = s.CurrentEventId;
                });

                Task.Run(() =>
                {
                    catchup.Run();
                    catchup.Dispose();
                });

                await catchup.Progress;
            }

            lastEventId.Should().Be(HighestEventId + 5);
        }
 private IUpdateProjectionWhen <IEvent> CreateProjector(
     Action <IEvent> action = null) =>
 Projector.Create(action ?? (_ => { })).Named(Any.CamelCaseName(6));
示例#13
0
 private IUpdateProjectionWhen <T> CreateProjector <T>(
     Action <T> action = null)
     where T : IEvent =>
 Projector.Create(action ?? (_ => { })).Named(Any.CamelCaseName(6));