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); }
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); } }
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); }
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); }
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)); } }
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"); }
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 }); } }
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); }
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));
private IUpdateProjectionWhen <T> CreateProjector <T>( Action <T> action = null) where T : IEvent => Projector.Create(action ?? (_ => { })).Named(Any.CamelCaseName(6));