Exemplo n.º 1
0
        private SeedingReport(SeedBucketInfo seedBucketInfo, SeedingPlan?seedingPlan, IReadOnlyCollection <SingleSeedSeedingReport> singleSeedSeedingResults, SeedingStatus status)
        {
            System.Diagnostics.Debug.Assert(status != SeedingStatus.SeedBucketHasErrors ||
                                            (status == SeedingStatus.SeedBucketHasErrors &&
                                             seedBucketInfo.HasAnyErrors &&
                                             seedingPlan == null &&
                                             singleSeedSeedingResults.Count == 0));

            System.Diagnostics.Debug.Assert(status != SeedingStatus.BuildingServiceProviderFailed ||
                                            (status == SeedingStatus.BuildingServiceProviderFailed &&
                                             !seedBucketInfo.HasAnyErrors &&
                                             seedingPlan != null &&
                                             singleSeedSeedingResults.Count == 0));

            System.Diagnostics.Debug.Assert(status != SeedingStatus.SeedingSingleSeedFailed ||
                                            (status == SeedingStatus.SeedingSingleSeedFailed &&
                                             !seedBucketInfo.HasAnyErrors &&
                                             seedingPlan != null &&
                                             singleSeedSeedingResults.Count(result => result.Status == SingleSeedSeedingStatus.Failed) == 1 &&
                                             singleSeedSeedingResults.Last().Status == SingleSeedSeedingStatus.Failed));

            System.Diagnostics.Debug.Assert(status != SeedingStatus.Succeeded ||
                                            (status == SeedingStatus.Succeeded &&
                                             !seedBucketInfo.HasAnyErrors &&
                                             seedingPlan != null &&

                                             // We can have a situation that there is no seeds to seed. This is fine.
                                             singleSeedSeedingResults.All(result => result.Status != SingleSeedSeedingStatus.Failed)));

            SeedBucketInfo           = seedBucketInfo;
            SeedingPlan              = seedingPlan;
            SingleSeedSeedingResults = singleSeedSeedingResults;
            Status = status;
        }
Exemplo n.º 2
0
        public static SeedingPlan CreateFor(SeedBucketInfo seedBucketInfo)
        {
            System.Diagnostics.Debug.Assert(!seedBucketInfo.HasAnyErrors);

            var seedingSteps = new List <SeedInfo>(seedBucketInfo.ContainedSeedables.OfType <SeedInfo>().Count());

            foreach (var seedableInfo in seedBucketInfo.ContainedSeedables)
            {
                RecursivelyBuildSeedingSteps(seedableInfo);
            }

            return(new SeedingPlan(seedingSteps));

            void RecursivelyBuildSeedingSteps(SeedableInfo seedableInfo)
            {
                if (seedableInfo is SeedInfo seedInfo && seedingSteps.Contains(seedInfo))
                {
                    return;
                }

                foreach (var requiredSeedable in seedableInfo.RequiredSeedables)
                {
                    RecursivelyBuildSeedingSteps(requiredSeedable);
                }

                // We have to add the seed info to the seeding plan at the
                // tail of the recursion so that the required seedables get
                // executed first (end up on the front of the seeding plan).
                if (seedableInfo is SeedInfo)
                {
                    seedingSteps.Add((SeedInfo)seedableInfo);
                }
            }
        }
Exemplo n.º 3
0
 public static SeedingReport CreateForSucceeded(SeedBucketInfo seedBucketInfo, SeedingPlan seedingPlan, IReadOnlyCollection <SingleSeedSeedingReport> singleSeedSeedingResults)
 {
     return(new SeedingReport
            (
                seedBucketInfo,
                seedingPlan,
                singleSeedSeedingResults,
                SeedingStatus.Succeeded
            ));
 }
Exemplo n.º 4
0
 public static SeedingReport CreateForBuildingServiceProviderFailed(SeedBucketInfo seedBucketInfo, SeedingPlan seedingPlan)
 {
     return(new SeedingReport
            (
                seedBucketInfo,
                seedingPlan,
                Array.Empty <SingleSeedSeedingReport>(),
                SeedingStatus.BuildingServiceProviderFailed
            ));
 }
Exemplo n.º 5
0
 public static SeedingReport CreateForSeedBucketHasErrors(SeedBucketInfo seedBucketInfo)
 {
     return(new SeedingReport
            (
                seedBucketInfo,
                null,
                Array.Empty <SingleSeedSeedingReport>(),
                SeedingStatus.SeedBucketHasErrors
            ));
 }
Exemplo n.º 6
0
        public void ReturnsᅠexpectedᅠfullyᅠpopulatedᅠSeedBucketInfoᅠthatᅠdoesᅠnotᅠrequireᅠotherᅠseedᅠbuckets()
        {
            const string seedBucketTypeName     = "TestSeedBucket";
            const string seedBucketFriendlyName = "Test seed bucket friendly name";
            const string seedBucketDescription  = "Test seed bucket description";

            var seedBucket = assemblyBuilder
                             .AddSeedBucket(seedBucketTypeName, seedBucketFriendlyName, seedBucketDescription)
                             .AddSeed("FirstSeed")
                             .AddSeed("SecondSeed", "Second seed friendly name", "Second seed description", true, false, false, null, "FirstSeed")
                             .AddSeed("ThirdSeed", "Third seed friendly name", "Third seed description", true, false, false, null, "FirstSeed", "SecondSeed")
                             .AddScenario("FirstScenario", requires: "FirstSeed")
                             .AddScenario("SecondScenario", "Second scenario friendly name", "Second scenario description", "FirstSeed", "SecondSeed")
                             .AddScenario("ThirdScenario", null, null, "FirstSeed", "SecondSeed", "FirstScenario", "SecondScenario")
                             .AddSeed("FourthSeed", requires: "ThirdScenario")
                             .BuildAssembly()
                             .GetSeedBucket(seedBucketTypeName);
            var type = seedBucket.GetType();

            var expected = new SeedBucketInfo
                           (
                type,
                type,
                type.FullName,
                seedBucketFriendlyName,
                seedBucketDescription,
                containedSeedablesExtractor.ExtractFrom(type),
                Array.Empty <Error>()
                           );

            var metaInfo = seedBucket.GetMetaInfo();

            metaInfo
            .Should()
            .BeEquivalentTo(expected, options => options.IgnoringCyclicReferences().WithoutStrictOrdering());

            metaInfo
            .ContainedSeedables
            .Select(seedable => seedable.SeedBucket)
            .Distinct()
            .Should()
            .HaveCount(1);

            metaInfo
            .ContainedSeedables
            .Select(seedable => seedable.SeedBucket)
            .First()
            .Should()
            .BeSameAs(metaInfo);
        }
Exemplo n.º 7
0
        public static SeedingPlan CreateFor(SeedBucketInfo seedBucketInfo, ISeedableFilter filter)
        {
            System.Diagnostics.Debug.Assert(!seedBucketInfo.HasAnyErrors);

            if (!seedBucketInfo.ContainedSeedables.Any(seedable => filter.Accepts(seedable)))
            {
                return(Empty);
            }

            IEnumerable <SeedableInfo> alwaysRequiredSeeds = seedBucketInfo.ContainedSeedables.OfType <SeedInfo>().Where(seed => seed.IsAlwaysRequired);
            var filteredSeedables = seedBucketInfo.ContainedSeedables.Where(seedable => filter.Accepts(seedable));

            // Always required seeds must be at the beginning so that we ensure that they are always created first.
            var seedablesToSeed = alwaysRequiredSeeds.Union(filteredSeedables);

            var seedingSteps = new List <SeedInfo>(seedBucketInfo.ContainedSeedables.OfType <SeedInfo>().Count());

            foreach (var seedableInfo in seedablesToSeed)
            {
                RecursivelyBuildSeedingSteps(seedableInfo);
            }

            return(new SeedingPlan(seedingSteps));

            void RecursivelyBuildSeedingSteps(SeedableInfo seedableInfo)
            {
                if (seedableInfo is SeedInfo seedInfo && seedingSteps.Contains(seedInfo))
                {
                    return;
                }

                foreach (var requiredSeedable in seedableInfo.RequiredSeedables)
                {
                    RecursivelyBuildSeedingSteps(requiredSeedable);
                }

                // We have to add the seed info to the seeding plan at the
                // tail of the recursion so that the required seedables get
                // executed first (end up on the front of the seeding plan).
                if (seedableInfo is SeedInfo)
                {
                    seedingSteps.Add((SeedInfo)seedableInfo);
                }
            }
        }
Exemplo n.º 8
0
        public void ReturnsᅠexpectedᅠminimalᅠSeedBucketInfo()
        {
            var seedBucket = assemblyBuilder.AddSeedBucket().BuildAssembly().GetSeedBucket();
            var type       = seedBucket.GetType();

            var expected = new SeedBucketInfo
                           (
                type,
                type,
                type.FullName,
                type.Name.Humanize(),
                string.Empty,
                Array.Empty <SeedableInfo>(),
                Array.Empty <Error>()
                           );

            seedBucket.GetMetaInfo().Should().BeEquivalentTo(expected);
        }
Exemplo n.º 9
0
        private async Task <SeedingReport> Seed(SeedBucketInfo seedBucketInfo, SeedBucketStartup?seedBucketStartup, ISeedableFilter filter)
        {
            if (seedBucketInfo.HasAnyErrors)
            {
                return(SeedingReport.CreateForSeedBucketHasErrors(seedBucketInfo));
            }

            var seedingPlan = SeedingPlan.CreateFor(seedBucketInfo, filter);

            // TODO: Check if the seeding plan is empty and return appropriate report.
            //       In the report show the used filter. "... no seeds or scenarios that satisfied the given filter: ...". Add the FriendlyDescription property to the ISeedablesFilter.

            return(await SeedSeedingPlan());

            async Task <SeedingReport> SeedSeedingPlan()
            {
                var singleSeedSeedingResults = new List <SingleSeedSeedingReport>();

                IServiceCollection serviceCollection = new ServiceCollection(); // TODO: We should have more of them. Think about lifecycle of the engine services, services in the different stages in the execution, etc.

                serviceCollection.AddSingleton(outputSink);
                try
                {
                    // TODO: Add creation of SeedingStartup and registration of services.
                    if (seedBucketStartup != null)
                    {
                        outputSink.WriteVerboseMessage($"Configuring service collection");

                        seedBucketStartup.ConfigureServices(serviceCollection);

                        // TODO: Check that the configuration does not override IOutputSink. Only the engine can add it. It must be singleton and the same one we have here.

                        outputSink.WriteVerboseMessage($"Initializing seeding");

                        using (var serviceScope = serviceCollection.BuildServiceProvider().CreateScope())
                        {
                            seedBucketStartup.InitializeSeeding(serviceScope.ServiceProvider);
                        }
                    }

                    // TODO: Add finer granulation of errors and seeding result - CreatingSeedingStartupFailed.
                }
                catch (Exception exception)
                {
                    outputSink.WriteError(exception.ToString()); // TODO: Output sink for exceptions.

                    return(SeedingReport.CreateForBuildingServiceProviderFailed(seedBucketInfo, seedingPlan));
                }

                var serviceProvider = serviceCollection.BuildServiceProvider();

                SeedInfo?currentSeedInfo;
                int      seedingStepNumber;

                for (int i = 0; i < seedingPlan.SeedingSteps.Count; i++)
                {
                    currentSeedInfo   = seedingPlan.SeedingSteps[i];
                    seedingStepNumber = i + 1;
                    try
                    {
                        bool hasSeeded;
                        using (var serviceScope = serviceProvider.CreateScope())
                        {
                            hasSeeded = await SeedSingleSeed(seedingStepNumber, serviceScope.ServiceProvider, currentSeedInfo);
                        }

                        singleSeedSeedingResults.Add(new SingleSeedSeedingReport(hasSeeded ? SingleSeedSeedingStatus.Seeded : SingleSeedSeedingStatus.Skipped, currentSeedInfo));
                    }
                    catch (Exception exception)
                    {
                        outputSink.WriteError(exception.ToString()); // TODO: Output sink that supports exceptions.

                        // TODO: Add finer granulation of errors and seeding result - CreatingSeedFailed.
                        // TODO: Add seed contract violation.
                        singleSeedSeedingResults.Add(new SingleSeedSeedingReport(SingleSeedSeedingStatus.Failed, currentSeedInfo));
                        return(SeedingReport.CreateForSeedingSingleSeedFailed(seedBucketInfo, seedingPlan, singleSeedSeedingResults));
                    }
                }

                outputSink.WriteConfirmation($"Seeding completed");

                return(SeedingReport.CreateForSucceeded(seedBucketInfo, seedingPlan, singleSeedSeedingResults));

                // Returns true if Seed() is called or false if the seed HasAlreadyYielded().
                async Task <bool> SeedSingleSeed(int seedingStep, IServiceProvider serviceProvider, SeedInfo seedInfo)
                {
                    System.Diagnostics.Debug.Assert(seedingStep > 0);

                    outputSink.WriteVerboseMessage($"Creating seed {seedInfo.FriendlyName}");

                    // TODO: Check if seedInfo.Type exists. Where to check that? Seeding should work only if Type exists. Where to add those checks?
                    var seed = (ISeed)ActivatorUtilities.GetServiceOrCreateInstance(serviceProvider, seedInfo.Type);

                    // TODO: Create YieldOf objects and assign them to YieldOf properties.
                    // TODO: Think what to do if the Type or PropertyInfo is null.
                    foreach (var requiredYield in seedInfo.RequiredYields)
                    {
                        // TODO: Check if it is already created. If we have two properties of the same yield type. This must never be the case it should be an error in the seed definition.
                        // TOOD: Yield access property must be public or internal or protected. It also must have non private setter.

                        var yieldingSeed = (ISeed)ActivatorUtilities.GetServiceOrCreateInstance(serviceProvider, requiredYield.YieldingSeed.Type);

                        var yield = ActivatorUtilities.GetServiceOrCreateInstance(serviceProvider, requiredYield.Type);

                        var seedPropertyOnYield = yield.GetType().GetProperty("Seed", BindingFlags.NonPublic | BindingFlags.FlattenHierarchy | BindingFlags.Instance);

                        // seedPropertyOnYield.SetValue(yield, yieldingSeed, BindingFlags.NonPublic | BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.SetProperty, null, null, null);
                        seedPropertyOnYield.SetValue(yield, yieldingSeed);

                        requiredYield.YieldAccessProperty !.SetValue(seed, yield);
                    }

                    if (await seed.HasAlreadyYielded())
                    {
                        outputSink.WriteMessage($"Skipping {seedInfo.FriendlyName}");
                        return(false);
                    }

                    outputSink.WriteMessage($"Seeding {seedInfo.FriendlyName}");

                    await seed.Seed();

                    outputSink.WriteMessage($"Seeding {seedInfo.FriendlyName} completed");

                    return(true);
                }
            }
        }