diff --git a/COMET.Web.Common.Tests/Extensions/SessionServiceExtensionsTestFixture.cs b/COMET.Web.Common.Tests/Extensions/SessionServiceExtensionsTestFixture.cs new file mode 100644 index 00000000..c946fbec --- /dev/null +++ b/COMET.Web.Common.Tests/Extensions/SessionServiceExtensionsTestFixture.cs @@ -0,0 +1,91 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2023 RHEA System S.A. +// +// Authors: Sam Gerené, Alex Vorobiev, Alexander van Delft, Jaime Bernar, Théate Antoine +// +// This file is part of COMET WEB Community Edition +// The COMET WEB Community Edition is the RHEA Web Application implementation of ECSS-E-TM-10-25 Annex A and Annex C. +// +// The COMET WEB Community Edition is free software; you can redistribute it and/or +// modify it under the terms of the GNU Affero General Public +// License as published by the Free Software Foundation; either +// version 3 of the License, or (at your option) any later version. +// +// The COMET WEB Community Edition is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace COMET.Web.Common.Tests.Extensions +{ + using CDP4Common.EngineeringModelData; + using CDP4Common.SiteDirectoryData; + + using CDP4Dal; + using CDP4Dal.Operations; + + using COMET.Web.Common.Extensions; + using COMET.Web.Common.Services.SessionManagement; + using Microsoft.Extensions.Logging; + using Moq; + using NUnit.Framework; + + [TestFixture] + public class SessionServiceExtensionsTestFixture + { + private Mock session; + private ISessionService sessionService; + + [SetUp] + public void Setup() + { + var logger = new Mock>(); + + this.session = new Mock(); + this.sessionService = new SessionService(logger.Object) + { + Session = this.session.Object + }; + } + + [Test] + public void VerifyAddParameter() + { + var model = new EngineeringModel(); + var iterationSetup = new IterationSetup(); + var iteration = new Iteration() + { + IterationSetup = iterationSetup, + Container = model + }; + model.Iteration.Add(iteration); + + var elementDefinition = new ElementDefinition(); + iteration.Element.Add(elementDefinition); + + var textParameterType = new TextParameterType(); + + var doe = new DomainOfExpertise() + { + Name = "doe", + ShortName = "doe" + }; + + Assert.Multiple(() => + { + Assert.That(() => this.sessionService.AddParameter(null, null, null, null, null), Throws.ArgumentNullException); + Assert.That(() => this.sessionService.AddParameter(elementDefinition, null, null, null, null), Throws.ArgumentNullException); + Assert.That(() => this.sessionService.AddParameter(elementDefinition, null, textParameterType, null, null), Throws.ArgumentNullException); + Assert.That(() => this.sessionService.AddParameter(elementDefinition, null, textParameterType, null, doe), Throws.Nothing); + }); + + this.session.Verify(x => x.Write(It.IsAny()), Times.Once); + } + } +} diff --git a/COMET.Web.Common.Tests/Services/SessionManagement/SessionServiceTestFixture.cs b/COMET.Web.Common.Tests/Services/SessionManagement/SessionServiceTestFixture.cs index 5820d5f1..6c54ff78 100644 --- a/COMET.Web.Common.Tests/Services/SessionManagement/SessionServiceTestFixture.cs +++ b/COMET.Web.Common.Tests/Services/SessionManagement/SessionServiceTestFixture.cs @@ -36,6 +36,9 @@ namespace COMET.Web.Common.Tests.Services.SessionManagement using COMET.Web.Common.Enumerations; using COMET.Web.Common.Services.SessionManagement; + + using Microsoft.Extensions.Logging; + using Moq; using NUnit.Framework; @@ -59,8 +62,13 @@ public class SessionServiceTestFixture [SetUp] public void Setup() { + var logger = new Mock>(); + this.session = new Mock(); - this.sessionService = new SessionService { Session = this.session.Object }; + this.sessionService = new SessionService(logger.Object) + { + Session = this.session.Object + }; this.assembler = new Assembler(this.uri); this.domain = new DomainOfExpertise(Guid.NewGuid(), this.assembler.Cache, this.uri); diff --git a/COMET.Web.Common/COMET.Web.Common.csproj b/COMET.Web.Common/COMET.Web.Common.csproj index d812aeb2..a254f0e7 100644 --- a/COMET.Web.Common/COMET.Web.Common.csproj +++ b/COMET.Web.Common/COMET.Web.Common.csproj @@ -3,7 +3,7 @@ net7.0 Latest - 1.0.39 + 1.0.40 1.0.0 1.0.0 CDP4 WEB Common @@ -27,6 +27,7 @@ + diff --git a/COMET.Web.Common/Extensions/SessionServiceExtensions.cs b/COMET.Web.Common/Extensions/SessionServiceExtensions.cs new file mode 100644 index 00000000..821d0f4c --- /dev/null +++ b/COMET.Web.Common/Extensions/SessionServiceExtensions.cs @@ -0,0 +1,87 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2023 RHEA System S.A. +// +// Authors: Sam Gerené, Alex Vorobiev, Alexander van Delft, Jaime Bernar, Théate Antoine +// +// This file is part of COMET WEB Community Edition +// The COMET WEB Community Edition is the RHEA Web Application implementation of ECSS-E-TM-10-25 Annex A and Annex C. +// +// The COMET WEB Community Edition is free software; you can redistribute it and/or +// modify it under the terms of the GNU Affero General Public +// License as published by the Free Software Foundation; either +// version 3 of the License, or (at your option) any later version. +// +// The COMET WEB Community Edition is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace COMET.Web.Common.Extensions +{ + using CDP4Common.EngineeringModelData; + using CDP4Common.SiteDirectoryData; + + using COMET.Web.Common.Services.SessionManagement; + + using FluentResults; + + /// + /// Static class with extension methods for the + /// + public static class SessionServiceExtensions + { + /// + /// Adds a new parameter for a given element definition + /// + /// The in which data will be updated + /// The in which a new parameter will be added + /// The of the new parameter + /// The of the new parameter + /// The of the new parameter + /// The of the owner + /// A + /// Throws an + public static async Task AddParameter(this ISessionService sessionService, ElementDefinition elementDefinition, ParameterGroup group, ParameterType parameterType, MeasurementScale measurementScale, DomainOfExpertise owner) + { + if (elementDefinition == null) + { + throw new ArgumentNullException(nameof(elementDefinition), "The container ElementDefinition may not be null"); + } + + if (parameterType == null) + { + throw new ArgumentNullException(nameof(parameterType), "The ParameterType may not be null"); + } + + if (owner == null) + { + throw new ArgumentNullException(nameof(owner), "The owner DomainOfExpertise may not be null"); + } + + if (sessionService.Session == null) + { + throw new ArgumentNullException(nameof(sessionService.Session), "The session may not be null"); + } + + var parameter = new Parameter(Guid.NewGuid(), null, null) + { + Owner = owner, + ParameterType = parameterType, + Scale = measurementScale, + Group = group, + ValueSet = { new ParameterValueSet() } + }; + + var clone = elementDefinition.Clone(false); + clone.Parameter.Add(parameter); + + return await sessionService.CreateThing(clone, parameter); + } + } +} diff --git a/COMET.Web.Common/Services/SessionManagement/ISessionService.cs b/COMET.Web.Common/Services/SessionManagement/ISessionService.cs index 68e4a680..2875261e 100644 --- a/COMET.Web.Common/Services/SessionManagement/ISessionService.cs +++ b/COMET.Web.Common/Services/SessionManagement/ISessionService.cs @@ -33,6 +33,8 @@ namespace COMET.Web.Common.Services.SessionManagement using DynamicData; + using FluentResults; + /// /// The interface provides access to an /// @@ -75,8 +77,8 @@ public interface ISessionService /// /// The selected /// The - /// An asynchronous operation - Task ReadIteration(IterationSetup iterationSetup, DomainOfExpertise domain); + /// An asynchronous operation with a + Task ReadIteration(IterationSetup iterationSetup, DomainOfExpertise domain); /// /// Close all the opened @@ -125,72 +127,72 @@ public interface ISessionService /// /// the container where the should be created /// the thing to create in the session - /// An asynchronous operation - Task CreateThing(Thing container, Thing thingToCreate); + /// An asynchronous operation with a + Task CreateThing(Thing container, Thing thingToCreate); /// /// Write new Things in an /// /// the container where the should be created /// the things to create in the session - /// An asynchronous operation - Task CreateThings(Thing container, params Thing[] thingsToCreate); + /// An asynchronous operation with a + Task CreateThings(Thing container, params Thing[] thingsToCreate); /// /// Write new Things in an /// /// The where the s should be created /// List of Things to create in the session - /// An asynchronous operation - Task CreateThings(Thing container, IEnumerable thingsToCreate); + /// An asynchronous operation with a + Task CreateThings(Thing container, IEnumerable thingsToCreate); /// /// Write updated Thing in an /// /// The where the s should be updated /// the thing to update in the session - /// An asynchronous operation - Task UpdateThing(Thing container, Thing thingToUpdate); + /// An asynchronous operation with a + Task UpdateThing(Thing container, Thing thingToUpdate); /// /// Write updated Things in an /// /// The where the s should be updated /// List of Things to update in the session - /// An asynchronous operation - Task UpdateThings(Thing container, params Thing[] thingsToUpdate); + /// An asynchronous operation with a + Task UpdateThings(Thing container, params Thing[] thingsToUpdate); /// /// Write updated Things in an /// /// The where the s should be updated /// List of Things to update in the session - /// An asynchronous operation - Task UpdateThings(Thing container, IEnumerable thingsToUpdate); + /// An asynchronous operation with a + Task UpdateThings(Thing container, IEnumerable thingsToUpdate); /// /// Deletes a from it's container /// /// the container clone of the thing to delete /// the thing to delete in the session - /// An asynchronous operation - Task DeleteThing(Thing containerClone, Thing thingToDelete); + /// An asynchronous operation with a + Task DeleteThing(Thing containerClone, Thing thingToDelete); /// /// Deletes a collection of from it's container /// /// the container clone of the thing to delete /// the things to delete in the session - /// An asynchronous operation - Task DeleteThings(Thing containerClone, params Thing[] thingsToDelete); + /// An asynchronous operation with a + Task DeleteThings(Thing containerClone, params Thing[] thingsToDelete); /// /// Deletes a collection from it's container /// /// the container clone of the thing to delete /// the things to delete in the session - /// An asynchronous operation - Task DeleteThings(Thing containerClone, IEnumerable thingsToDelete); + /// An asynchronous operation with a + Task DeleteThings(Thing containerClone, IEnumerable thingsToDelete); /// /// Gets the inside an iteration diff --git a/COMET.Web.Common/Services/SessionManagement/SessionService.cs b/COMET.Web.Common/Services/SessionManagement/SessionService.cs index 3a18ff1c..d792332a 100644 --- a/COMET.Web.Common/Services/SessionManagement/SessionService.cs +++ b/COMET.Web.Common/Services/SessionManagement/SessionService.cs @@ -39,7 +39,9 @@ namespace COMET.Web.Common.Services.SessionManagement using DynamicData; - using NLog; + using FluentResults; + + using Microsoft.Extensions.Logging; using ReactiveUI; @@ -50,9 +52,9 @@ namespace COMET.Web.Common.Services.SessionManagement public class SessionService : ReactiveObject, ISessionService { /// - /// The current class + /// The /// - private readonly Logger logger = LogManager.GetCurrentClassLogger(); + private readonly ILogger logger; /// /// Gets a readonly collection of open @@ -74,6 +76,15 @@ public class SessionService : ReactiveObject, ISessionService /// public bool IsSessionOpen { get; set; } + /// + /// Creates a new instance of type + /// + /// the + public SessionService(ILogger logger) + { + this.logger = logger; + } + /// /// Retrieves the that is loaded in the /// @@ -104,8 +115,12 @@ public async Task Close() /// /// The selected /// The - public async Task ReadIteration(IterationSetup iterationSetup, DomainOfExpertise domain) + /// An asynchronous operation with a + public async Task ReadIteration(IterationSetup iterationSetup, DomainOfExpertise domain) { + var result = new Result(); + + this.logger.LogInformation("Opening iteration"); var modelSetup = (EngineeringModelSetup)iterationSetup.Container; var model = new EngineeringModel(modelSetup.EngineeringModelIid, this.Session.Assembler.Cache, this.Session.Credentials.Uri); @@ -127,12 +142,17 @@ public async Task ReadIteration(IterationSetup iterationSetup, DomainOfExpertise this.OpenIterations.Add(openedIteration); CDPMessageBus.Current.SendMessage(SessionStateKind.IterationOpened); + this.logger.LogInformation("Iteration opened successfully"); + result.Successes.Add(new Success("Iteration opened successfully")); } catch (Exception exception) { - this.logger.Error($"During read operation an error has occured: {exception.Message}"); + this.logger.LogError($"During read operation an error has occured: {exception.Message}", exception); + result.Errors.Add(new Error($"During read operation an error has occured: {exception.Message}")); throw; } + + return result; } /// @@ -140,6 +160,8 @@ public async Task ReadIteration(IterationSetup iterationSetup, DomainOfExpertise /// public void CloseIterations() { + this.logger.LogInformation("Closing all the opened iterations"); + foreach (var iteration in this.OpenIterations.Items.ToList()) { this.CloseIteration(iteration); @@ -152,6 +174,7 @@ public void CloseIterations() /// The public void CloseIteration(Iteration iteration) { + this.logger.LogInformation($"Closing iteration with id {iteration.Iid}"); this.Session.CloseIterationSetup(iteration.IterationSetup); this.OpenIterations.Remove(this.OpenIterations.Items.First(x => x.Iid == iteration.Iid)); } @@ -202,7 +225,7 @@ public async Task RefreshSession() CDPMessageBus.Current.SendMessage(SessionStateKind.RefreshEnded); - Console.WriteLine($"Session refreshed in {sw.ElapsedMilliseconds} [ms]"); + this.logger.LogInformation($"Session refreshed in {sw.ElapsedMilliseconds} [ms]"); } /// @@ -220,10 +243,10 @@ public void SwitchDomain(Iteration iteration, DomainOfExpertise domainOfExpertis /// /// the container where the should be created /// the thing to create in the session - /// An asynchronous operation - public async Task CreateThing(Thing container, Thing thingToCreate) + /// An asynchronous operation with a + public async Task CreateThing(Thing container, Thing thingToCreate) { - await this.CreateThings(container, new List { thingToCreate }); + return await this.CreateThings(container, new List { thingToCreate }); } /// @@ -231,10 +254,10 @@ public async Task CreateThing(Thing container, Thing thingToCreate) /// /// the container where the should be created /// the things to create in the session - /// An asynchronous operation - public async Task CreateThings(Thing container, params Thing[] thingsToCreate) + /// An asynchronous operation with a + public async Task CreateThings(Thing container, params Thing[] thingsToCreate) { - await this.CreateThings(container, thingsToCreate.ToList()); + return await this.CreateThings(container, thingsToCreate.ToList()); } /// @@ -242,11 +265,15 @@ public async Task CreateThings(Thing container, params Thing[] thingsToCreate) /// /// The where the s should be created /// List of Things to create in the session - public async Task CreateThings(Thing thing, IEnumerable thingsToCreate) + /// An asynchronous operation with a + public async Task CreateThings(Thing thing, IEnumerable thingsToCreate) { + var result = new Result(); + if (thingsToCreate == null) { - return; + result.Errors.Add(new Error("The things to create can't be null")); + return result; } var thingClone = thing; @@ -270,12 +297,16 @@ public async Task CreateThings(Thing thing, IEnumerable thingsToCreate) try { await this.Session.Write(operationContainer); - Console.WriteLine("Writing done !"); + this.logger.LogInformation("Writing done!"); + result.Successes.Add(new Success("Writing done!")); } catch (DalWriteException ex) { - Console.WriteLine($"The create operation failed: {ex.Message}"); + this.logger.LogError($"The create operation failed: {ex.Message}", ex); + result.Errors.Add(new Error($"The create operation failed: {ex.Message}")); } + + return result; } /// @@ -283,10 +314,10 @@ public async Task CreateThings(Thing thing, IEnumerable thingsToCreate) /// /// The where the s should be updated /// the thing to update in the session - /// An asynchronous operation - public async Task UpdateThing(Thing container, Thing thingToUpdate) + /// An asynchronous operation with a + public async Task UpdateThing(Thing container, Thing thingToUpdate) { - await this.UpdateThings(container, new List { thingToUpdate }); + return await this.UpdateThings(container, new List { thingToUpdate }); } /// @@ -294,10 +325,10 @@ public async Task UpdateThing(Thing container, Thing thingToUpdate) /// /// The where the s should be updated /// List of Things to update in the session - /// An asynchronous operation - public async Task UpdateThings(Thing container, params Thing[] thingsToUpdate) + /// An asynchronous operation with a + public async Task UpdateThings(Thing container, params Thing[] thingsToUpdate) { - await this.UpdateThings(container, thingsToUpdate.ToList()); + return await this.UpdateThings(container, thingsToUpdate.ToList()); } /// @@ -305,11 +336,15 @@ public async Task UpdateThings(Thing container, params Thing[] thingsToUpdate) /// /// The where the s should be updated /// List of Things to update in the session - public async Task UpdateThings(Thing thing, IEnumerable thingsToUpdate) + /// An asynchronous operation with a + public async Task UpdateThings(Thing thing, IEnumerable thingsToUpdate) { + var result = new Result(); + if (thingsToUpdate == null) { - return; + result.Errors.Add(new Error("The things to update can't be null")); + return result; } var sw = Stopwatch.StartNew(); @@ -336,16 +371,20 @@ public async Task UpdateThings(Thing thing, IEnumerable thingsToUpdate) try { await this.Session.Write(operationContainer); - Console.WriteLine($"Update writing done in {sw.ElapsedMilliseconds} [ms]"); + this.logger.LogInformation($"Update writing done in {sw.ElapsedMilliseconds} [ms]"); + result.Successes.Add(new Success($"Update writing done in {sw.ElapsedMilliseconds} [ms]")); } catch (Exception ex) { - Console.WriteLine($"The update operation failed: {ex.Message}"); + this.logger.LogError($"The update operation failed: {ex.Message}", ex); + result.Errors.Add(new Error($"The update operation failed: {ex.Message}")); } finally { sw.Stop(); } + + return result; } /// @@ -353,10 +392,10 @@ public async Task UpdateThings(Thing thing, IEnumerable thingsToUpdate) /// /// the container clone of the thing to delete /// the cloned thing to delete in the session - /// An asynchronous operation - public async Task DeleteThing(Thing containerClone, Thing thingToDelete) + /// An asynchronous operation with a + public async Task DeleteThing(Thing containerClone, Thing thingToDelete) { - await this.DeleteThings(containerClone, new List { thingToDelete }); + return await this.DeleteThings(containerClone, new List { thingToDelete }); } /// @@ -364,10 +403,10 @@ public async Task DeleteThing(Thing containerClone, Thing thingToDelete) /// /// the container clone of the thing to delete /// the cloned things to delete in the session - /// An asynchronous operation - public async Task DeleteThings(Thing containerClone, params Thing[] thingsToDelete) + /// An asynchronous operation with a + public async Task DeleteThings(Thing containerClone, params Thing[] thingsToDelete) { - await this.DeleteThings(containerClone, thingsToDelete.ToList()); + return await this.DeleteThings(containerClone, thingsToDelete.ToList()); } /// @@ -375,12 +414,15 @@ public async Task DeleteThings(Thing containerClone, params Thing[] thingsToDele /// /// the container clone of the thing to delete /// the cloned things to delete in the session - /// An asynchronous operation - public async Task DeleteThings(Thing containerClone, IEnumerable thingsToDelete) + /// An asynchronous operation with a + public async Task DeleteThings(Thing containerClone, IEnumerable thingsToDelete) { + var result = new Result(); + if (thingsToDelete == null) { - return; + result.Errors.Add(new Error("The things to delete can't be null")); + return result; } var sw = Stopwatch.StartNew(); @@ -411,16 +453,20 @@ public async Task DeleteThings(Thing containerClone, IEnumerable thingsTo try { await this.Session.Write(operationContainer); - Console.WriteLine($"Delete done in {sw.ElapsedMilliseconds} [ms]"); + this.logger.LogInformation($"Delete done in {sw.ElapsedMilliseconds} [ms]"); + result.Successes.Add(new Success($"Delete done in {sw.ElapsedMilliseconds} [ms]")); } catch (Exception ex) { - Console.WriteLine($"The delete operation failed: {ex.Message}"); + this.logger.LogError($"The delete operation failed: {ex.Message}", ex); + result.Errors.Add(new Error($"The delete operation failed: {ex.Message}")); } finally { sw.Stop(); } + + return result; } /// diff --git a/COMETwebapp.Tests/Components/SystemRepresentation/SystemRepresentationBodyTestFixture.cs b/COMETwebapp.Tests/Components/SystemRepresentation/SystemRepresentationBodyTestFixture.cs index b5ea94c6..7eecc457 100644 --- a/COMETwebapp.Tests/Components/SystemRepresentation/SystemRepresentationBodyTestFixture.cs +++ b/COMETwebapp.Tests/Components/SystemRepresentation/SystemRepresentationBodyTestFixture.cs @@ -46,6 +46,7 @@ namespace COMETwebapp.Tests.Components.SystemRepresentation using COMETwebapp.ViewModels.Components.SystemRepresentation; using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Logging; using Moq; @@ -74,10 +75,15 @@ public class SystemRepresentationPageTestFixture [SetUp] public void SetUp() { - this.context = new TestContext(); + var logger = new Mock>(); + this.context = new TestContext(); this.session = new Mock(); - this.sessionService = new SessionService { Session = this.session.Object }; + + this.sessionService = new SessionService(logger.Object) + { + Session = this.session.Object + }; this.context.Services.AddSingleton(this.sessionService); this.context.ConfigureDevExpressBlazor();