From 12ad6c93afae5cca248dc10ea47c692b1bb2e137 Mon Sep 17 00:00:00 2001 From: Roberto Alves Date: Fri, 20 Oct 2023 10:13:30 +0100 Subject: [PATCH 1/5] Refactor the CherryPickRunner to allow for the possibility to CherryPick on a specific engineering model and iteration. --- .../Utilities/CherryPick/CherryPickRunner.cs | 104 +++++++++++++----- .../Utilities/CherryPick/ICherryPickRunner.cs | 14 ++- 2 files changed, 90 insertions(+), 28 deletions(-) diff --git a/COMET.Web.Common/Utilities/CherryPick/CherryPickRunner.cs b/COMET.Web.Common/Utilities/CherryPick/CherryPickRunner.cs index c9bc990c..50636ee1 100644 --- a/COMET.Web.Common/Utilities/CherryPick/CherryPickRunner.cs +++ b/COMET.Web.Common/Utilities/CherryPick/CherryPickRunner.cs @@ -25,10 +25,13 @@ namespace COMET.Web.Common.Utilities.CherryPick { + using CDP4Common.CommonData; using CDP4Common.SiteDirectoryData; using COMET.Web.Common.Services.SessionManagement; + using Thing = CDP4Common.DTO.Thing; + /// /// Utility class that could run CherryPick query for /// @@ -37,12 +40,12 @@ public class CherryPickRunner : ICherryPickRunner /// /// Gets the collection of /// - private readonly List NeedCherryPicked = new(); + private readonly List needCherryPicked = new(); /// /// Gets the /// - protected readonly ISessionService SessionService; + private readonly ISessionService sessionService; /// /// Initializes a new @@ -50,7 +53,7 @@ public class CherryPickRunner : ICherryPickRunner /// The public CherryPickRunner(ISessionService sessionService) { - this.SessionService = sessionService; + this.sessionService = sessionService; } /// @@ -61,49 +64,100 @@ public CherryPickRunner(ISessionService sessionService) /// /// Initializes the internal properties /// - /// A collection of - public void InitializeProperties(IEnumerable needCherryPicked) + /// A collection of + public void InitializeProperties(IEnumerable needCherryPickedData) { - this.NeedCherryPicked.Clear(); - this.NeedCherryPicked.AddRange(needCherryPicked); + this.needCherryPicked.Clear(); + this.needCherryPicked.AddRange(needCherryPickedData); } /// - /// Runs the cherrypick features based on data required from + /// Gets the defined category ids to be used as a filter /// - /// A - public async Task RunCherryPick() + /// A with the IDs of the categories to filter on + private IEnumerable GetCategoryIdsForCherryPick() { - if (this.IsCherryPicking) - { - return; - } - - this.IsCherryPicking = true; - var classKinds = this.NeedCherryPicked.SelectMany(x => x.ClassKindsOfInterest).Distinct(); - var categoriesName = this.NeedCherryPicked.SelectMany(x => x.CategoriesOfInterest).Distinct(); - + var categoriesName = this.needCherryPicked.SelectMany(x => x.CategoriesOfInterest).Distinct(); var categories = new List(); - foreach (var referenceDataLibrary in this.SessionService.Session.RetrieveSiteDirectory().AvailableReferenceDataLibraries()) + foreach (var referenceDataLibrary in this.sessionService.Session.RetrieveSiteDirectory().AvailableReferenceDataLibraries()) { categories.AddRange(referenceDataLibrary.DefinedCategory .Where(x => categoriesName.Contains(x.Name)) .ToList()); } - var availableEngineeringModelSetups = this.SessionService.GetParticipantModels().ToList(); + var categoriesIds = categories.Select(x => x.Iid); + return categoriesIds; + } - var cherryPicks = availableEngineeringModelSetups.Select(engineeringModelSetup => this.SessionService.Session.CherryPick(engineeringModelSetup.EngineeringModelIid, engineeringModelSetup.IterationSetup.Single(x => x.FrozenOn == null).IterationIid, classKinds, categories.Select(x => x.Iid))) - .ToList(); + /// + /// Gets the defined class kinds to be used as a filter + /// + /// A with the to filter on + private IEnumerable GetClassKindsForCherryPick() + { + return this.needCherryPicked.SelectMany(x => x.ClassKindsOfInterest).Distinct(); + } + + /// + /// Processes the retrieved cherry picked data + /// + /// The cherry picked data + private void ProcessCherryPickedData(IReadOnlyCollection> cherryPickedData) + { + foreach (var needCherryPickedData in this.needCherryPicked) + { + needCherryPickedData.ProcessCherryPickedData(cherryPickedData); + } + } + + /// + /// Runs the cherrypick features based on data required from + /// + /// A + public async Task RunCherryPickAsync() + { + if (this.IsCherryPicking) + { + return; + } + this.IsCherryPicking = true; + + var classKinds = this.GetClassKindsForCherryPick(); + var categoriesIds = this.GetCategoryIdsForCherryPick(); + + var availableEngineeringModelSetups = this.sessionService.GetParticipantModels().ToList(); + var cherryPicks = availableEngineeringModelSetups.Select(engineeringModelSetup => this.sessionService.Session.CherryPick(engineeringModelSetup.EngineeringModelIid, engineeringModelSetup.IterationSetup.Single(x => x.FrozenOn == null).IterationIid, classKinds, categoriesIds)).ToList(); var results = (await Task.WhenAll(cherryPicks)).Where(x => x.Any()).ToList(); - foreach (var needCherryPickedData in this.NeedCherryPicked) + this.ProcessCherryPickedData(results); + this.IsCherryPicking = false; + } + + /// + /// Runs the cherrypick features for a specific Engineering Model and Iteration, based on data required from + /// + /// The engineering model Id that we want to cherry pick from + /// The iteration Id that we want to cherry pick from + /// A + public async Task RunSingleCherryPickAsync(Guid engineeringModelId, Guid iterationId) + { + if (this.IsCherryPicking) { - needCherryPickedData.ProcessCherryPickedData(results); + return; } + this.IsCherryPicking = true; + + var classKinds = this.GetClassKindsForCherryPick(); + var categoriesIds = this.GetCategoryIdsForCherryPick(); + + var cherryPicks = await this.sessionService.Session.CherryPick(engineeringModelId, iterationId, classKinds, categoriesIds); + + this.ProcessCherryPickedData(new []{ cherryPicks }); + this.IsCherryPicking = false; } } diff --git a/COMET.Web.Common/Utilities/CherryPick/ICherryPickRunner.cs b/COMET.Web.Common/Utilities/CherryPick/ICherryPickRunner.cs index aa8c4e32..db298ad4 100644 --- a/COMET.Web.Common/Utilities/CherryPick/ICherryPickRunner.cs +++ b/COMET.Web.Common/Utilities/CherryPick/ICherryPickRunner.cs @@ -38,13 +38,21 @@ public interface ICherryPickRunner /// /// Initializes the internal properties /// - /// A collection of - void InitializeProperties(IEnumerable needCherryPicked); + /// A collection of + void InitializeProperties(IEnumerable needCherryPickedData); + /// + /// Runs the cherrypick features for a specific Engineering Model and Iteration, based on data required from + /// + /// The engineering model Id that we want to cherry pick from + /// The iteration Id that we want to cherry pick from + /// A + Task RunSingleCherryPickAsync(Guid engineeringModelId, Guid iterationId); + /// /// Runs the cherrypick features based on data required from /// /// A - Task RunCherryPick(); + Task RunCherryPickAsync(); } } From 06d913983d70a216a9a5d0abb81d65b4b632fe3d Mon Sep 17 00:00:00 2001 From: Roberto Alves Date: Fri, 20 Oct 2023 10:13:33 +0100 Subject: [PATCH 2/5] Update CherryPickRunnerTestFixture.cs --- .../CherryPick/CherryPickRunnerTestFixture.cs | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/COMET.Web.Common.Tests/Utilities/CherryPick/CherryPickRunnerTestFixture.cs b/COMET.Web.Common.Tests/Utilities/CherryPick/CherryPickRunnerTestFixture.cs index 1b460b8f..f3bb06ec 100644 --- a/COMET.Web.Common.Tests/Utilities/CherryPick/CherryPickRunnerTestFixture.cs +++ b/COMET.Web.Common.Tests/Utilities/CherryPick/CherryPickRunnerTestFixture.cs @@ -28,7 +28,8 @@ namespace COMET.Web.Common.Tests.Utilities.CherryPick { using NUnit.Framework; - using CDP4Common.SiteDirectoryData; + using SiteDirectory = CDP4Common.SiteDirectoryData.SiteDirectory; + using CDP4Common.DTO; using COMET.Web.Common.Services.SessionManagement; using COMET.Web.Common.Utilities.CherryPick; @@ -61,12 +62,24 @@ public async Task VerifyProperties() var propertyInfo = typeof(CherryPickRunner).GetProperty("IsCherryPicking", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public); propertyInfo?.SetValue(this.viewModel, true, null); - await this.viewModel.RunCherryPick(); - this.needCherryPickedData.Verify(x => x.ProcessCherryPickedData(Moq.It.IsAny>>()), Times.Never); + await this.viewModel.RunCherryPickAsync(); + this.needCherryPickedData.Verify(x => x.ProcessCherryPickedData(Moq.It.IsAny>>()), Times.Never); propertyInfo?.SetValue(this.viewModel, false, null); - await this.viewModel.RunCherryPick(); - this.needCherryPickedData.Verify(x => x.ProcessCherryPickedData(Moq.It.IsAny>>()), Times.Once); + await this.viewModel.RunCherryPickAsync(); + this.needCherryPickedData.Verify(x => x.ProcessCherryPickedData(Moq.It.IsAny>>()), Times.Once); + + this.needCherryPickedData.Invocations.Clear(); + + var engineeringModelId = Guid.NewGuid(); + var iterationId = Guid.NewGuid(); + propertyInfo?.SetValue(this.viewModel, true, null); + await this.viewModel.RunSingleCherryPickAsync(engineeringModelId, iterationId); + this.needCherryPickedData.Verify(x => x.ProcessCherryPickedData(Moq.It.IsAny>>()), Times.Never); + + propertyInfo?.SetValue(this.viewModel, false, null); + await this.viewModel.RunSingleCherryPickAsync(engineeringModelId, iterationId); + this.needCherryPickedData.Verify(x => x.ProcessCherryPickedData(Moq.It.IsAny>>()), Times.Once); } } } From fecfda7bd40a44fd372e2dcf481028583dc476f6 Mon Sep 17 00:00:00 2001 From: Roberto Alves Date: Fri, 20 Oct 2023 11:18:32 +0100 Subject: [PATCH 3/5] Refactor the methods so that we use a Tuple for the RunCherryPick methods instead of a single specific parameter. --- .../CherryPick/CherryPickRunnerTestFixture.cs | 4 +- .../Utilities/CherryPick/CherryPickRunner.cs | 100 +++++++----------- .../Utilities/CherryPick/ICherryPickRunner.cs | 13 ++- 3 files changed, 47 insertions(+), 70 deletions(-) diff --git a/COMET.Web.Common.Tests/Utilities/CherryPick/CherryPickRunnerTestFixture.cs b/COMET.Web.Common.Tests/Utilities/CherryPick/CherryPickRunnerTestFixture.cs index f3bb06ec..e931ccfc 100644 --- a/COMET.Web.Common.Tests/Utilities/CherryPick/CherryPickRunnerTestFixture.cs +++ b/COMET.Web.Common.Tests/Utilities/CherryPick/CherryPickRunnerTestFixture.cs @@ -74,11 +74,11 @@ public async Task VerifyProperties() var engineeringModelId = Guid.NewGuid(); var iterationId = Guid.NewGuid(); propertyInfo?.SetValue(this.viewModel, true, null); - await this.viewModel.RunSingleCherryPickAsync(engineeringModelId, iterationId); + await this.viewModel.RunCherryPickAsync(new[] { (engineeringModelId, iterationId)}); this.needCherryPickedData.Verify(x => x.ProcessCherryPickedData(Moq.It.IsAny>>()), Times.Never); propertyInfo?.SetValue(this.viewModel, false, null); - await this.viewModel.RunSingleCherryPickAsync(engineeringModelId, iterationId); + await this.viewModel.RunCherryPickAsync(new[] { (engineeringModelId, iterationId)}); this.needCherryPickedData.Verify(x => x.ProcessCherryPickedData(Moq.It.IsAny>>()), Times.Once); } } diff --git a/COMET.Web.Common/Utilities/CherryPick/CherryPickRunner.cs b/COMET.Web.Common/Utilities/CherryPick/CherryPickRunner.cs index 50636ee1..f728ab2f 100644 --- a/COMET.Web.Common/Utilities/CherryPick/CherryPickRunner.cs +++ b/COMET.Web.Common/Utilities/CherryPick/CherryPickRunner.cs @@ -70,53 +70,23 @@ public void InitializeProperties(IEnumerable needCherryPi this.needCherryPicked.Clear(); this.needCherryPicked.AddRange(needCherryPickedData); } - - /// - /// Gets the defined category ids to be used as a filter - /// - /// A with the IDs of the categories to filter on - private IEnumerable GetCategoryIdsForCherryPick() - { - var categoriesName = this.needCherryPicked.SelectMany(x => x.CategoriesOfInterest).Distinct(); - var categories = new List(); - - foreach (var referenceDataLibrary in this.sessionService.Session.RetrieveSiteDirectory().AvailableReferenceDataLibraries()) - { - categories.AddRange(referenceDataLibrary.DefinedCategory - .Where(x => categoriesName.Contains(x.Name)) - .ToList()); - } - - var categoriesIds = categories.Select(x => x.Iid); - return categoriesIds; - } - - /// - /// Gets the defined class kinds to be used as a filter - /// - /// A with the to filter on - private IEnumerable GetClassKindsForCherryPick() - { - return this.needCherryPicked.SelectMany(x => x.ClassKindsOfInterest).Distinct(); - } - + /// - /// Processes the retrieved cherry picked data + /// Runs the cherrypick features based on data required from /// - /// The cherry picked data - private void ProcessCherryPickedData(IReadOnlyCollection> cherryPickedData) + /// A + public async Task RunCherryPickAsync() { - foreach (var needCherryPickedData in this.needCherryPicked) - { - needCherryPickedData.ProcessCherryPickedData(cherryPickedData); - } + var availableEngineeringModelSetups = this.sessionService.GetParticipantModels().ToList(); + var engineeringModelAndIterationIdTuple = availableEngineeringModelSetups.Select(x => (x.Iid, x.IterationSetup.Single(c => c.FrozenOn == null).Iid)); + await this.RunCherryPickAsync(engineeringModelAndIterationIdTuple); } /// - /// Runs the cherrypick features based on data required from + /// Runs the cherrypick features based on data required from /// /// A - public async Task RunCherryPickAsync() + public async Task RunCherryPickAsync(IEnumerable<(Guid engineeringModelId, Guid iterationId)> ids) { if (this.IsCherryPicking) { @@ -124,41 +94,49 @@ public async Task RunCherryPickAsync() } this.IsCherryPicking = true; - var classKinds = this.GetClassKindsForCherryPick(); - var categoriesIds = this.GetCategoryIdsForCherryPick(); - - var availableEngineeringModelSetups = this.sessionService.GetParticipantModels().ToList(); - var cherryPicks = availableEngineeringModelSetups.Select(engineeringModelSetup => this.sessionService.Session.CherryPick(engineeringModelSetup.EngineeringModelIid, engineeringModelSetup.IterationSetup.Single(x => x.FrozenOn == null).IterationIid, classKinds, categoriesIds)).ToList(); + var categoryIds = this.GetCategoryIdsForCherryPick(); + + var cherryPicks = ids.Select(pair => this.sessionService.Session.CherryPick(pair.engineeringModelId, pair.iterationId, classKinds, categoryIds)) + .ToList(); + var results = (await Task.WhenAll(cherryPicks)).Where(x => x.Any()).ToList(); + + foreach (var needCherryPickedData in this.needCherryPicked) + { + needCherryPickedData.ProcessCherryPickedData(results); + } - this.ProcessCherryPickedData(results); this.IsCherryPicking = false; } /// - /// Runs the cherrypick features for a specific Engineering Model and Iteration, based on data required from + /// Gets the defined category ids to be used as a filter /// - /// The engineering model Id that we want to cherry pick from - /// The iteration Id that we want to cherry pick from - /// A - public async Task RunSingleCherryPickAsync(Guid engineeringModelId, Guid iterationId) + /// A with the IDs of the categories to filter on + private IEnumerable GetCategoryIdsForCherryPick() { - if (this.IsCherryPicking) + var categoriesName = this.needCherryPicked.SelectMany(x => x.CategoriesOfInterest).Distinct(); + var categories = new List(); + + foreach (var referenceDataLibrary in this.sessionService.Session.RetrieveSiteDirectory().AvailableReferenceDataLibraries()) { - return; + categories.AddRange(referenceDataLibrary.DefinedCategory + .Where(x => categoriesName.Contains(x.Name)) + .ToList()); } - this.IsCherryPicking = true; - - var classKinds = this.GetClassKindsForCherryPick(); - var categoriesIds = this.GetCategoryIdsForCherryPick(); - - var cherryPicks = await this.sessionService.Session.CherryPick(engineeringModelId, iterationId, classKinds, categoriesIds); - - this.ProcessCherryPickedData(new []{ cherryPicks }); + var categoriesIds = categories.Select(x => x.Iid); + return categoriesIds; + } - this.IsCherryPicking = false; + /// + /// Gets the defined class kinds to be used as a filter + /// + /// A with the to filter on + private IEnumerable GetClassKindsForCherryPick() + { + return this.needCherryPicked.SelectMany(x => x.ClassKindsOfInterest).Distinct(); } } } diff --git a/COMET.Web.Common/Utilities/CherryPick/ICherryPickRunner.cs b/COMET.Web.Common/Utilities/CherryPick/ICherryPickRunner.cs index db298ad4..84bfb344 100644 --- a/COMET.Web.Common/Utilities/CherryPick/ICherryPickRunner.cs +++ b/COMET.Web.Common/Utilities/CherryPick/ICherryPickRunner.cs @@ -42,17 +42,16 @@ public interface ICherryPickRunner void InitializeProperties(IEnumerable needCherryPickedData); /// - /// Runs the cherrypick features for a specific Engineering Model and Iteration, based on data required from + /// Runs the cherrypick features based on data required from <see cref="CherryPickRunner.NeedCherryPicked" /> /// - /// The engineering model Id that we want to cherry pick from - /// The iteration Id that we want to cherry pick from /// A - Task RunSingleCherryPickAsync(Guid engineeringModelId, Guid iterationId); - + Task RunCherryPickAsync(); + /// - /// Runs the cherrypick features based on data required from + /// Runs the cherrypick features based on data required from and a particular set of EngineeringModelId and IterationId. /// + /// A to run the cherry pick for a particular set of engineeringModelIds and iterationIds /// A - Task RunCherryPickAsync(); + Task RunCherryPickAsync(IEnumerable<(Guid engineeringModelId, Guid iterationId)> ids); } } From 43572d0f9434f4d48955012da598beec09576843 Mon Sep 17 00:00:00 2001 From: Roberto Alves Date: Fri, 20 Oct 2023 11:23:08 +0100 Subject: [PATCH 4/5] Add missing documentation and remove unecessary using --- COMET.Web.Common/Utilities/CherryPick/CherryPickRunner.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/COMET.Web.Common/Utilities/CherryPick/CherryPickRunner.cs b/COMET.Web.Common/Utilities/CherryPick/CherryPickRunner.cs index f728ab2f..4a809deb 100644 --- a/COMET.Web.Common/Utilities/CherryPick/CherryPickRunner.cs +++ b/COMET.Web.Common/Utilities/CherryPick/CherryPickRunner.cs @@ -30,8 +30,6 @@ namespace COMET.Web.Common.Utilities.CherryPick using COMET.Web.Common.Services.SessionManagement; - using Thing = CDP4Common.DTO.Thing; - /// /// Utility class that could run CherryPick query for /// @@ -83,8 +81,9 @@ public async Task RunCherryPickAsync() } /// - /// Runs the cherrypick features based on data required from + /// Runs the cherrypick features based on data required from and a particular set of EngineeringModelId and IterationId. /// + /// A to run the cherry pick for a particular set of engineeringModelIds and iterationIds /// A public async Task RunCherryPickAsync(IEnumerable<(Guid engineeringModelId, Guid iterationId)> ids) { From 6896b93601f4a15986163c5630a3e42197a44c7a Mon Sep 17 00:00:00 2001 From: Roberto Alves Date: Fri, 20 Oct 2023 12:01:08 +0100 Subject: [PATCH 5/5] Clarify documentation on the CherryPickRunner --- COMET.Web.Common/Utilities/CherryPick/CherryPickRunner.cs | 2 +- COMET.Web.Common/Utilities/CherryPick/ICherryPickRunner.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/COMET.Web.Common/Utilities/CherryPick/CherryPickRunner.cs b/COMET.Web.Common/Utilities/CherryPick/CherryPickRunner.cs index 4a809deb..4a392a96 100644 --- a/COMET.Web.Common/Utilities/CherryPick/CherryPickRunner.cs +++ b/COMET.Web.Common/Utilities/CherryPick/CherryPickRunner.cs @@ -70,7 +70,7 @@ public void InitializeProperties(IEnumerable needCherryPi } /// - /// Runs the cherrypick features based on data required from + /// Runs the cherrypick features based on data required from for all the Engineering Models the user is participating on /// /// A public async Task RunCherryPickAsync() diff --git a/COMET.Web.Common/Utilities/CherryPick/ICherryPickRunner.cs b/COMET.Web.Common/Utilities/CherryPick/ICherryPickRunner.cs index 84bfb344..21436a30 100644 --- a/COMET.Web.Common/Utilities/CherryPick/ICherryPickRunner.cs +++ b/COMET.Web.Common/Utilities/CherryPick/ICherryPickRunner.cs @@ -42,7 +42,7 @@ public interface ICherryPickRunner void InitializeProperties(IEnumerable needCherryPickedData); /// - /// Runs the cherrypick features based on data required from <see cref="CherryPickRunner.NeedCherryPicked" /> + /// Runs the cherrypick features based on data required from ; /// /// A Task RunCherryPickAsync();