From c23dfe1039e3b29cee19771be15ea2f3bc9cd7ac Mon Sep 17 00:00:00 2001 From: Phil Schneider Date: Fri, 2 Aug 2024 17:02:38 +0200 Subject: [PATCH] feat(wallet): add existence check for wallet creation (#71) Refs: #66 Reviewed-By: Evelyn Gurschler --- src/Dim.sln | 7 ++ .../Repositories/ITenantRepository.cs | 1 + .../Repositories/TenantRepository.cs | 6 +- .../Dim.Web/BusinessLogic/DimBusinessLogic.cs | 5 + .../DimProcess.Executor.Tests.csproj | 20 +++ .../DimProcess.Library.Tests.csproj | 20 +++ tests/web/Dim.Web.Tests/Dim.Web.Tests.csproj | 51 ++++++++ .../Dim.Web.Tests/DimBusinessLogicTests.cs | 119 ++++++++++++++++++ tests/web/Dim.Web.Tests/Usings.cs | 25 ++++ 9 files changed, 253 insertions(+), 1 deletion(-) create mode 100644 tests/web/Dim.Web.Tests/Dim.Web.Tests.csproj create mode 100644 tests/web/Dim.Web.Tests/DimBusinessLogicTests.cs create mode 100644 tests/web/Dim.Web.Tests/Usings.cs diff --git a/src/Dim.sln b/src/Dim.sln index 90ca4c2..ee2abba 100644 --- a/src/Dim.sln +++ b/src/Dim.sln @@ -40,6 +40,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DimProcess.Executor.Tests", EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DimProcess.Library.Tests", "..\tests\processes\DimProcess.Library.Tests\DimProcess.Library.Tests.csproj", "{85D316A0-17BE-4983-AB06-5C72365ABD9B}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dim.Web.Tests", "..\tests\web\Dim.Web.Tests\Dim.Web.Tests.csproj", "{CE87E424-36CF-4597-9E08-2D687E67F259}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -106,6 +108,10 @@ Global {85D316A0-17BE-4983-AB06-5C72365ABD9B}.Debug|Any CPU.Build.0 = Debug|Any CPU {85D316A0-17BE-4983-AB06-5C72365ABD9B}.Release|Any CPU.ActiveCfg = Release|Any CPU {85D316A0-17BE-4983-AB06-5C72365ABD9B}.Release|Any CPU.Build.0 = Release|Any CPU + {CE87E424-36CF-4597-9E08-2D687E67F259}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CE87E424-36CF-4597-9E08-2D687E67F259}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CE87E424-36CF-4597-9E08-2D687E67F259}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CE87E424-36CF-4597-9E08-2D687E67F259}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {8356C7AF-6F88-4A62-B3E9-5656634A6FEA} = {B84A3CAB-AC86-4B2D-A490-79E1002350FF} @@ -123,5 +129,6 @@ Global {0D288AF0-1CE5-4B2B-9F80-532040F24BCF} = {CB1B7D43-9AFC-47EF-8915-A547F7F553AB} {A44447B0-794D-451A-A571-E3B761174B48} = {CB1B7D43-9AFC-47EF-8915-A547F7F553AB} {85D316A0-17BE-4983-AB06-5C72365ABD9B} = {CB1B7D43-9AFC-47EF-8915-A547F7F553AB} + {CE87E424-36CF-4597-9E08-2D687E67F259} = {CB1B7D43-9AFC-47EF-8915-A547F7F553AB} EndGlobalSection EndGlobal diff --git a/src/database/Dim.DbAccess/Repositories/ITenantRepository.cs b/src/database/Dim.DbAccess/Repositories/ITenantRepository.cs index 4600594..101d14e 100644 --- a/src/database/Dim.DbAccess/Repositories/ITenantRepository.cs +++ b/src/database/Dim.DbAccess/Repositories/ITenantRepository.cs @@ -46,4 +46,5 @@ public interface ITenantRepository Task<(bool Exists, Guid TechnicalUserId, Guid ProcessId)> GetTechnicalUserForBpn(string bpn, string technicalUserName); Task GetExternalIdForTechnicalUser(Guid technicalUserId); void RemoveTechnicalUser(Guid technicalUserId); + Task IsTenantExisting(string companyName, string bpn); } diff --git a/src/database/Dim.DbAccess/Repositories/TenantRepository.cs b/src/database/Dim.DbAccess/Repositories/TenantRepository.cs index 2823801..465ecc3 100644 --- a/src/database/Dim.DbAccess/Repositories/TenantRepository.cs +++ b/src/database/Dim.DbAccess/Repositories/TenantRepository.cs @@ -160,5 +160,9 @@ public Task GetExternalIdForTechnicalUser(Guid technicalUserId) => public void RemoveTechnicalUser(Guid technicalUserId) => context.TechnicalUsers - .Remove(new TechnicalUser(technicalUserId, default, default, null!, default)); + .Remove(new TechnicalUser(technicalUserId, Guid.Empty, Guid.Empty, null!, Guid.Empty)); + + public Task IsTenantExisting(string companyName, string bpn) => + context.Tenants + .AnyAsync(x => x.CompanyName == companyName && x.Bpn == bpn); } diff --git a/src/web/Dim.Web/BusinessLogic/DimBusinessLogic.cs b/src/web/Dim.Web/BusinessLogic/DimBusinessLogic.cs index 7496cdc..9ee7657 100644 --- a/src/web/Dim.Web/BusinessLogic/DimBusinessLogic.cs +++ b/src/web/Dim.Web/BusinessLogic/DimBusinessLogic.cs @@ -42,6 +42,11 @@ public class DimBusinessLogic( public async Task StartSetupDim(string companyName, string bpn, string didDocumentLocation, bool isIssuer) { + if (await dimRepositories.GetInstance().IsTenantExisting(companyName, bpn).ConfigureAwait(ConfigureAwaitOptions.None)) + { + throw new ConflictException($"Tenant {companyName} with Bpn {bpn} already exists"); + } + var processStepRepository = dimRepositories.GetInstance(); var processId = processStepRepository.CreateProcess(ProcessTypeId.SETUP_DIM).Id; processStepRepository.CreateProcessStep(ProcessStepTypeId.CREATE_SUBACCOUNT, ProcessStepStatusId.TODO, processId); diff --git a/tests/processes/DimProcess.Executor.Tests/DimProcess.Executor.Tests.csproj b/tests/processes/DimProcess.Executor.Tests/DimProcess.Executor.Tests.csproj index e97e276..256b8ce 100644 --- a/tests/processes/DimProcess.Executor.Tests/DimProcess.Executor.Tests.csproj +++ b/tests/processes/DimProcess.Executor.Tests/DimProcess.Executor.Tests.csproj @@ -1,3 +1,23 @@ + + net8.0 diff --git a/tests/processes/DimProcess.Library.Tests/DimProcess.Library.Tests.csproj b/tests/processes/DimProcess.Library.Tests/DimProcess.Library.Tests.csproj index ad6c020..e6d31e8 100644 --- a/tests/processes/DimProcess.Library.Tests/DimProcess.Library.Tests.csproj +++ b/tests/processes/DimProcess.Library.Tests/DimProcess.Library.Tests.csproj @@ -1,3 +1,23 @@ + + net8.0 diff --git a/tests/web/Dim.Web.Tests/Dim.Web.Tests.csproj b/tests/web/Dim.Web.Tests/Dim.Web.Tests.csproj new file mode 100644 index 0000000..dd2aff2 --- /dev/null +++ b/tests/web/Dim.Web.Tests/Dim.Web.Tests.csproj @@ -0,0 +1,51 @@ + + + + + net8.0 + enable + enable + false + Dim.Web.Tests + Dim.Web.Tests + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + diff --git a/tests/web/Dim.Web.Tests/DimBusinessLogicTests.cs b/tests/web/Dim.Web.Tests/DimBusinessLogicTests.cs new file mode 100644 index 0000000..8c37dff --- /dev/null +++ b/tests/web/Dim.Web.Tests/DimBusinessLogicTests.cs @@ -0,0 +1,119 @@ +/******************************************************************************** + * Copyright (c) 2024 BMW Group AG + * Copyright 2024 SAP SE or an SAP affiliate company and ssi-dim-middle-layer contributors. + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +using Dim.Clients.Api.Cf; +using Dim.Clients.Api.Dim; +using Dim.DbAccess; +using Dim.DbAccess.Repositories; +using Dim.Entities.Entities; +using Dim.Entities.Enums; +using Dim.Web.BusinessLogic; +using Microsoft.Extensions.Options; +using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling; + +namespace Dim.Web.Tests; + +public class DimBusinessLogicTests +{ + private static readonly Guid OperatorId = Guid.NewGuid(); + private readonly IDimBusinessLogic _sut; + private readonly ICfClient _cfClient; + private readonly IDimClient _dimClient; + private readonly ITenantRepository _tenantRepository; + private readonly IProcessStepRepository _processStepRepository; + + public DimBusinessLogicTests() + { + var fixture = new Fixture().Customize(new AutoFakeItEasyCustomization { ConfigureMembers = true }); + fixture.Behaviors.OfType().ToList() + .ForEach(b => fixture.Behaviors.Remove(b)); + fixture.Behaviors.Add(new OmitOnRecursionBehavior()); + + var repositories = A.Fake(); + _dimClient = A.Fake(); + _cfClient = A.Fake(); + + _tenantRepository = A.Fake(); + _processStepRepository = A.Fake(); + + A.CallTo(() => repositories.GetInstance()).Returns(_tenantRepository); + A.CallTo(() => repositories.GetInstance()).Returns(_processStepRepository); + + _sut = new DimBusinessLogic(repositories, _cfClient, _dimClient, Options.Create(new DimSettings + { + OperatorId = OperatorId + })); + } + + [Fact] + public async Task StartSetupDim_WithExisting_ThrowsConflictException() + { + // Arrange + A.CallTo(() => _tenantRepository.IsTenantExisting(A._, A._)) + .Returns(true); + async Task Act() => await _sut.StartSetupDim("testCompany", "BPNL00000001TEST", "https://example.org/test", false); + + // Act + var result = await Assert.ThrowsAsync(Act); + + // Assert + result.Message.Should().Be($"Tenant testCompany with Bpn BPNL00000001TEST already exists"); + } + + [Fact] + public async Task StartSetupDim_WithNewData_CreatesExpected() + { + // Arrange + var processId = Guid.NewGuid(); + var processes = new List(); + var processSteps = new List(); + var tenants = new List(); + A.CallTo(() => _tenantRepository.IsTenantExisting(A._, A._)) + .Returns(false); + A.CallTo(() => _processStepRepository.CreateProcess(A._)) + .Invokes((ProcessTypeId processTypeId) => + { + processes.Add(new Process(processId, processTypeId, Guid.NewGuid())); + }); + A.CallTo(() => _processStepRepository.CreateProcessStep(A._, A._, A._)) + .Invokes((ProcessStepTypeId processStepTypeId, ProcessStepStatusId processStepStatusId, Guid pId) => + { + processSteps.Add(new ProcessStep(Guid.NewGuid(), processStepTypeId, processStepStatusId, processId, DateTimeOffset.UtcNow)); + }); + A.CallTo(() => + _tenantRepository.CreateTenant(A._, A._, A._, A._, A._, A._)) + .Invokes((string companyName, string bpn, string didDocumentLocation, bool isIssuer, Guid pId, + Guid operatorId) => + { + tenants.Add(new Tenant(Guid.NewGuid(), companyName, bpn, didDocumentLocation, isIssuer, pId, operatorId)); + }); + + // Act + await _sut.StartSetupDim("testCompany", "BPNL00000001TEST", "https://example.org/test", false); + + // Assert + processes.Should().ContainSingle() + .Which.ProcessTypeId.Should().Be(ProcessTypeId.SETUP_DIM); + processSteps.Should().ContainSingle() + .And.Satisfy(x => x.ProcessId == processId && x.ProcessStepTypeId == ProcessStepTypeId.CREATE_SUBACCOUNT); + tenants.Should().ContainSingle() + .And.Satisfy(x => x.CompanyName == "testCompany" && x.Bpn == "BPNL00000001TEST"); + } +} diff --git a/tests/web/Dim.Web.Tests/Usings.cs b/tests/web/Dim.Web.Tests/Usings.cs new file mode 100644 index 0000000..ded99ae --- /dev/null +++ b/tests/web/Dim.Web.Tests/Usings.cs @@ -0,0 +1,25 @@ +/******************************************************************************** + * Copyright (c) 2024 BMW Group AG + * Copyright 2024 SAP SE or an SAP affiliate company and ssi-dim-middle-layer contributors. + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +global using AutoFixture; +global using AutoFixture.AutoFakeItEasy; +global using FakeItEasy; +global using FluentAssertions; +global using Xunit;