/// <summary> /// Gets the top level feature graphs, that is the graphs /// for features that do not have a parent feature. /// </summary> /// <returns> /// A collection of <see cref="FeatureGraph"/> instances representing /// the dependency graphs for the unparented features. /// </returns> public async Task <IEnumerable <FeatureGraph> > GetTopLevelFeatureGraphsAsync() { var features = (await _featureManager.GetAllDbFeatures()).ToList(); var invocations = (await _analysisReportManager.GetAllDbInvocations()).ToList(); _logger.LogInformation("Calculating top level feature graphs for {FeatureCount} features and {InvocationCount} invocations.", features.Count, invocations.Count); var invocationFeatures = (from invocation in invocations select new { Invocation = invocation, Features = features.Where(f => f.DirectInvocationSignatures != null && f.DirectInvocationSignatures.Intersect(invocation.InvokedSignatures).Any()).ToList() }).ToList(); var featuresInvocations = (from feature in features select new { Feature = feature, Invocations = invocationFeatures.Where(i => feature.DirectInvocationSignatures != null && feature.DirectInvocationSignatures.Contains(i.Invocation.Signature)) }).ToList(); var featureGraphs = new Dictionary <DbFeature, FeatureGraph>(); foreach (var feature in featuresInvocations) { var featureGraph = new FeatureGraph { FeatureName = feature.Feature.Title, ProductName = feature.Feature.Product, GroupName = feature.Feature.Group, Tags = feature.Feature.Tags, Version = feature.Feature.Version, DependsOn = new List <FeatureGraph>() }; featureGraphs.Add(feature.Feature, featureGraph); } var unparentedGraphs = new List <FeatureGraph>(featureGraphs.Values); foreach (var feature in featuresInvocations) { var featureGraph = featureGraphs[feature.Feature]; var dependencies = feature.Invocations.SelectMany(i => i.Features).Select(f => featureGraphs[f]).ToList(); dependencies.ForEach(f => unparentedGraphs.Remove(f)); featureGraph.DependsOn.AddRange(dependencies.Distinct()); } return(unparentedGraphs); }
public async Task VerifyFeatureGraphsCanBeDiscovered() { // Arrange var callingFeature = CreateDbFeature("CallingFeature", "SomeClass.Foo()"); var calledFeature = CreateDbFeature("CalledFeature", "SomeOtherClass.Bar()"); _featureManager.GetAllDbFeatures().Returns(new[] { callingFeature, calledFeature }); _analysisReportManager.GetAllDbInvocations().Returns(new DbInvocation[] { new DbInvocation() { Signature = "SomeClass.Foo()", InvokedSignatures = new [] { "SomeClass.Foo(System.String)", "SomeOtherClass.Bar()" } }, new DbInvocation() { Signature = "SomeOtherClass.Bar()", InvokedSignatures = new [] { "SomeOtherClass.JuiceBar()" } } }); // Act var target = new DependencyManager(_featureManager, _analysisReportManager, _logger); var graphs = (await target.GetTopLevelFeatureGraphsAsync()).ToList(); // Assert graphs.Count.ShouldBe(1); graphs[0].FeatureName.ShouldBe("CallingFeature"); graphs[0].DependsOn.Count.ShouldBe(1); graphs[0].DependsOn[0].FeatureName.ShouldBe("CalledFeature"); }