Exemple #1
0
        [Test]//Do not worry about it if this test fails when running in ncrunch. It runs it much slower for some reason. Probably due to intrumenting the assembly. Just ignore it in ncrunch.
        public void A_hundred_thousand_events_large_aggregate_with_four_migrations_should_load_cached_in_less_than_150_milliseconds()
        {
            var eventMigrations = Seq.Create <IEventMigration>(
                Before <E6> .Insert <E2>(),
                Before <E7> .Insert <E3>(),
                Before <E8> .Insert <E4>(),
                Before <E9> .Insert <E5>()
                ).ToArray();

            using (var container = CreateContainerForEventStoreType(() => eventMigrations, EventStoreType))
            {
                var timeSource = container.Resolve <DummyTimeSource>();

                var history   = Seq.OfTypes <Ec1>().Concat(1.Through(100000).Select(index => typeof(E1))).ToArray();
                var aggregate = TestAggregate.FromEvents(timeSource, Guid.NewGuid(), history);
                container.ExecuteUnitOfWorkInIsolatedScope(() => container.Resolve <IEventStoreSession>().Save(aggregate));

                //Warm up cache..
                container.ExecuteUnitOfWorkInIsolatedScope(() => container.Resolve <IEventStoreSession>().Get <TestAggregate>(aggregate.Id));

                TimeAsserter.Execute(
                    maxTotal: 150.Milliseconds().AdjustRuntimeForNCrunch(boost: 6),
                    description: "load aggregate in isolated scope",
                    action: () => container.ExecuteInIsolatedScope(() => container.Resolve <IEventStoreSession>().Get <TestAggregate>(aggregate.Id)));
            }
        }
        public void Given_a_10000_events_large_aggregate()
        {
            var historyTypes = Seq.OfTypes <Ec1>()
                               .Concat(
                1.Through(10)
                .SelectMany(
                    index => 1.Through(996)
                    .Select(_ => typeof(E1))
                    .Concat(Seq.OfTypes <E2, E4, E6, E8>()))).ToList();

            var aggregate = TestAggregate.FromEvents(DummyTimeSource.Now, Guid.NewGuid(), historyTypes);

            _history = aggregate.History.Cast <AggregateRootEvent>().ToList();
        }
        public void UpdatingAnAggregateAfterPersistingMigrations()
        {
            var emptyMigrationsArray = new IEventMigration[0];
            IReadOnlyList <IEventMigration> migrations = emptyMigrationsArray;

            using (var container = CreateContainerForEventStoreType(() => migrations, EventStoreType))
            {
                var id = Guid.Parse("00000000-0000-0000-0000-000000000001");

                container.Resolve <DummyTimeSource>().UtcNow = DateTime.Parse("2001-01-01 12:00");

                var initialAggregate = TestAggregate.FromEvents(container.Resolve <IUtcTimeTimeSource>(), id, Seq.OfTypes <Ec1, E1>());
                var initialHistory   = initialAggregate.History;


                Func <IEventStoreSession> session    = () => container.Resolve <IEventStoreSession>();
                Func <IEventStore>        eventStore = () => container.Resolve <IEventStore>();

                container.ExecuteUnitOfWorkInIsolatedScope(() => session().Save(initialAggregate));

                migrations = Seq.Create(Replace <E1> .With <E5>()).ToList();

                container.ExecuteUnitOfWorkInIsolatedScope(() => eventStore().PersistMigrations());

                migrations = Seq.Create <IEventMigration>().ToList();

                container.ExecuteUnitOfWorkInIsolatedScope(() => session().Get <TestAggregate>(id).RaiseEvents(new E2()));

                var aggregate = container.ExecuteInIsolatedScope(() => session().Get <TestAggregate>(id));

                var expected = TestAggregate.FromEvents(container.Resolve <IUtcTimeTimeSource>(), id, Seq.OfTypes <Ec1, E5, E2>()).History;
                AssertStreamsAreIdentical(expected: expected, migratedHistory: aggregate.History, descriptionOfHistory: "migrated history");

                var completeEventHistory = container.ExecuteInIsolatedScope(() => eventStore().ListAllEventsForTestingPurposesAbsolutelyNotUsableForARealEventStoreOfAnySize()).Cast <AggregateRootEvent>();
                AssertStreamsAreIdentical(expected: expected, migratedHistory: completeEventHistory, descriptionOfHistory: "streamed persisted history");

                Console.WriteLine($"Version");
                Console.WriteLine("Aggregate Effective Inserted Manual");
                Console.WriteLine("A E I M");
                completeEventHistory.ForEach(@event => Console.WriteLine($"{@event.AggregateRootVersion} {@event.EffectiveVersion} {@event.InsertedVersion} {@event.ManualVersion}"));

                ClearEventstoreCache(container);

                completeEventHistory = container.ExecuteInIsolatedScope(() => eventStore().ListAllEventsForTestingPurposesAbsolutelyNotUsableForARealEventStoreOfAnySize()).Cast <AggregateRootEvent>();
                AssertStreamsAreIdentical(expected: expected, migratedHistory: completeEventHistory, descriptionOfHistory: "streamed persisted history");
            }
        }
        public void PersistingMigrationsAndThenUpdatingTheAggregateFromAnotherProcessesEventStore()
        {
            var actualMigrations = Seq.Create(Replace <E1> .With <E2>()).ToArray();
            IReadOnlyList <IEventMigration> migrations = new List <IEventMigration>();

            using (var persistingContainer = CreateContainerForEventStoreType(() => migrations, EventStoreType))
            {
                string eventStoreConnectionString;
                using (persistingContainer.BeginScope())
                {
                    eventStoreConnectionString = ((SqlServerEventStore)persistingContainer.Resolve <IEventStore>()).ConnectionString;
                    eventStoreConnectionString = eventStoreConnectionString + ";";
                }
                Func <IEventStore> persistingEventStore = () => persistingContainer.Resolve <IEventStore>();

                using (var otherProcessContainer = CreateContainerForEventStoreType(() => migrations, EventStoreType, eventStoreConnectionString))
                {
                    Func <IEventStoreSession> otherEventstoreSession = () => otherProcessContainer.Resolve <IEventStoreSession>();

                    var id = Guid.Parse("00000000-0000-0000-0000-000000000001");

                    var aggregate = TestAggregate.FromEvents(
                        persistingContainer.Resolve <IUtcTimeTimeSource>(),
                        id,
                        Seq.OfTypes <Ec1, E1, E2, E3, E4>());

                    otherProcessContainer.ExecuteUnitOfWorkInIsolatedScope(() => otherEventstoreSession().Save(aggregate));
                    migrations = actualMigrations;
                    otherProcessContainer.ExecuteUnitOfWorkInIsolatedScope(() => otherEventstoreSession().Get <TestAggregate>(id));

                    var test = persistingContainer.ExecuteUnitOfWorkInIsolatedScope(() => persistingEventStore().GetAggregateHistory(id));
                    test.Count().Should().BeGreaterThan(0);

                    persistingContainer.ExecuteInIsolatedScope(() => persistingEventStore().PersistMigrations());

                    otherProcessContainer.ExecuteUnitOfWorkInIsolatedScope(
                        () =>
                    {
                        otherEventstoreSession().Get <TestAggregate>(id).RaiseEvents(new E3());
                    });
                }
            }
        }
        public void RunMigrationTest
        (
            IEnumerable <Type> originalHistory,
            IEnumerable <Type> expectedHistory,
            params IEventMigration[] manualMigrations)
        {
            var migrationInstances = manualMigrations;
            var aggregateId        = Guid.NewGuid();
            var aggregate          = TestAggregate.FromEvents(aggregateId, originalHistory);

            var mutatedHistory = new SingleAggregateEventStreamMutator(aggregate.Id, migrationInstances)
                                 .MutateCompleteAggregateHistory(aggregate.History).ToList();

            var expected = TestAggregate.FromEvents(aggregateId, expectedHistory).History.ToList();

            Console.WriteLine($"Expected: ");
            expected.ForEach(e => Console.WriteLine($"   {e}"));

            Console.WriteLine($"\nActual: ");
            mutatedHistory.ForEach(e => Console.WriteLine($"   {e}"));

            expected.ForEach(
                (@event, index) =>
            {
                if (@event.GetType() != mutatedHistory[index].GetType())
                {
                    Assert.Fail(
                        $"Expected event at postion {index} to be of type {@event.GetType()} but it was of type: {mutatedHistory[index].GetType()}");
                }
            });

            mutatedHistory.ShouldAllBeEquivalentTo(
                expected,
                config => config.RespectingRuntimeTypes()
                .WithStrictOrdering()
                .Excluding(@event => @event.EventId)
                .Excluding(@event => @event.TimeStamp));
        }
        public void Inserting_E2_After_E1_Persisting_and_then_Inserting_E3_after_E1()
        {
            var firstMigration  = Seq.Create(After <E1> .Insert <E2>()).ToArray();
            var secondMigration = Seq.Create(After <E1> .Insert <E3>()).ToArray();
            IReadOnlyList <IEventMigration> migrations = new List <IEventMigration>();

            using (var container = CreateContainerForEventStoreType(() => migrations, EventStoreType))
            {
                container.Resolve <DummyTimeSource>().UtcNow = DateTime.Parse("2001-01-01 12:00");

                var id = Guid.Parse("00000000-0000-0000-0000-000000000001");
                var initialAggregate = TestAggregate.FromEvents(container.Resolve <IUtcTimeTimeSource>(), id, Seq.OfTypes <Ec1, E1>());
                var expectedHistoryAfterFirstMigration  = TestAggregate.FromEvents(container.Resolve <IUtcTimeTimeSource>(), id, Seq.OfTypes <Ec1, E1, E2>()).History;
                var expectedHistoryAfterSecondMigration = TestAggregate.FromEvents(container.Resolve <IUtcTimeTimeSource>(), id, Seq.OfTypes <Ec1, E1, E3, E2>()).History;

                Func <IEventStoreSession> session    = () => container.Resolve <IEventStoreSession>();
                Func <IEventStore>        eventStore = () => container.Resolve <IEventStore>();

                container.ExecuteUnitOfWorkInIsolatedScope(() => session().Save(initialAggregate));
                migrations = firstMigration;
                var historyWithFirstMigrationUnPersisted = container.ExecuteUnitOfWorkInIsolatedScope(() => session().Get <TestAggregate>(id).History);

                container.ExecuteUnitOfWorkInIsolatedScope(() => eventStore().PersistMigrations());
                var historyAfterPersistingFirstMigration = container.ExecuteUnitOfWorkInIsolatedScope(() => session().Get <TestAggregate>(id).History);
                AssertStreamsAreIdentical(expectedHistoryAfterFirstMigration, historyWithFirstMigrationUnPersisted, nameof(historyWithFirstMigrationUnPersisted));
                AssertStreamsAreIdentical(expectedHistoryAfterFirstMigration, historyAfterPersistingFirstMigration, nameof(historyAfterPersistingFirstMigration));

                migrations = secondMigration;
                ClearEventstoreCache(container);
                var historyWithSecondMigrationUnPersisted = container.ExecuteUnitOfWorkInIsolatedScope(() => session().Get <TestAggregate>(id).History);

                container.ExecuteUnitOfWorkInIsolatedScope(() => eventStore().PersistMigrations());
                var historyAfterPersistingSecondMigration = container.ExecuteUnitOfWorkInIsolatedScope(() => session().Get <TestAggregate>(id).History);
                AssertStreamsAreIdentical(expectedHistoryAfterSecondMigration, historyWithSecondMigrationUnPersisted, nameof(historyWithSecondMigrationUnPersisted));
                AssertStreamsAreIdentical(expectedHistoryAfterSecondMigration, historyAfterPersistingSecondMigration, nameof(historyAfterPersistingSecondMigration));
            }
        }
        public void PersistingMigrationsOfTheSameAggregateMultipleTimesWithEventsAddedInTheMiddleAndAfter()
        {
            var emptyMigrationsArray = new IEventMigration[0];
            IReadOnlyList <IEventMigration> migrations = emptyMigrationsArray;

            using (var container = CreateContainerForEventStoreType(() => migrations, EventStoreType))
            {
                var id = Guid.Parse("00000000-0000-0000-0000-000000000001");

                container.Resolve <DummyTimeSource>().UtcNow = DateTime.Parse("2001-01-01 12:00");

                var aggregate      = TestAggregate.FromEvents(container.Resolve <IUtcTimeTimeSource>(), id, Seq.OfTypes <Ec1, E1, E2, E3, E4>());
                var initialHistory = aggregate.History;


                Func <IEventStoreSession> session    = () => container.Resolve <IEventStoreSession>();
                Func <IEventStore>        eventStore = () => container.Resolve <IEventStore>();

                var firstSavedHistory = container.ExecuteUnitOfWorkInIsolatedScope(
                    () =>
                {
                    session().Save(aggregate);
                    return(session().Get <TestAggregate>(id).History);
                });


                AssertStreamsAreIdentical(initialHistory, firstSavedHistory, "first saved history");

                migrations = Seq.Create(Replace <E1> .With <E5>()).ToList();

                var migratedHistory = container.ExecuteUnitOfWorkInIsolatedScope(() => session().Get <TestAggregate>(id).History);
                var expectedAfterReplacingE1WithE5 =
                    TestAggregate.FromEvents(container.Resolve <IUtcTimeTimeSource>(), id, Seq.OfTypes <Ec1, E5, E2, E3, E4>()).History;
                AssertStreamsAreIdentical(expected: expectedAfterReplacingE1WithE5, migratedHistory: migratedHistory, descriptionOfHistory: "migrated history");

                var historyAfterPersistingButBeforeReload = container.ExecuteUnitOfWorkInIsolatedScope(
                    () =>
                {
                    eventStore().PersistMigrations();
                    return(session().Get <TestAggregate>(id).History);
                });

                AssertStreamsAreIdentical(expected: expectedAfterReplacingE1WithE5, migratedHistory: historyAfterPersistingButBeforeReload, descriptionOfHistory: "migrated, persisted");

                var historyAfterPersistingAndReloading = container.ExecuteUnitOfWorkInIsolatedScope(() => session().Get <TestAggregate>(id).History);
                AssertStreamsAreIdentical(expected: expectedAfterReplacingE1WithE5, migratedHistory: historyAfterPersistingAndReloading, descriptionOfHistory: "migrated, persisted, reloaded");

                container.ExecuteUnitOfWorkInIsolatedScope(() => session().Get <TestAggregate>(id).RaiseEvents(new E6(), new E7()));

                migrations = Seq.Create(Replace <E2> .With <E6>()).ToList();
                ClearEventstoreCache(container);

                migratedHistory = container.ExecuteUnitOfWorkInIsolatedScope(() => session().Get <TestAggregate>(id).History);
                var expectedAfterReplacingE2WithE6 = TestAggregate.FromEvents(container.Resolve <IUtcTimeTimeSource>(), id, Seq.OfTypes <Ec1, E5, E6, E3, E4, E6, E7>()).History;
                AssertStreamsAreIdentical(expected: expectedAfterReplacingE2WithE6, migratedHistory: migratedHistory, descriptionOfHistory: "migrated history");

                historyAfterPersistingButBeforeReload = container.ExecuteUnitOfWorkInIsolatedScope(
                    () =>
                {
                    eventStore().PersistMigrations();
                    return(session().Get <TestAggregate>(id).History);
                });

                AssertStreamsAreIdentical(expected: expectedAfterReplacingE2WithE6, migratedHistory: historyAfterPersistingButBeforeReload, descriptionOfHistory: "migrated, persisted");
                historyAfterPersistingAndReloading = container.ExecuteUnitOfWorkInIsolatedScope(() => session().Get <TestAggregate>(id).History);
                AssertStreamsAreIdentical(expected: expectedAfterReplacingE2WithE6, migratedHistory: historyAfterPersistingAndReloading, descriptionOfHistory: "migrated, persisted, reloaded");

                migrations = Seq.Empty <IEventMigration>().ToList();
                container.ExecuteUnitOfWorkInIsolatedScope(() => session().Get <TestAggregate>(id).RaiseEvents(new E8(), new E9()));
                historyAfterPersistingAndReloading = container.ExecuteUnitOfWorkInIsolatedScope(() => session().Get <TestAggregate>(id).History);
                var expectedAfterReplacingE2WithE6AndRaisingE8E9 = TestAggregate.FromEvents(container.Resolve <IUtcTimeTimeSource>(), id, Seq.OfTypes <Ec1, E5, E6, E3, E4, E6, E7, E8, E9>()).History;
                AssertStreamsAreIdentical(expected: expectedAfterReplacingE2WithE6AndRaisingE8E9, migratedHistory: historyAfterPersistingAndReloading, descriptionOfHistory: "migrated, persisted, reloaded");
            }
        }
        private static void RunScenarioWithEventStoreType
            (MigrationScenario scenario, Type eventStoreType, WindsorContainer container, IList <IEventMigration> migrations, int indexOfScenarioInBatch)
        {
            var startingMigrations = migrations.ToList();

            migrations.Clear();

            var timeSource = container.Resolve <DummyTimeSource>();

            IReadOnlyList <IAggregateRootEvent> eventsInStoreAtStart;

            using (container.BeginScope()) //Why is this needed? It fails without it but I do not understand why...
            {
                var eventStore = container.Resolve <IEventStore>();
                eventsInStoreAtStart = eventStore.ListAllEventsForTestingPurposesAbsolutelyNotUsableForARealEventStoreOfAnySize();
            }

            Console.WriteLine($"\n########Running Scenario {indexOfScenarioInBatch}");

            var original = TestAggregate.FromEvents(DummyTimeSource.Now, scenario.AggregateId, scenario.OriginalHistory).History.ToList();

            Console.WriteLine($"Original History: ");
            original.ForEach(e => Console.WriteLine($"      {e}"));
            Console.WriteLine();

            var initialAggregate = TestAggregate.FromEvents(timeSource, scenario.AggregateId, scenario.OriginalHistory);
            var expected         = TestAggregate.FromEvents(timeSource, scenario.AggregateId, scenario.ExpectedHistory).History.ToList();
            var expectedCompleteEventstoreStream = eventsInStoreAtStart.Concat(expected).ToList();

            Console.WriteLine($"Expected History: ");
            expected.ForEach(e => Console.WriteLine($"      {e}"));
            Console.WriteLine();

            var initialAggregate2 = TestAggregate.FromEvents(timeSource, scenario.AggregateId, scenario.OriginalHistory);

            timeSource.UtcNow += 1.Hours();//Bump clock to ensure that times will be be wrong unless the time from the original events are used..

            Console.WriteLine("Doing pure in memory ");
            IReadOnlyList <IAggregateRootEvent> otherHistory = SingleAggregateInstanceEventStreamMutator.MutateCompleteAggregateHistory(
                scenario.Migrations,
                initialAggregate2.History.Cast <AggregateRootEvent>().ToList());

            AssertStreamsAreIdentical(expected, otherHistory, $"Direct call to SingleAggregateInstanceEventStreamMutator.MutateCompleteAggregateHistory");

            container.ExecuteUnitOfWorkInIsolatedScope(() => container.Resolve <IEventStoreSession>().Save(initialAggregate));
            migrations.AddRange(startingMigrations);
            var migratedHistory = container.ExecuteUnitOfWorkInIsolatedScope(() => container.Resolve <IEventStoreSession>().Get <TestAggregate>(initialAggregate.Id)).History;

            AssertStreamsAreIdentical(expected, migratedHistory, "Loaded un-cached aggregate");

            var migratedCachedHistory = container.ExecuteUnitOfWorkInIsolatedScope(() => container.Resolve <IEventStoreSession>().Get <TestAggregate>(initialAggregate.Id)).History;

            AssertStreamsAreIdentical(expected, migratedCachedHistory, "Loaded cached aggregate");


            Console.WriteLine("  Streaming all events in store");
            var streamedEvents = container.ExecuteUnitOfWorkInIsolatedScope(() => container.Resolve <IEventStore>().ListAllEventsForTestingPurposesAbsolutelyNotUsableForARealEventStoreOfAnySize().ToList());

            AssertStreamsAreIdentical(expectedCompleteEventstoreStream, streamedEvents, "Streaming all events in store");

            Console.WriteLine("  Persisting migrations");
            using (container.BeginScope())
            {
                container.Resolve <IEventStore>().PersistMigrations();
            }

            migratedHistory = container.ExecuteUnitOfWorkInIsolatedScope(() => container.Resolve <IEventStoreSession>().Get <TestAggregate>(initialAggregate.Id)).History;
            AssertStreamsAreIdentical(expected, migratedHistory, "Loaded aggregate");

            Console.WriteLine("Streaming all events in store");
            streamedEvents = container.ExecuteUnitOfWorkInIsolatedScope(() => container.Resolve <IEventStore>().ListAllEventsForTestingPurposesAbsolutelyNotUsableForARealEventStoreOfAnySize().ToList());
            AssertStreamsAreIdentical(expectedCompleteEventstoreStream, streamedEvents, "Streaming all events in store");


            Console.WriteLine("  Disable all migrations so that none are used when reading from the event stores");
            migrations.Clear();

            migratedHistory = container.ExecuteUnitOfWorkInIsolatedScope(() => container.Resolve <IEventStoreSession>().Get <TestAggregate>(initialAggregate.Id)).History;
            AssertStreamsAreIdentical(expected, migratedHistory, "loaded aggregate");

            Console.WriteLine("Streaming all events in store");
            streamedEvents = container.ExecuteUnitOfWorkInIsolatedScope(() => container.Resolve <IEventStore>().ListAllEventsForTestingPurposesAbsolutelyNotUsableForARealEventStoreOfAnySize().ToList());
            AssertStreamsAreIdentical(expectedCompleteEventstoreStream, streamedEvents, "Streaming all events in store");

            if (eventStoreType == typeof(SqlServerEventStore))
            {
                Console.WriteLine("Clearing sql server eventstore cache");
                container.ExecuteUnitOfWorkInIsolatedScope(() => ((SqlServerEventStore)container.Resolve <IEventStore>()).ClearCache());
                migratedHistory = container.ExecuteUnitOfWorkInIsolatedScope(() => container.Resolve <IEventStoreSession>().Get <TestAggregate>(initialAggregate.Id)).History;
                AssertStreamsAreIdentical(expected, migratedHistory, "Loaded aggregate");

                Console.WriteLine("Streaming all events in store");
                streamedEvents = container.ExecuteUnitOfWorkInIsolatedScope(() => container.Resolve <IEventStore>().ListAllEventsForTestingPurposesAbsolutelyNotUsableForARealEventStoreOfAnySize().ToList());
                AssertStreamsAreIdentical(expectedCompleteEventstoreStream, streamedEvents, "Streaming all events in store");
            }
        }